aboutsummaryrefslogtreecommitdiff
path: root/python/ndpi_example.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/ndpi_example.py')
-rwxr-xr-xpython/ndpi_example.py155
1 files changed, 88 insertions, 67 deletions
diff --git a/python/ndpi_example.py b/python/ndpi_example.py
index afbba43b5..ff11e6d37 100755
--- a/python/ndpi_example.py
+++ b/python/ndpi_example.py
@@ -1,43 +1,44 @@
#!/usr/bin/env python3
-#
-# ndpi_example.py
-#
-# Copyright (C) 2011-19 - ntop.org
-#
-# nDPI is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# nDPI is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with nDPI. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from ndpi_typestruct import *
-from scapy.all import *
+# -*- coding: utf-8 -*-
+
+"""
+file: ndpi_example.py
+This file is part of nDPI.
+
+Copyright (C) 2011-19 - ntop.org
+Copyright (C) 2019 - Zied Aouini <aouinizied@gmail.com> (Incremental improvements)
+nDPI is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+nDPI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with nDPI.
+If not, see <http://www.gnu.org/licenses/>.
+"""
+
+from ndpi_bindings import *
+from ctypes import *
+from scapy.all import *
+import sys
# ------- return type & pcapstruct to declare -------
-class workflow(Structure):
+class WorkFlow(Structure):
_fields_ = [("src_ip", c_uint32),
("dst_ip", c_uint32),
("src_port", c_uint16),
("dst_port", c_uint16),
("protocol", c_uint8),
("packets", c_uint32),
- ("detected_protocol", ndpi_protocol),
+ ("detected_protocol", NDPIProtocol),
("detection_completed", c_uint8),
("id", c_uint32),
- ("src_id", POINTER(ndpi_id_struct)),
- ("dst_id", POINTER(ndpi_id_struct)),
- ("flow", POINTER(ndpi_flow_struct))]
+ ("src_id", POINTER(NDPIIdStruct)),
+ ("dst_id", POINTER(NDPIIdStruct)),
+ ("flow", POINTER(NDPIFlowStruct))]
CMCFUN = CFUNCTYPE(c_int, c_void_p, c_void_p)
@@ -48,17 +49,19 @@ FREE = CFUNCTYPE(None, c_void_p)
def node_proto_guess_walker(nodo, which, depth, user_data):
global ndpi_info_mod
- flow = cast(nodo, POINTER(POINTER(workflow))).contents.contents
- if which == 0 or which == 3: #execute only preorder operation of the tree
+ flow = cast(nodo, POINTER(POINTER(WorkFlow))).contents.contents
+ if which == 0 or which == 3: # execute only preorder operation of the tree
if flow.detection_completed == 0: # order for tree operation
- flow.detected_protocol = ndpi.ndpi_detection_giveup(ndpi_info_mod, flow.flow, flow.protocol,
- int(socket.ntohl(flow.src_ip)), 1)
+ flow.detected_protocol = ndpi.ndpi_detection_giveup(ndpi_info_mod,
+ flow.flow,
+ 1,
+ cast(addressof(c_uint8(0)), POINTER(c_uint8)))
count_protocol[flow.detected_protocol.app_protocol] += flow.packets
def py_cmp_fun(a, b):
- fa = cast(a, POINTER(workflow))
- fb = cast(b, POINTER(workflow))
+ fa = cast(a, POINTER(WorkFlow))
+ fb = cast(b, POINTER(WorkFlow))
if fa.contents.src_ip < fb.contents.src_ip: return -1
elif fa.contents.src_ip > fb.contents.src_ip: return 1
@@ -83,7 +86,7 @@ free_walk = FREE(freer)
# --------------------------------------
-# number of anylized packet
+# number of analyzed packet
packet_number = 0
flow_count = 0
max_num_udp_dissected_pkts = 16
@@ -103,6 +106,8 @@ if ndpi.ndpi_get_api_version() != ndpi.ndpi_wrap_get_api_version():
ndpi_info_mod = ndpi.ndpi_init_detection_module()
if ndpi_info_mod is None:
sys.exit(-1)
+else:
+ ndpi_ndpi_finalize_initalization(ndpi_info_mod)
def ip2int(ip):
@@ -113,30 +118,34 @@ def ip2int(ip):
return int(struct.unpack("!I", packedIP)[0])
-def get_flow(packet):
+def get_flow(pkt):
global flows_root
global flows_root_ref
global flow_count
- ip_packet = packet[1]
+ ip_packet = pkt[1]
ip_protocol = ip_packet.proto
transport_packet = None
- if ip_protocol == 6 or ip_protocol == 17: transport_packet = packet[2]
+ if ip_protocol == 6 or ip_protocol == 17:
+ transport_packet = pkt[2]
if transport_packet is not None:
# to avoid two nodes in one binary tree for a flow
ip_src = ip2int(ip_packet.src)
ip_dst = ip2int(ip_packet.dst)
src_port = transport_packet.sport
dst_port = transport_packet.dport
- else: return None
+ else:
+ return None
# set flows to correct type and data
- ndpi_flow = pointer(ndpi_flow_struct())
- memset(ndpi_flow, 0, sizeof(ndpi_flow_struct))
+ ndpi_flow = pointer(NDPIFlowStruct())
+ memset(ndpi_flow, 0, sizeof(NDPIFlowStruct))
if ip_src > ip_dst:
- flow = workflow(ip_src, ip_dst, src_port, dst_port, int(ip_packet.proto), 0, ndpi_protocol(), 0, 0, pointer(ndpi_id_struct()), pointer(ndpi_id_struct()), ndpi_flow)
+ flow = WorkFlow(ip_src, ip_dst, src_port, dst_port, int(ip_packet.proto), 0, NDPIProtocol(), 0, 0,
+ pointer(NDPIIdStruct()), pointer(NDPIIdStruct()), ndpi_flow)
else:
- flow = workflow(ip_dst, ip_src, dst_port, src_port, int(ip_packet.proto), 0, ndpi_protocol(), 0, 0, pointer(ndpi_id_struct()), pointer(ndpi_id_struct()), ndpi_flow)
+ flow = WorkFlow(ip_dst, ip_src, dst_port, src_port, int(ip_packet.proto), 0, NDPIProtocol(), 0, 0,
+ pointer(NDPIIdStruct()), pointer(NDPIIdStruct()), ndpi_flow)
flow_ref = pointer(flow)
res = ndpi.ndpi_tfind(flow_ref, flows_root_ref, cmp_func)
if res is None:
@@ -144,41 +153,45 @@ def get_flow(packet):
lista.append(flow)
flow_count += 1
return pointer(flow)
- flow = cast(res, POINTER(POINTER(workflow))).contents
+ flow = cast(res, POINTER(POINTER(WorkFlow))).contents
return flow
-def packetcaptured(packet):
+def packetcaptured(pkt):
global packet_number
- global start_time
global ndpi_info_mod
flow = None
- h = pcap_pkthdr()
+ h = PcapPktHdr()
- #getting flow
+ # getting flow
try:
- flow = get_flow(packet)
+ flow = get_flow(pkt)
except AttributeError:
- pass # ignore packet
+ pass # ignore packet
if flow is None: return
- #filling pcap_pkthdr
- h.len = h.caplen = len(packet)
- h.ts.tv_sec = int(packet["IP"].time/1000000)
- h.ts.tv_usec = int(packet["IP"].time)
+ # filling pcap_pkthdr
+ h.len = h.caplen = len(pkt)
+ h.ts.tv_sec = int(pkt["IP"].time/1000000)
+ h.ts.tv_usec = int(pkt["IP"].time)
# real work
- if int(packet[1].frag) == 0: # not fragmented packet
+ if int(pkt[1].frag) == 0: # not fragmented packet
flow.contents.packets += 1
packet_number += 1
# get ndpi_iphdr address
- iphdr_addr = cast(c_char_p(packet[1].build()), c_void_p)
+ iphdr_addr = cast(c_char_p(pkt[1].build()), c_void_p)
ndpi_flow = flow.contents.flow
if flow.contents.detection_completed is 0:
- flow.contents.detected_protocol = ndpi.ndpi_detection_process_packet(ndpi_info_mod, ndpi_flow, cast(iphdr_addr, POINTER(c_uint8)),
- int(packet[1].len), h.ts.tv_usec, flow.contents.src_id, flow.contents.dst_id)
+ flow.contents.detected_protocol = ndpi.ndpi_detection_process_packet(ndpi_info_mod,
+ ndpi_flow,
+ cast(iphdr_addr, POINTER(c_uint8)),
+ int(pkt[1].len),
+ h.ts.tv_usec,
+ flow.contents.src_id,
+ flow.contents.dst_id)
flow1 = flow.contents.detected_protocol
@@ -187,27 +200,32 @@ def packetcaptured(packet):
if flow.contents.protocol == 6: valid = flow.contents.packets > max_num_tcp_dissected_pkts
elif flow.contents.protocol == 17: valid = flow.contents.packets > max_num_udp_dissected_pkts
- #should we continue anylizing packet or not?
+ # should we continue anylizing packet or not?
if valid or flow1.app_protocol is not 0:
- if valid or flow1.master_protocol is not 91: #or # 91 is NDPI_PROTOCOL_TLS
- flow.contents.detection_completed = 1 #protocol found
+ if valid or flow1.master_protocol is not 91: # or # 91 is NDPI_PROTOCOL_TLS
+ flow.contents.detection_completed = 1 # protocol found
if flow1.app_protocol is 0:
- flow.contents.detected_protocol = ndpi.ndpi_detection_giveup(ndpi_info_mod, ndpi_flow, 1)
-
+ flow.contents.detected_protocol = ndpi.ndpi_detection_giveup(ndpi_info_mod,
+ ndpi_flow,
+ 1,
+ cast(addressof(c_uint8(0)),
+ POINTER(c_uint8)))
def result():
global flows_root_ref
global ndpi_info_mod
- print('\nnumber of anylized packet ' + str(packet_number))
- print('number of flows ' + str(flow_count))
+ print('\nnumber of analyzed packet: ' + str(packet_number))
+ print('number of flows: ' + str(flow_count))
ndpi.ndpi_twalk(flows_root_ref.contents, guess_walker, None)
print('\nDetected protocols:')
for i in range(0, ndpi.ndpi_get_num_supported_protocols(ndpi_info_mod)):
if count_protocol[i] > 0:
- print(cast(ndpi.ndpi_get_proto_name(ndpi_info_mod, i), c_char_p).value + ': '.encode('UTF-8') + str(count_protocol[i]).encode('UTF-8'))
+ print("{}: {} packets".format(
+ cast(ndpi.ndpi_get_proto_name(ndpi_info_mod, i), c_char_p).value.decode('utf-8'),
+ str(count_protocol[i])))
def free(ndpi_struct):
@@ -216,16 +234,16 @@ def free(ndpi_struct):
def initialize(ndpi_struct):
- all = NDPI_PROTOCOL_BITMASK()
+ all = NDPIProtocolBitMask()
ndpi.ndpi_wrap_NDPI_BITMASK_SET_ALL(pointer(all))
ndpi.ndpi_set_protocol_detection_bitmask2(ndpi_struct, pointer(all))
-print('Using nDPI ' + str(cast(ndpi.ndpi_revision(), c_char_p).value))
+print('Using nDPI ' + cast(ndpi.ndpi_revision(), c_char_p).value.decode("utf-8"))
initialize(ndpi_info_mod)
-if(len(sys.argv) != 2):
+if len(sys.argv) != 2:
print("\nUsage: ndpi_example.py <device>")
sys.exit(0)
@@ -247,6 +265,9 @@ else:
sniff(iface=sys.argv[1], prn=packetcaptured)
except KeyboardInterrupt:
print('\nInterrupted\n')
+ except PermissionError:
+ sys.exit('\nRoot privilege required for live capture on interface: {}\n'.format(sys.argv[1]))
+
result()
free(ndpi_info_mod)