diff options
-rw-r--r-- | python/README | 10 | ||||
-rw-r--r-- | python/flow_printer.py | 27 | ||||
-rwxr-xr-x | python/ndpi_example.py | 151 | ||||
-rw-r--r-- | python/ndpi_typestruct.py | 809 |
4 files changed, 570 insertions, 427 deletions
diff --git a/python/README b/python/README index 61a689a77..f55139d0c 100644 --- a/python/README +++ b/python/README @@ -1,7 +1,11 @@ -This direcgory contains the Python bindings for nDPI +This directory contains the Python3 bindings for nDPI -Usage: +Demo example: - python3 ndpi_example.py <interface> - python3 ndpi_example.py <pcap_file> -Code courtesy of Massimo Puddu +Additional example (using nfstream package): +- python3 flow_printer.py <interface> +- python3 flow_printer.py <pcap_file> + +Code courtesy of: Massimo Puddu, Zied Aouini diff --git a/python/flow_printer.py b/python/flow_printer.py new file mode 100644 index 000000000..a30ea79b9 --- /dev/null +++ b/python/flow_printer.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +file: flow_printer.py +This file is part of nfstream. + +Copyright (C) 2019 - Zied Aouini <aouinizied@gmail.com> + +nfstream 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. + +nfstream 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 nfstream. +If not, see <http://www.gnu.org/licenses/>. +""" + +from nfstream.streamer import Streamer +import sys + +flow_streamer = Streamer(source=sys.argv[1]) +flows_count = 0 +for flow in flow_streamer: + print("flow[{}]: \n{}\n".format(flows_count, flow)) + flows_count += 1 diff --git a/python/ndpi_example.py b/python/ndpi_example.py index afbba43b5..d134d3947 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/>. -# +# -*- 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_typestruct 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) diff --git a/python/ndpi_typestruct.py b/python/ndpi_typestruct.py index 4f8c8c236..889257dea 100644 --- a/python/ndpi_typestruct.py +++ b/python/ndpi_typestruct.py @@ -1,343 +1,319 @@ -# -# ndpi_typestruct.h -# -# Copyright (C) 2019 - 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/>. -# - - -import os -from ctypes import * - -ndpi = CDLL('./ndpi_wrap.so') - -# NDPI_SELECTION_BITMASK_PROTOCOL_SIZE = c_uint32 -# ndpi_protocol_category_t, ndpi_protocol_breed_t e ndpi_log_level_t are enum and are imported as c_int - -class ndpi_detection_module_struct(Structure): +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +file: ndpi_typestruct.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 ctypes import CDLL, Structure, c_uint16, c_int, c_ulong, c_uint32, CFUNCTYPE, c_void_p, POINTER, c_char_p, c_uint8 +from ctypes import c_char, c_uint, c_int16, c_longlong, c_size_t, Union, c_ubyte, c_uint64, c_int32, c_ushort, cast +from os.path import abspath, dirname +ndpi = CDLL(dirname(abspath(__file__)) + '/ndpi_wrap.so') + +# ----------------------------------------------- Structures ----------------------------------------------------------- + + +class NDPIDetectionModuleStruct(Structure): pass -class ndpi_flow_struct(Structure): + +class NDPIFlowStruct(Structure): pass -class ndpi_protocol(Structure): + +class NDPIProtocol(Structure): _fields_ = [ ("master_protocol", c_uint16), ("app_protocol", c_uint16), ("category", c_int) - ] -class timeval(Structure): + +class TimeVal(Structure): _fields_ = [("tv_sec", c_ulong), ("tv_usec", c_ulong)] -class pcap_pkthdr(Structure): - _fields_ = [("ts", timeval), ("caplen", c_uint32), ("len", c_uint32)] -#dal file ../src/include/ndpi_tydedefs.h -class ndpi_ndpi_mask(Structure): +class PcapPktHdr(Structure): + _fields_ = [("ts", TimeVal), ("caplen", c_uint32), ("len", c_uint32)] + + +class NDPIMask(Structure): _fields_ = [("fds_bits", c_uint32)] -class NDPI_PROTOCOL_BITMASK(Structure): - _fields_ = [("fds_bits", ndpi_ndpi_mask * ndpi.ndpi_wrap_ndpi_num_fds_bits())] -class ndpi_subprotocol_conf_struct(Structure): - _fields_ = [("func", CFUNCTYPE(c_void_p,POINTER(ndpi_detection_module_struct),c_char_p,c_char_p,c_int))] +class NDPIProtocolBitMask(Structure): + _fields_ = [("fds_bits", NDPIMask * ndpi.ndpi_wrap_ndpi_num_fds_bits())] + + +class NDPISubprotocolConfStruct(Structure): + _fields_ = [("func", CFUNCTYPE(c_void_p, POINTER(NDPIDetectionModuleStruct), c_char_p, c_char_p, c_int))] + -class ndpi_automa(Structure): +class NDPIAutoma(Structure): _fields_ = [ - ("ac_automa", c_void_p), #Real type is AC_AUTOMATA_t + ("ac_automa", c_void_p), ("ac_automa_finalized", c_uint8) ] -class struct_node_t(Structure): + +class NDPINode(Structure): pass -struct_node_t._fields_ = [ + + +NDPINode._fields_ = [ ('key', POINTER(c_char)), - ('left', POINTER(struct_node_t)), - ('right', POINTER(struct_node_t)), + ('left', POINTER(NDPINode)), + ('right', POINTER(NDPINode)), ] -class ndpi_call_function_struct(Structure): + +class NDPICallFunctionStruct(Structure): _fields_ = [ - ("detection_bitmask", NDPI_PROTOCOL_BITMASK), - ("excluded_protocol_bitmask",NDPI_PROTOCOL_BITMASK), + ("detection_bitmask", NDPIProtocolBitMask), + ("excluded_protocol_bitmask", NDPIProtocolBitMask), ("ndpi_selection_bitmask", c_uint32), - ("func", CFUNCTYPE(None, POINTER(ndpi_detection_module_struct), POINTER(ndpi_flow_struct))), + ("func", CFUNCTYPE(None, POINTER(NDPIDetectionModuleStruct), POINTER(NDPIFlowStruct))), ("detection_feature", c_uint8) ] -class ndpi_proto_defaults_t(Structure): + +class NDPIProtoDefaultsT(Structure): _fields_ = [ - ("protoName", POINTER(c_char)), - ("protoCategory",c_uint), + ("protoName", c_char_p), + ("protoCategory", c_uint), ("can_have_a_subprotocol", c_uint8), ("protoId", c_uint16), ("protoIdx", c_uint16), ("master_tcp_protoId", c_uint16 * 2), ("master_udp_protoId", c_uint16 * 2), ("protoBreed", c_uint), - ("func", CFUNCTYPE(None, POINTER(ndpi_detection_module_struct), POINTER(ndpi_flow_struct))), + ("func", CFUNCTYPE(None, POINTER(NDPIDetectionModuleStruct), POINTER(NDPIFlowStruct))), ] -class ndpi_default_ports_tree_node_t(Structure): + +class NDPIDefaultsPortsTreeNodeT(Structure): _fields_ = [ - ("proto", ndpi_proto_defaults_t), - ("customUserProto",c_uint8), + ("proto", NDPIProtoDefaultsT), + ("customUserProto", c_uint8), ("default_port", c_int16) ] -# NDPI_PROTOCOL_BITTORRENT -class spinlock_t(Structure): - _fields_ = [("val", c_int)] #missing volatile -class atomic_t(Structure): - _fields_ = [("counter", c_int)] #missing volatile +class SpinlockT(Structure): + _fields_ = [("val", c_int)] + + +class AtomicT(Structure): + _fields_ = [("counter", c_int)] + -class time_t(Structure): - _fields_ = [("counter", c_longlong)] # piattaform dependent +class TimeT(Structure): + _fields_ = [("counter", c_longlong)] -class hash_ip4p_node(Structure): + +class HashIp4pNode(Structure): pass -hash_ip4p_node._fields_ = [ - ("next", POINTER(hash_ip4p_node)), - ("prev", POINTER(hash_ip4p_node)), - ("lchg", time_t), + +HashIp4pNode._fields_ = [ + ("next", POINTER(HashIp4pNode)), + ("prev", POINTER(HashIp4pNode)), + ("lchg", TimeT), ("port", c_uint16), ("count", c_uint16, 12), ("flag", c_uint16, 4), ("ip", c_uint32) ] -class hash_ip4p(Structure): + +class HashIp4p(Structure): _fields_ = [ - ("top", POINTER(hash_ip4p_node)), - ("lock",spinlock_t), + ("top", POINTER(HashIp4pNode)), + ("lock",SpinlockT), ("len", c_size_t) ] -class hash_ip4p_table(Structure): + +class HashIp4pTable(Structure): _fields_ = [ ("size", c_size_t), - ("ipv6",c_int), - ("lock", spinlock_t), - ("count", atomic_t), - ("tbl", hash_ip4p) + ("ipv6", c_int), + ("lock", SpinlockT), + ("count", AtomicT), + ("tbl", HashIp4p) ] -class bt_announce(Structure): # 192 bytes + +class BtAnnounce(Structure): _fields_ = [ ("hash", c_uint32 * 5), ("ip", c_uint32 * 4), ("time", c_uint32), ("port", c_uint16), ("name_len", c_uint8), - ("name", c_uint8 * 149) # 149 bytes + ("name", c_uint8 * 149) + ] + + +class NDPILruCacheEntry(Structure): + _fields_ = [ + ("key", c_uint32), + ("is_full", c_uint32, 1), + ("value", c_uint32, 16), + ("pad", c_uint32, 15) ] -class ndpi_lru_cache(Structure): # 192 bytes + +class NDPILruCache(Structure): _fields_ = [ ("num_entries", c_uint32), - ("entries", POINTER(c_uint32)), + ("entries", POINTER(NDPILruCacheEntry)), ] -class cache_entry(Structure): + +class CacheEntry(Structure): pass -cache_entry._fields_ = [ + +CacheEntry._fields_ = [ ("item", c_void_p), ("item_size", c_uint32), - ("prev", POINTER(cache_entry)), - ("next", POINTER(cache_entry)) + ("prev", POINTER(CacheEntry)), + ("next", POINTER(CacheEntry)) ] -class cache_entry_map(Structure): + +class CacheEntryMap(Structure): pass -cache_entry_map._fields_ = [ - ("entry", POINTER(cache_entry)), - ("next", POINTER(cache_entry_map)), + +CacheEntryMap._fields_ = [ + ("entry", POINTER(CacheEntry)), + ("next", POINTER(CacheEntryMap)), ] -class cache(Structure): # 192 bytes + +class Cache(Structure): _fields_ = [ ("size", c_uint32), ("max_size", c_uint32), - ("head", POINTER(cache_entry)), - ("tail", POINTER(cache_entry)), - ("map", POINTER(POINTER(cache_entry_map))) - ] - -class custom_categories(Structure): - _fields_ =[ - #Hyperscam - #("hostnames", POINTER(hs)), - #("num_to_load", c_uint), - #("to_load", POINTER(hs_list)), - ("hostnames", ndpi_automa), - ("hostnames_shadow", ndpi_automa), - ("hostnames_hash", c_void_p), - ("ipAddresses", c_void_p), - ("ipAddresses_shadow", c_void_p), # Patricia - ("categories_loaded", c_uint8), + ("head", POINTER(CacheEntry)), + ("tail", POINTER(CacheEntry)), + ("map", POINTER(POINTER(CacheEntryMap))) ] -ndpi_detection_module_struct._fields_ = [ - ("detection_bitmask", NDPI_PROTOCOL_BITMASK), - ("generic_http_packet_bitmask", NDPI_PROTOCOL_BITMASK), - - ("current_ts", c_uint32), - - ("ticks_per_second", c_uint32), - - #("user_data", c_void_p), debug +class CustomCategories(Structure): + _fields_ = [ + ("hostnames", NDPIAutoma), + ("hostnames_shadow", NDPIAutoma), + ("ipAddresses", c_void_p), + ("ipAddresses_shadow", c_void_p), + ("categories_loaded", c_uint8), + ] - ("custom_category_labels", (c_char * ndpi.ndpi_wrap_num_custom_categories()) * ndpi.ndpi_wrap_custom_category_label_len()), - #callback function buffer - ("callback_buffer", ndpi_call_function_struct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), +NDPIDetectionModuleStruct._fields_ = [ + ("detection_bitmask", NDPIProtocolBitMask), + ("generic_http_packet_bitmask", NDPIProtocolBitMask), + ("current_ts", c_uint32), + ("ticks_per_second", c_uint32), + ("custom_category_labels", + (c_char * ndpi.ndpi_wrap_num_custom_categories()) * ndpi.ndpi_wrap_custom_category_label_len()), + ("callback_buffer", NDPICallFunctionStruct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), ("callback_buffer_size", c_uint32), - - ("callback_buffer_tcp_no_payload", ndpi_call_function_struct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), + ("callback_buffer_tcp_no_payload", NDPICallFunctionStruct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), ("callback_buffer_size_tcp_no_payload", c_uint32), - - ("callback_buffer_tcp_payload", ndpi_call_function_struct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), + ("callback_buffer_tcp_payload", NDPICallFunctionStruct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), ("callback_buffer_size_tcp_payload", c_uint32), - - ("callback_buffer_udp", ndpi_call_function_struct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), + ("callback_buffer_udp", NDPICallFunctionStruct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), ("callback_buffer_size_udp", c_uint32), - - ("callback_buffer_non_tcp_udp", ndpi_call_function_struct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), + ("callback_buffer_non_tcp_udp", NDPICallFunctionStruct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), ("callback_buffer_size_non_tcp_udp", c_uint32), - - ("tcpRoot", POINTER(ndpi_default_ports_tree_node_t)), - ("udpRoot", POINTER(ndpi_default_ports_tree_node_t)), - - ("ndpi_log_level", c_uint), #default error - - # ifdef NDPI_ENABLE_DEBUG_MESSAGES - #debug callback, only set whendebug is used * / - #ndpi_debug_function_ptr ndpi_debug_printf; - #const char * ndpi_debug_print_file; - #const char * ndpi_debug_print_function; - #u_int32_t ndpi_debug_print_line; - #NDPI_PROTOCOL_BITMASK debug_bitmask; - # endif - - #misc parameters - ("tcp_max_retransmission_window_size", c_uint32), - - ("directconnect_connection_ip_tick_timeout", c_uint32), - - #subprotocol registration handler - ("subprotocol_conf", ndpi_subprotocol_conf_struct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), - - ("ndpi_num_supported_protocols", c_uint), + ("tcpRoot", POINTER(NDPIDefaultsPortsTreeNodeT)), + ("udpRoot", POINTER(NDPIDefaultsPortsTreeNodeT)), + ("ndpi_log_level", c_uint), + ("tcp_max_retransmission_window_size", c_uint32), + ("directconnect_connection_ip_tick_timeout", c_uint32), + ("subprotocol_conf", NDPISubprotocolConfStruct * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + 1)), + ("ndpi_num_supported_protocols", c_uint), ("ndpi_num_custom_protocols", c_uint), - - #HTTP / DNS / HTTPS host matching * / - ("host_automa", ndpi_automa), #Used for DNS / HTTPS - ("content_automa", ndpi_automa), # Used for HTTP subprotocol_detection - ("subprotocol_automa", ndpi_automa), # Used for HTTP subprotocol_detection - ("bigrams_automa", ndpi_automa), #TOR - ("impossible_bigrams_automa", ndpi_automa), # TOR - - ("custom_categories", custom_categories), - #IP-based protocol detection - ("protocols_ptree", c_void_p), - - #irc parameters - ("irc_timeout", c_uint32), - #gnutella parameters - ("gnutella_timeout", c_uint32), - #battlefield parameters - ("battlefield_timeout", c_uint32), - # thunder parameters - ("thunder_timeout", c_uint32), - # SoulSeek parameters - ("soulseek_connection_ip_tick_timeout", c_uint32), - # rtsp parameters - ("rtsp_connection_timeout", c_uint32), - # tvants parameters - ("tvants_connection_timeout", c_uint32), - # rstp - ("orb_rstp_ts_timeout", c_uint32), - # yahoo - ("yahoo_detect_http_connections", c_uint8), + ("host_automa", NDPIAutoma), + ("content_automa", NDPIAutoma), + ("subprotocol_automa", NDPIAutoma), + ("bigrams_automa", NDPIAutoma), + ("impossible_bigrams_automa", NDPIAutoma), + ("custom_categories", CustomCategories), + ("protocols_ptree", c_void_p), + ("irc_timeout", c_uint32), + ("gnutella_timeout", c_uint32), + ("battlefield_timeout", c_uint32), + ("thunder_timeout", c_uint32), + ("soulseek_connection_ip_tick_timeout", c_uint32), + ("rtsp_connection_timeout", c_uint32), + ("tvants_connection_timeout", c_uint32), + ("orb_rstp_ts_timeout", c_uint32), + ("yahoo_detect_http_connections", c_uint8), ("yahoo_lan_video_timeout", c_uint32), ("zattoo_connection_timeout", c_uint32), ("jabber_stun_timeout", c_uint32), ("jabber_file_transfer_timeout", c_uint32), - - # ifdef NDPI_ENABLE_DEBUG_MESSAGES - # define NDPI_IP_STRING_SIZE 40 - #char ip_string[NDPI_IP_STRING_SIZE]; - # endif - - ("ip_version_limit", c_uint8), - #NDPI_PROTOCOL_BITTORRENT - ("bt_ht", POINTER(hash_ip4p_table)), - # ifdef NDPI_DETECTION_SUPPORT_IPV6 - ("bt6_ht", POINTER(hash_ip4p_table)), - # endif - - # BT_ANNOUNCE - ("bt_ann", POINTER(bt_announce)), + ("ip_version_limit", c_uint8), + ("bt_ht", POINTER(HashIp4pTable)), + ("bt6_ht", POINTER(HashIp4pTable)), + ("bt_ann", POINTER(BtAnnounce)), ("bt_ann_len", c_int), - - # NDPI_PROTOCOL_OOKLA - ("ookla_cache", POINTER(ndpi_lru_cache)), - - # NDPI_PROTOCOL_TINC - ("tinc_cache", POINTER(cache)), - - ("proto_defaults", ndpi_proto_defaults_t * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + ndpi.ndpi_wrap_ndpi_max_num_custom_protocols())), - - ("http_dont_dissect_response", c_uint8, 1), + ("ookla_cache", POINTER(NDPILruCache)), + ("tinc_cache", POINTER(Cache)), + ("proto_defaults", NDPIProtoDefaultsT * (ndpi.ndpi_wrap_ndpi_max_supported_protocols() + + ndpi.ndpi_wrap_ndpi_max_num_custom_protocols())), + ("http_dont_dissect_response", c_uint8, 1), ("dns_dont_dissect_response", c_uint8, 1), - ("direction_detect_disable", c_uint8, 1), # disable internal detection of packet direction - ("disable_metadata_export", c_uint8, 1), # No metadata is exported - ("enable_category_substring_match", c_uint8, 1), # Default is perfect match - - ("hyperscan", c_void_p) # Intel Hyperscan + ("direction_detect_disable", c_uint8, 1), + ("disable_metadata_export", c_uint8, 1), + ("hyperscan", c_void_p) ] -class u6_addr(Union): # 128-bit IP6 address + +class U6Addr(Union): _fields_ = [ - ("u6_addr8",c_uint8 * 16), - ("u6_addr16",c_uint16 * 8), - ("u6_addr32",c_uint32 * 4) + ("u6_addr8", c_uint8 * 16), + ("u6_addr16", c_uint16 * 8), + ("u6_addr32", c_uint32 * 4), + ("u6_addr64", c_uint64 * 2) ] -class ndpi_in6_addr(Structure): - _fields_ = [("u6_addr", u6_addr)] + +class NDPIIn6Addr(Structure): + _pack_ = 1 + _fields_ = [("u6_addr", U6Addr)] -class ndpi_ip_addr_t(Union): +class NDPIIpAddrT(Union): _fields_ = [ ('ipv4', c_uint32), ('ipv4_u_int8_t', c_uint8 * 4), - ('ipv6', ndpi_in6_addr), + ('ipv6', NDPIIn6Addr), ] -class ndpi_id_struct(Structure): + +class NDPIIdStruct(Structure): _fields_ = [ - ('detected_protocol_bitmask', NDPI_PROTOCOL_BITMASK), - ('rtsp_ip_address', ndpi_ip_addr_t), + ('detected_protocol_bitmask', NDPIProtocolBitMask), + ('rtsp_ip_address', NDPIIpAddrT), ('yahoo_video_lan_timer', c_uint32), ('irc_port', c_uint16 * 8), ('last_time_port_used', c_uint32 * 8), @@ -371,10 +347,10 @@ class ndpi_id_struct(Structure): ('rtsp_ts_set', c_uint32, 1), ] -#struct flow -class ndpi_flow_tcp_struct(Structure): + +class NDPIFlowTcpStruct(Structure): + _pack_ = 1 _fields_ = [ - # NDPI_PROTOCOL_MAIL_SMTP ('smtp_command_bitmask', c_uint16), ('pop_command_bitmask', c_uint16), ('qq_nxt_len', c_uint16), @@ -405,10 +381,16 @@ class ndpi_flow_tcp_struct(Structure): ('ssh_stage', c_uint32, 3), ('vnc_stage', c_uint32, 2), ('telnet_stage', c_uint32, 2), - ('ssl_seen_client_cert', c_uint8, 1), - ('ssl_seen_server_cert', c_uint8, 1), - ('ssl_seen_certificate', c_uint8, 1), - ('ssl_stage', c_uint8, 2), + ('tls_srv_cert_fingerprint_ctx', c_void_p), + ('tls_seen_client_cert', c_uint8, 1), + ('tls_seen_server_cert', c_uint8, 1), + ('tls_seen_certificate', c_uint8, 1), + ('tls_srv_cert_fingerprint_found', c_uint8, 1), + ('tls_srv_cert_fingerprint_processed', c_uint8, 1), + ('tls_stage', c_uint8, 2), + ('tls_record_offset', c_int16), + ('tls_fingerprint_len', c_int16), + ('tls_sha1_certificate_fingerprint', c_uint8 * 20), ('postgres_stage', c_uint32, 3), ('ddlink_server_direction', c_uint32, 1), ('seen_syn', c_uint32, 1), @@ -429,13 +411,15 @@ class ndpi_flow_tcp_struct(Structure): ('lotus_notes_packet_id', c_uint8), ('teamviewer_stage', c_uint8), ('prev_zmq_pkt_len', c_uint8), - ('prev_zmq_pkt', c_ubyte * 10), + ('prev_zmq_pkt', c_char * 10), ('ppstream_stage', c_uint32, 3), ('memcached_matches', c_uint8), ('nest_log_sink_matches', c_uint8), ] -class ndpi_flow_udp_struct(Structure): + +class NDPIFlowUdpStruct(Structure): + _pack_ = 1 _fields_ = [ ('battlefield_msg_id', c_uint32), ('snmp_msg_id', c_uint32), @@ -454,103 +438,152 @@ class ndpi_flow_udp_struct(Structure): ('rx_conn_epoch', c_uint32), ('rx_conn_id', c_uint32), ('memcached_matches', c_uint8), + ('wireguard_stage', c_uint8), + ('wireguard_peer_index', c_uint32 * 2), ] -# the tcp / udp / other l4 value union used to reduce the number of bytes for tcp or udp protocol states -class l4(Union): - _fields_ = [("tcp", ndpi_flow_tcp_struct),("udp", ndpi_flow_udp_struct)] -class http(Structure): +class L4(Union): + _fields_ = [("tcp", NDPIFlowTcpStruct), ("udp", NDPIFlowUdpStruct)] + + +class Http(Structure): _fields_ = [ ("method", c_int), ("url", c_char_p), ("content_type", c_char_p), - ("num_request_headers", c_uint8), ("num_response_headers", c_uint8), - ("request_version", c_uint8), # 0=1.0 and 1=1.1. Create an enum for this? - ("response_status_code", c_uint16), # 200, 404, etc. + ("num_request_headers", c_uint8), + ("num_response_headers", c_uint8), + ("request_version", c_uint8), + ("response_status_code", c_uint16), ] -class dns(Structure): # the only fields useful for nDPI and ntopng + +class Dns(Structure): _fields_ = [ - ("num_queries", c_uint8), ("num_answers", c_uint8), ("reply_code", c_uint8), - ("query_type", c_uint16), ("query_class", c_uint16), ("rsp_type", c_uint16), - ("rsp_addr", ndpi_ip_addr_t) # The first address in a DNS response packet + ("num_queries", c_uint8), + ("num_answers", c_uint8), + ("reply_code", c_uint8), + ("is_query", c_uint8), + ("query_type", c_uint16), + ("query_class", c_uint16), + ("rsp_type", c_uint16), + ("rsp_addr", NDPIIpAddrT) ] -class ntp(Structure): - _fields_ = [("request_code", c_uint8), ("version", c_uint8)] -class ssl(Structure): +class Ntp(Structure): + _fields_ = [("request_code", c_uint8), + ("version", c_uint8)] + + +class Kerberos(Structure): + _fields_ = [("cname", c_char * 24), + ("realm", c_char * 24)] + + +class Ssl(Structure): _fields_ = [ - ("ssl_version", c_uint8), - ("client_certificate", c_char * 64), ("server_certificate", c_char * 64), ("server_organization", c_char * 64), - ("ja3_client", c_char * 33), ("ja3_server", c_char * 33), + ("ssl_version", c_uint16), + ("client_certificate", c_char * 64), + ("server_certificate", c_char * 64), + ("server_organization", c_char * 64), + ('notBefore', c_uint32), + ('notAfter', c_uint32), + ("ja3_client", c_char * 33), + ("ja3_server", c_char * 33), ("server_cipher", c_uint16), ("server_unsafe_cipher", c_int) ] -class stun(Structure): + +class Stun(Structure): _fields_ = [ ("num_udp_pkts", c_uint8), ("num_processed_pkts", c_uint8), ("num_binding_requests", c_uint8), - ("is_skype", c_uint8) ] -class stun_ssl(Union): # We can have STUN over SSL thus they need to live together - _fields_ = [("ssl", ssl),("stun",stun)] -class ssh(Structure): - _fields_ = [("client_signature", c_char * 48), ("server_signature", c_char * 48)] +class StunSsl(Structure): + _fields_ = [("ssl", Ssl), ("stun", Stun)] + + +class Ssh(Structure): + _fields_ = [ + ("client_signature", c_char * 48), + ("server_signature", c_char * 48), + ("hassh_client", c_char * 33), + ("hassh_server", c_char * 33) + ] -class mdns(Structure): + +class Imo(Structure): + _fields_ = [ + ("last_one_byte_pkt", c_uint8), + ("last_byte", c_uint8) + ] + + +class Mdns(Structure): _fields_ = [("answer", c_char * 96)] -class ubntac2(Structure): - _fields_ = [("version", c_char * 96)] -class http2(Structure): +class Ubntac2(Structure): + _fields_ = [("version", c_char * 32)] + + +class Http2(Structure): _fields_ = [ - ("detected_os", c_ubyte * 32), #Via HTTP User-Agent - ("nat_ip", c_ubyte * 24) + ("detected_os", c_char * 32), + ("nat_ip", c_char * 24) ] -class bittorrent(Structure): # Bittorrent hash - _fields_ = [ ("hash", c_ubyte * 20) ] -class dhcp(Structure): +class Bittorrent(Structure): + _fields_ = [("hash", c_char * 20)] + + +class Dhcp(Structure): _fields_ = [ ("fingerprint", c_char * 48), - ("nat_ip", c_char * 48) + ("class_ident", c_char * 48) ] -class protos(Union): + +class Protos(Union): _fields_ = [ - ("dns", dns), - ("ntp", ntp), - ("stun_ssl", stun_ssl), - ("ssh", ssh), - ("mdns", mdns), - ("ubntac2", ubntac2), - ("http", http2), - ("bittorrent", bittorrent), - ("dhcp", dhcp) + ("dns", Dns), + ("kerberos", Kerberos), + ("stun_ssl", StunSsl), + ("ssh", Ssh), + ("imo", Imo), + ("mdns", Mdns), + ("ubntac2", Ubntac2), + ("http", Http2), + ("bittorrent", Bittorrent), + ("dhcp", Dhcp) ] -class tinc_cache_entry(Structure): + +class TincCacheEntry(Structure): + _pack_ = 1 _fields_ = [ ('src_address', c_uint32), ('dst_address', c_uint32), ('dst_port', c_uint16), ] -class struct_ndpi_int_one_line_struct(Structure): + +class NDPIIntOneLineStruct(Structure): _fields_ = [ ('ptr', POINTER(c_uint8)), ('len', c_uint16), ] -class struct_ndpi_iphdr_little_end(Structure): + +class NDPIIphdr(Structure): + _pack_ = 1 _fields_ = [ ('ihl', c_uint8, 4), ('version', c_uint8, 4), @@ -564,7 +597,9 @@ class struct_ndpi_iphdr_little_end(Structure): ('saddr', c_uint32), ('daddr', c_uint32)] -class struct_ndpi_ip6_hdrctl(Structure): + +class NDPIIp6Hdrctl(Structure): + _pack_ = 1 _fields_ = [ ('ip6_un1_flow', c_uint32), ('ip6_un1_plen', c_uint16), @@ -572,14 +607,18 @@ class struct_ndpi_ip6_hdrctl(Structure): ('ip6_un1_hlim', c_uint8), ] -class struct_ndpi_ipv6hdr(Structure): + +class NDPIIpv6hdr(Structure): + _pack_ = 1 _fields_ = [ - ('ip6_hdr', struct_ndpi_ip6_hdrctl), - ('ip6_src', ndpi_in6_addr), - ('ip6_dst', ndpi_in6_addr), + ('ip6_hdr', NDPIIp6Hdrctl), + ('ip6_src', NDPIIn6Addr), + ('ip6_dst', NDPIIn6Addr), ] -class struct_ndpi_tcphdr(Structure): + +class NDPITcpHdr(Structure): + _pack_ = 1 _fields_ = [ ('source', c_uint16), ('dest', c_uint16), @@ -600,7 +639,9 @@ class struct_ndpi_tcphdr(Structure): ('urg_ptr', c_uint16), ] -class struct_ndpi_udphdr(Structure): + +class NDPIUdpHdr(Structure): + _pack_ = 1 _fields_ = [ ('source', c_uint16), ('dest', c_uint16), @@ -608,36 +649,44 @@ class struct_ndpi_udphdr(Structure): ('check', c_uint16), ] -class ndpi_packet_struct(Structure): + +class NDPIPacketStructStack(Structure): + _pack_ = 1 + _fields_ = [ + ('detected_subprotocol_stack', c_uint8 * ndpi.ndpi_wrap_ndpi_procol_size()), + ('protocol_stack_info', c_uint16) + ] + + +class NDPIPacketStruct(Structure): _fields_ = [ - ('iph', POINTER(struct_ndpi_iphdr_little_end)), - ('iphv6', POINTER(struct_ndpi_ipv6hdr)), - ('tcp', POINTER(struct_ndpi_tcphdr)), - ('udp', POINTER(struct_ndpi_udphdr)), + ('iph', POINTER(NDPIIphdr)), + ('iphv6', POINTER(NDPIIpv6hdr)), + ('tcp', POINTER(NDPITcpHdr)), + ('udp', POINTER(NDPIUdpHdr)), ('generic_l4_ptr', POINTER(c_uint8)), ('payload', POINTER(c_uint8)), ('tick_timestamp', c_uint32), ('tick_timestamp_l', c_uint64), - ('detected_protocol_stack', c_uint16 * 2), - ('detected_subprotocol_stack', c_uint8 * 2), - ('protocol_stack_info', c_uint16), - ('line', struct_ndpi_int_one_line_struct * 64), - ('host_line', struct_ndpi_int_one_line_struct), - ('forwarded_line', struct_ndpi_int_one_line_struct), - ('referer_line', struct_ndpi_int_one_line_struct), - ('content_line', struct_ndpi_int_one_line_struct), - ('accept_line', struct_ndpi_int_one_line_struct), - ('user_agent_line', struct_ndpi_int_one_line_struct), - ('http_url_name', struct_ndpi_int_one_line_struct), - ('http_encoding', struct_ndpi_int_one_line_struct), - ('http_transfer_encoding', struct_ndpi_int_one_line_struct), - ('http_contentlen', struct_ndpi_int_one_line_struct), - ('http_cookie', struct_ndpi_int_one_line_struct), - ('http_origin', struct_ndpi_int_one_line_struct), - ('http_x_session_type', struct_ndpi_int_one_line_struct), - ('server_line', struct_ndpi_int_one_line_struct), - ('http_method', struct_ndpi_int_one_line_struct), - ('http_response', struct_ndpi_int_one_line_struct), + ('detected_protocol_stack', c_uint16 * ndpi.ndpi_wrap_ndpi_procol_size()), + ('ndpi_packet_stack', NDPIPacketStructStack), + ('line', NDPIIntOneLineStruct * 64), + ('host_line', NDPIIntOneLineStruct), + ('forwarded_line', NDPIIntOneLineStruct), + ('referer_line', NDPIIntOneLineStruct), + ('content_line', NDPIIntOneLineStruct), + ('accept_line', NDPIIntOneLineStruct), + ('user_agent_line', NDPIIntOneLineStruct), + ('http_url_name', NDPIIntOneLineStruct), + ('http_encoding', NDPIIntOneLineStruct), + ('http_transfer_encoding', NDPIIntOneLineStruct), + ('http_contentlen', NDPIIntOneLineStruct), + ('http_cookie', NDPIIntOneLineStruct), + ('http_origin', NDPIIntOneLineStruct), + ('http_x_session_type', NDPIIntOneLineStruct), + ('server_line', NDPIIntOneLineStruct), + ('http_method', NDPIIntOneLineStruct), + ('http_response', NDPIIntOneLineStruct), ('http_num_headers', c_uint8), ('l3_packet_len', c_uint16), ('l4_packet_len', c_uint16), @@ -654,58 +703,43 @@ class ndpi_packet_struct(Structure): ('packet_lines_parsed_complete', c_uint8, 1), ('packet_direction', c_uint8, 1), ('empty_line_position_set', c_uint8, 1), + ('pad', c_uint8, 5), + ] + + +class NDPIFlowStructStack(Structure): + _pack_ = 1 + _fields_ = [ + ("detected_protocol_stack", c_uint16 * ndpi.ndpi_wrap_ndpi_procol_size()), + ("protocol_stack_info", c_uint16) ] -ndpi_flow_struct._fields_ = [ - ("detected_protocol_stack", c_uint16 * ndpi.ndpi_wrap_ndpi_procol_size()), - ("protocol_stack_info", c_uint16), - # init parameter, internal used to set up timestamp,... +NDPIFlowStruct._fields_ = [ + ("ndpi_flow_stack", NDPIFlowStructStack), ("guessed_protocol_id", c_uint16), ("guessed_host_protocol_id", c_uint16), ("guessed_category", c_uint16), ("guessed_header_category", c_uint16), + ("l4_proto", c_uint8), ("protocol_id_already_guessed", c_uint8, 1), ("host_already_guessed", c_uint8, 1), ("init_finished", c_uint8, 1), ("setup_packet_direction", c_uint8, 1), ("packet_direction", c_uint8, 1), ("check_extra_packets", c_uint8, 1), - - # if ndpi_struct->direction_detect_disable == 1 tcp sequence number connection tracking ("next_tcp_seq_nr", c_uint32 * 2), - ("max_extra_packets_to_check", c_uint8), ("num_extra_packets_checked", c_uint8), - ("num_processed_pkts", c_uint8), # <= WARNING it can wrap but we do expect people to giveup earlier - - ("extra_packets_func", CFUNCTYPE(c_int,POINTER(ndpi_detection_module_struct),POINTER(ndpi_flow_struct))), - - ("l4", l4), - - # Pointer to src or dst that identifies the server of this connection - ("server_id", ndpi_id_struct), - # HTTP host or DNS query + ("num_processed_pkts", c_uint8), + ("extra_packets_func", CFUNCTYPE(c_int, POINTER(NDPIDetectionModuleStruct), POINTER(NDPIFlowStruct))), + ("l4", L4), + ("server_id", POINTER(NDPIIdStruct)), ("host_server_name", c_ubyte * 256), - - - # This structure below will not not stay inside the protos - # structure below as HTTP is used by many subprotocols - # such as FaceBook, Google... so it is hard to know - # when to use it or not. Thus we leave it outside for the - # time being. - - - ("http", http), - ("protos", protos), - - # ALL protocol specific 64 bit variables here - - # protocols which have marked a connection as this connection cannot be protocol XXX, multiple u_int64_t - ("excluded_protocol_bitmask", NDPI_PROTOCOL_BITMASK), - + ("http", Http), + ("protos", Protos), + ("excluded_protocol_bitmask", NDPIProtocolBitMask), ("category", c_int), - ('redis_s2d_first_char', c_uint8), ('redis_d2s_first_char', c_uint8), ('packet_counter', c_uint16), @@ -742,32 +776,89 @@ ndpi_flow_struct._fields_ = [ ('ovpn_session_id', c_uint8 * 8), ('ovpn_counter', c_uint8), ('tinc_state', c_uint8), - ('tinc_cache_entry', tinc_cache_entry), + ('TincCacheEntry', TincCacheEntry), ('csgo_strid', c_uint8 * 18), ('csgo_state', c_uint8), ('csgo_s2', c_uint8), ('csgo_id2', c_uint32), ('kxun_counter', c_uint16), ('iqiyi_counter', c_uint16), - ('packet', ndpi_packet_struct), - ('flow', POINTER(ndpi_flow_struct)), - ('src', POINTER(ndpi_id_struct)), - ('dst', POINTER(ndpi_id_struct)) + ('packet', NDPIPacketStruct), + ('flow', POINTER(NDPIFlowStruct)), + ('src', POINTER(NDPIIdStruct)), + ('dst', POINTER(NDPIIdStruct)) ] - +# ----------------------------------------------- nDPI APIs ------------------------------------------------------------ + +""" ndpi_detection_giveup: Function to be called before we give up with detection for a given flow. + This function reduces the NDPI_UNKNOWN_PROTOCOL detection. """ +ndpi.ndpi_detection_giveup.restype = NDPIProtocol +ndpi.ndpi_detection_giveup.argtypes = [POINTER(NDPIDetectionModuleStruct), + POINTER(NDPIFlowStruct), c_uint8, + POINTER(c_uint8)] + +""" ndpi_detection_process_packet: Processes one packet and returns the ID of the detected protocol. + This is the MAIN PACKET PROCESSING FUNCTION. """ +ndpi.ndpi_detection_process_packet.restype = NDPIProtocol +ndpi.ndpi_detection_process_packet.argtypes = [POINTER(NDPIDetectionModuleStruct), + POINTER(NDPIFlowStruct), + POINTER(c_ubyte), + c_ushort, + c_uint64, + POINTER(NDPIIdStruct), + POINTER(NDPIIdStruct)] + +""" ndpi_ssl_version2str : Converts ssl version to readable string """ +ndpi.ndpi_ssl_version2str.restype = c_char_p +ndpi.ndpi_ssl_version2str.argtypes = [c_int16, POINTER(c_uint8)] + +""" ndpi_init_detection_module: Returns a new initialized detection module. + Note that before you can use it you can still load hosts and do other things. As soon as you are ready to use + it do not forget to call first ndpi_finalize_initalization() """ +ndpi.ndpi_init_detection_module.restype = POINTER(NDPIDetectionModuleStruct) + + +def ndpi_ndpi_finalize_initalization(detection_module): + """ ndpi_finalize_initalization: Completes the initialization (ndpi_revision >= 3.1)""" + if cast(ndpi.ndpi_revision(), c_char_p).value.decode("utf-8")[:3] >= '3.1': + ndpi.ndpi_finalize_initalization.restype = c_void_p + ndpi.ndpi_finalize_initalization.argtypes = [POINTER(NDPIDetectionModuleStruct)] + return ndpi.ndpi_finalize_initalization(detection_module) + else: + # ignore it + return None + + +""" ndpi_tfind: find a node, or return 0. """ ndpi.ndpi_tfind.restype = c_void_p + +""" ndpi_tsearch: ftp://ftp.cc.uoc.gr/mirrors/OpenBSD/src/lib/libc/stdlib/tsearch.c + find or insert datum into search tree. """ ndpi.ndpi_tsearch.restype = c_void_p +ndpi.ndpi_tsearch.argtypes = [c_void_p, POINTER(c_void_p), CFUNCTYPE(c_int, c_void_p, c_void_p)] + +""" ndpi_revision: Get the nDPI version release. """ ndpi.ndpi_revision.restype = c_void_p + +""" ndpi_get_proto_name: Get the protocol name associated to the ID.""" ndpi.ndpi_get_proto_name.restype = c_void_p + +""" ndpi_category_get_name: Get protocol category as string.""" +ndpi.ndpi_category_get_name.restype = c_void_p + +""" ndpi_get_num_supported_protocols: Get the total number of the supported protocols.""" ndpi.ndpi_get_num_supported_protocols.restype = c_uint -ndpi.ndpi_detection_process_packet.restype = ndpi_protocol -ndpi.ndpi_init_detection_module.restype = POINTER(ndpi_detection_module_struct) -ndpi.ndpi_wrap_NDPI_BITMASK_SET_ALL.argtypes = [POINTER(NDPI_PROTOCOL_BITMASK)] -ndpi.ndpi_set_protocol_detection_bitmask2.argtypes = [POINTER(ndpi_detection_module_struct), POINTER(NDPI_PROTOCOL_BITMASK)] -ndpi.ndpi_tsearch.argtypes = [c_void_p, POINTER(c_void_p), CFUNCTYPE(c_int, c_void_p, c_void_p)] + +""" ndpi_wrap_NDPI_BITMASK_SET_ALL: memset((char *)(p), 0xFF, sizeof(*(p)))""" +ndpi.ndpi_wrap_NDPI_BITMASK_SET_ALL.argtypes = [POINTER(NDPIProtocolBitMask)] + +""" ndpi_set_protocol_detection_bitmask2: Sets the protocol bitmask2.""" +ndpi.ndpi_set_protocol_detection_bitmask2.argtypes = [POINTER(NDPIDetectionModuleStruct), + POINTER(NDPIProtocolBitMask)] + +""" ndpi_twalk: Walk the nodes of a tree. """ ndpi.ndpi_twalk.argtypes = [c_void_p, CFUNCTYPE(None, c_void_p, c_int32, c_int, c_void_p), c_void_p] -ndpi.ndpi_tdestroy.argtypes = [c_void_p, CFUNCTYPE(None, c_void_p)] -ndpi.ndpi_detection_giveup.restype = ndpi_protocol -ndpi.ndpi_detection_giveup.argtypes = [POINTER(ndpi_detection_module_struct), POINTER(ndpi_flow_struct), c_uint8] -ndpi.ndpi_detection_process_packet.argtypes = [POINTER(ndpi_detection_module_struct), POINTER(ndpi_flow_struct), POINTER(c_ubyte), c_ushort, c_uint64, POINTER(ndpi_id_struct), POINTER(ndpi_id_struct)] + +""" ndpi_tdestroy: node destroy. """ +ndpi.ndpi_tdestroy.argtypes = [c_void_p, CFUNCTYPE(None, c_void_p)]
\ No newline at end of file |