/* * ndpi_main.c * * Copyright (C) 2011-19 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH * * 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 . * */ #ifdef HAVE_CONFIG_H #include "ndpi_config.h" #endif #include #include #include #include "ahocorasick.h" #include "libcache.h" #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN #include "ndpi_api.h" #include "ndpi_config.h" #include #ifndef WIN32 #include #endif #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ #include #endif #include "ndpi_content_match.c.inc" #include "third_party/include/ndpi_patricia.h" #include "third_party/include/ht_hash.h" /* stun.c */ extern u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow, u_int8_t rev); static int _ndpi_debug_callbacks = 0; /* #define MATCH_DEBUG 1 */ /* ****************************************** */ static void *(*_ndpi_flow_malloc)(size_t size); static void (*_ndpi_flow_free)(void *ptr); static void *(*_ndpi_malloc)(size_t size); static void (*_ndpi_free)(void *ptr); /* ****************************************** */ /* Forward */ static void addDefaultPort(struct ndpi_detection_module_struct *ndpi_str, ndpi_port_range *range, ndpi_proto_defaults_t *def, u_int8_t customUserProto, ndpi_default_ports_tree_node_t **root, const char *_func, int _line); static int removeDefaultPort(ndpi_port_range *range, ndpi_proto_defaults_t *def, ndpi_default_ports_tree_node_t **root); /* ****************************************** */ void* ndpi_malloc(size_t size) { return(_ndpi_malloc ? _ndpi_malloc(size) : malloc(size)); } void* ndpi_flow_malloc(size_t size) { return(_ndpi_flow_malloc ? _ndpi_flow_malloc(size) : ndpi_malloc(size)); } /* ****************************************** */ void * ndpi_calloc(unsigned long count, size_t size) { size_t len = count*size; void *p = ndpi_malloc(len); if(p) memset(p, 0, len); return(p); } /* ****************************************** */ void ndpi_free(void *ptr) { if(_ndpi_free) _ndpi_free(ptr); else free(ptr); } /* ****************************************** */ void ndpi_flow_free(void *ptr) { if(_ndpi_flow_free) _ndpi_flow_free(ptr); else ndpi_free_flow((struct ndpi_flow_struct *) ptr); } /* ****************************************** */ void * ndpi_realloc(void *ptr, size_t old_size, size_t new_size) { void *ret = ndpi_malloc(new_size); if(!ret) return(ret); else { memcpy(ret, ptr, old_size); ndpi_free(ptr); return(ret); } } /* ****************************************** */ char * ndpi_strdup(const char *s) { int len = strlen(s); char *m = ndpi_malloc(len+1); if(m) { memcpy(m, s, len); m[len] = '\0'; } return(m); } /* *********************************************************************************** */ /* Opaque structure defined here */ struct ndpi_ptree { patricia_tree_t *v4; patricia_tree_t *v6; }; /* *********************************************************************************** */ u_int32_t ndpi_detection_get_sizeof_ndpi_flow_struct(void) { return(sizeof(struct ndpi_flow_struct)); } /* *********************************************************************************** */ u_int32_t ndpi_detection_get_sizeof_ndpi_id_struct(void) { return(sizeof(struct ndpi_id_struct)); } /* *********************************************************************************** */ char * ndpi_get_proto_by_id(struct ndpi_detection_module_struct *ndpi_str, u_int id) { return((id >= ndpi_str->ndpi_num_supported_protocols) ? NULL : ndpi_str->proto_defaults[id].protoName); } /* *********************************************************************************** */ u_int16_t ndpi_get_proto_by_name(struct ndpi_detection_module_struct *ndpi_str, const char *name) { u_int16_t i, num = ndpi_get_num_supported_protocols(ndpi_str); for(i = 0; i < num; i++) if(strcasecmp(ndpi_get_proto_by_id(ndpi_str, i), name) == 0) return(i); return(NDPI_PROTOCOL_UNKNOWN); } /* ************************************************************************************* */ #ifdef CODE_UNUSED ndpi_port_range * ndpi_build_default_ports_range(ndpi_port_range *ports, u_int16_t portA_low, u_int16_t portA_high, u_int16_t portB_low, u_int16_t portB_high, u_int16_t portC_low, u_int16_t portC_high, u_int16_t portD_low, u_int16_t portD_high, u_int16_t portE_low, u_int16_t portE_high) { int i = 0; ports[i].port_low = portA_low, ports[i].port_high = portA_high; i++; ports[i].port_low = portB_low, ports[i].port_high = portB_high; i++; ports[i].port_low = portC_low, ports[i].port_high = portC_high; i++; ports[i].port_low = portD_low, ports[i].port_high = portD_high; i++; ports[i].port_low = portE_low, ports[i].port_high = portE_high; return(ports); } #endif /* *********************************************************************************** */ ndpi_port_range * ndpi_build_default_ports(ndpi_port_range *ports, u_int16_t portA, u_int16_t portB, u_int16_t portC, u_int16_t portD, u_int16_t portE) { int i = 0; ports[i].port_low = portA, ports[i].port_high = portA; i++; ports[i].port_low = portB, ports[i].port_high = portB; i++; ports[i].port_low = portC, ports[i].port_high = portC; i++; ports[i].port_low = portD, ports[i].port_high = portD; i++; ports[i].port_low = portE, ports[i].port_high = portE; return(ports); } /* ********************************************************************************** */ void ndpi_set_proto_breed(struct ndpi_detection_module_struct *ndpi_str, u_int16_t protoId, ndpi_protocol_breed_t breed) { if(protoId >= NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS) return; else ndpi_str->proto_defaults[protoId].protoBreed = breed; } /* ********************************************************************************** */ void ndpi_set_proto_category(struct ndpi_detection_module_struct *ndpi_str, u_int16_t protoId, ndpi_protocol_category_t protoCategory) { if(protoId >= NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS) return; else ndpi_str->proto_defaults[protoId].protoCategory = protoCategory; } /* ********************************************************************************** */ /* There are some (master) protocols that are informative, meaning that it shows what is the subprotocol about, but also that the subprotocol isn't a real protocol. Example: - DNS is informative as if we see a DNS request for www.facebook.com, the returned protocol is DNS.Facebook, but Facebook isn't a real subprotocol but rather it indicates a query for Facebook and not Facebook traffic. - HTTP/SSL are NOT informative as SSL.Facebook (likely) means that this is SSL (HTTPS) traffic containg Facebook traffic. */ u_int8_t ndpi_is_subprotocol_informative(struct ndpi_detection_module_struct *ndpi_str, u_int16_t protoId) { if(protoId >= NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS) return(0); switch(protoId) { /* All dissectors that have calls to ndpi_match_host_subprotocol() */ case NDPI_PROTOCOL_DNS: case NDPI_PROTOCOL_HTTP: case NDPI_PROTOCOL_TLS: case NDPI_PROTOCOL_QUIC: case NDPI_PROTOCOL_FBZERO: return(1); break; default: return(0); } } /* ********************************************************************************** */ void ndpi_exclude_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int16_t protocol_id, const char *_file, const char *_func,int _line) { if(protocol_id < NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS) { #ifdef NDPI_ENABLE_DEBUG_MESSAGES if( ndpi_str && ndpi_str->ndpi_log_level >= NDPI_LOG_DEBUG && ndpi_str->ndpi_debug_printf != NULL) { (*(ndpi_str->ndpi_debug_printf))(protocol_id, ndpi_str, NDPI_LOG_DEBUG, _file, _func, _line, "exclude %s\n",ndpi_get_proto_name(ndpi_str, protocol_id)); } #endif NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, protocol_id); } } /* ********************************************************************************** */ void ndpi_set_proto_defaults(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol_breed_t breed, u_int16_t protoId, u_int8_t can_have_a_subprotocol, u_int16_t tcp_master_protoId[2], u_int16_t udp_master_protoId[2], char *protoName, ndpi_protocol_category_t protoCategory, ndpi_port_range *tcpDefPorts, ndpi_port_range *udpDefPorts) { char *name; int j; if(protoId >= NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS) { #ifdef DEBUG NDPI_LOG_ERR(ndpi_str, "[NDPI] %s/protoId=%d: INTERNAL ERROR\n", protoName, protoId); #endif return; } if(ndpi_str->proto_defaults[protoId].protoName != NULL) { #ifdef DEBUG NDPI_LOG_ERR(ndpi_str, "[NDPI] %s/protoId=%d: already initialized. Ignoring it\n", protoName, protoId); #endif return; } name = ndpi_strdup(protoName); ndpi_str->proto_defaults[protoId].protoName = name, ndpi_str->proto_defaults[protoId].protoCategory = protoCategory, ndpi_str->proto_defaults[protoId].protoId = protoId, ndpi_str->proto_defaults[protoId].protoBreed = breed; ndpi_str->proto_defaults[protoId].can_have_a_subprotocol = can_have_a_subprotocol; memcpy(&ndpi_str->proto_defaults[protoId].master_tcp_protoId, tcp_master_protoId, 2*sizeof(u_int16_t)); memcpy(&ndpi_str->proto_defaults[protoId].master_udp_protoId, udp_master_protoId, 2*sizeof(u_int16_t)); for(j=0; jproto_defaults[protoId], 0, &ndpi_str->udpRoot, __FUNCTION__,__LINE__); if(tcpDefPorts[j].port_low != 0) addDefaultPort(ndpi_str, &tcpDefPorts[j], &ndpi_str->proto_defaults[protoId], 0, &ndpi_str->tcpRoot, __FUNCTION__,__LINE__); } } /* ******************************************************************** */ static int ndpi_default_ports_tree_node_t_cmp(const void *a, const void *b) { ndpi_default_ports_tree_node_t *fa = (ndpi_default_ports_tree_node_t*)a; ndpi_default_ports_tree_node_t *fb = (ndpi_default_ports_tree_node_t*)b; //printf("[NDPI] %s(%d, %d)\n", __FUNCTION__, fa->default_port, fb->default_port); return((fa->default_port == fb->default_port) ? 0 : ((fa->default_port < fb->default_port) ? -1 : 1)); } /* ******************************************************************** */ void ndpi_default_ports_tree_node_t_walker(const void *node, const ndpi_VISIT which, const int depth) { ndpi_default_ports_tree_node_t *f = *(ndpi_default_ports_tree_node_t **)node; printf("<%d>Walk on node %s (%u)\n", depth, which == ndpi_preorder?"ndpi_preorder": which == ndpi_postorder?"ndpi_postorder": which == ndpi_endorder?"ndpi_endorder": which == ndpi_leaf?"ndpi_leaf": "unknown", f->default_port); } /* ******************************************************************** */ static void addDefaultPort(struct ndpi_detection_module_struct *ndpi_str, ndpi_port_range *range, ndpi_proto_defaults_t *def, u_int8_t customUserProto, ndpi_default_ports_tree_node_t **root, const char *_func, int _line) { u_int16_t port; for(port=range->port_low; port<=range->port_high; port++) { ndpi_default_ports_tree_node_t *node = (ndpi_default_ports_tree_node_t*)ndpi_malloc(sizeof(ndpi_default_ports_tree_node_t)); ndpi_default_ports_tree_node_t *ret; if(!node) { NDPI_LOG_ERR(ndpi_str, "%s:%d not enough memory\n", _func, _line); break; } node->proto = def, node->default_port = port, node->customUserProto = customUserProto; ret = (ndpi_default_ports_tree_node_t*)ndpi_tsearch(node, (void*)root, ndpi_default_ports_tree_node_t_cmp); /* Add it to the tree */ if(ret != node) { NDPI_LOG_DBG(ndpi_str, "[NDPI] %s:%d found duplicate for port %u: overwriting it with new value\n", _func, _line, port); ret->proto = def; ndpi_free(node); } } } /* ****************************************************** */ /* NOTE This function must be called with a semaphore set, this in order to avoid changing the datastructures while using them */ static int removeDefaultPort(ndpi_port_range *range, ndpi_proto_defaults_t *def, ndpi_default_ports_tree_node_t **root) { ndpi_default_ports_tree_node_t node; u_int16_t port; for(port=range->port_low; port<=range->port_high; port++) { ndpi_default_ports_tree_node_t *ret; node.proto = def, node.default_port = port; ret = (ndpi_default_ports_tree_node_t*)ndpi_tdelete(&node, (void*)root, ndpi_default_ports_tree_node_t_cmp); /* Add it to the tree */ if(ret != NULL) { ndpi_free((ndpi_default_ports_tree_node_t*)ret); return(0); } } return(-1); } /* ****************************************************** */ static int ndpi_string_to_automa(struct ndpi_detection_module_struct *ndpi_str, ndpi_automa *automa, char *value, u_int16_t protocol_id, ndpi_protocol_category_t category, ndpi_protocol_breed_t breed) { AC_PATTERN_t ac_pattern; if(protocol_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) { NDPI_LOG_ERR(ndpi_str, "[NDPI] protoId=%d: INTERNAL ERROR\n", protocol_id); return(-1); } if(automa->ac_automa == NULL) return(-2); ac_pattern.astring = value, ac_pattern.rep.number = protocol_id, ac_pattern.rep.category = (u_int16_t)category, ac_pattern.rep.breed = (u_int16_t)breed; #ifdef MATCH_DEBUG printf("Adding to automa [%s][protocol_id: %u][category: %u][breed: %u]\n", value, protocol_id, category, breed); #endif if(value == NULL) ac_pattern.length = 0; else ac_pattern.length = strlen(ac_pattern.astring); if(ac_automata_add(((AC_AUTOMATA_t*)automa->ac_automa), &ac_pattern) != ACERR_SUCCESS) return(-2); return(0); } /* ****************************************************** */ static int ndpi_add_host_url_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *_value, int protocol_id, ndpi_protocol_category_t category, ndpi_protocol_breed_t breed) { int rv; char *value = ndpi_strdup(_value); if(!value) return(-1); #ifdef DEBUG NDPI_LOG_DEBUG2(ndpi_str, "[NDPI] Adding [%s][%d]\n", value, protocol_id); #endif rv = ndpi_string_to_automa(ndpi_str, &ndpi_str->host_automa, value, protocol_id, category, breed); if(rv != 0) ndpi_free(value); return(rv); } /* ****************************************************** */ #ifdef CODE_UNUSED int ndpi_add_content_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *value, int protocol_id, ndpi_protocol_category_t category, ndpi_protocol_breed_t breed) { return(ndpi_string_to_automa(ndpi_str, &ndpi_str->content_automa, value, protocol_id, category, breed)); } #endif /* ****************************************************** */ /* NOTE This function must be called with a semaphore set, this in order to avoid changing the datastructures while using them */ static int ndpi_remove_host_url_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *value, int protocol_id) { NDPI_LOG_ERR(ndpi_str, "[NDPI] Missing implementation for proto %s/%d\n",value,protocol_id); return(-1); } /* ******************************************************************** */ void ndpi_init_protocol_match(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol_match *match) { u_int16_t no_master[2] = { NDPI_PROTOCOL_NO_MASTER_PROTO, NDPI_PROTOCOL_NO_MASTER_PROTO }; ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS]; if(ndpi_str->proto_defaults[match->protocol_id].protoName == NULL) { ndpi_str->proto_defaults[match->protocol_id].protoName = ndpi_strdup(match->proto_name); ndpi_str->proto_defaults[match->protocol_id].protoId = match->protocol_id; ndpi_str->proto_defaults[match->protocol_id].protoCategory = match->protocol_category; ndpi_str->proto_defaults[match->protocol_id].protoBreed = match->protocol_breed; ndpi_set_proto_defaults(ndpi_str, ndpi_str->proto_defaults[match->protocol_id].protoBreed, ndpi_str->proto_defaults[match->protocol_id].protoId, 0 /* can_have_a_subprotocol */, no_master, no_master, ndpi_str->proto_defaults[match->protocol_id].protoName, ndpi_str->proto_defaults[match->protocol_id].protoCategory, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); } ndpi_add_host_url_subprotocol(ndpi_str, match->string_to_match, match->protocol_id, match->protocol_category, match->protocol_breed); } /* ******************************************************************** */ #ifdef HAVE_HYPERSCAN static int hyperscan_load_patterns(struct hs *hs, u_int num_patterns, const char **expressions, unsigned int *ids) { hs_compile_error_t *compile_err; if(hs_compile_multi(expressions, NULL, ids, num_patterns, HS_MODE_BLOCK, NULL, &hs->database, &compile_err) != HS_SUCCESS) { NDPI_LOG_ERR(ndpi_str, "Unable to initialize hyperscan database\n"); hs_free_compile_error(compile_err); return(-1); } hs->scratch = NULL; if(hs_alloc_scratch(hs->database, &hs->scratch) != HS_SUCCESS) { NDPI_LOG_ERR(ndpi_str, "Unable to allocate hyperscan scratch space\n"); hs_free_database(hs->database); return(-1); } return(0); } /* ******************************************************************** */ static char* string2hex(const char *pat) { u_int patlen, i; char *hexbuf, *buf; patlen = strlen(pat); hexbuf = (char*)ndpi_calloc(sizeof(char), patlen * 4 + 1); if(!hexbuf) return(NULL); for (i = 0, buf = hexbuf; i < patlen; i++, buf += 4) { snprintf(buf, 5, "\\x%02x", (unsigned char)pat[i]); } *buf = '\0'; return(hexbuf); } /* ******************************************************************** */ static int init_hyperscan(struct ndpi_detection_module_struct *ndpi_str) { u_int num_patterns = 0, i, j; char **expressions; unsigned int *ids; unsigned char *need_to_be_free; struct hs *hs; int rc; ndpi_str->hyperscan = (void*)ndpi_malloc(sizeof(struct hs)); if(!ndpi_str->hyperscan) return(-1); hs = (struct hs*)ndpi_str->hyperscan; for(i = 0; (host_match[i].string_to_match != NULL) || (host_match[i].pattern_to_match != NULL); i++) num_patterns++; expressions = (char**)ndpi_calloc(sizeof(char*), num_patterns + 1); if(!expressions) return(-1); ids = (unsigned int*)ndpi_calloc(sizeof(unsigned int), num_patterns + 1); if(!ids) { ndpi_free(expressions); return(-1); } need_to_be_free = (unsigned char*)ndpi_calloc(sizeof(unsigned char), num_patterns + 1); if(!need_to_be_free) { ndpi_free(expressions); ndpi_free(ids); return(-1); } for(i = 0, j = 0; host_match[i].string_to_match != NULL || host_match[i].pattern_to_match != NULL; i++) { if(host_match[i].pattern_to_match) { expressions[j] = host_match[i].pattern_to_match; ids[j] = host_match[i].protocol_id; need_to_be_free[j] = 0; ++j; } else { expressions[j] = string2hex(host_match[i].string_to_match); if(expressions[j] != NULL) { ids[j] = host_match[i].protocol_id; need_to_be_free[j] = 1; ++j; } else { #ifdef DEBUG printf("Fail to calloc memory for %s\n", host_match[i].string_to_match); #endif } } /*printf("[DEBUG] %s\n", j ? expressions[j - 1] : "No Expression");*/ } rc = hyperscan_load_patterns(hs, j, (const char**)expressions, ids); for(i = 0; i < j; ++i) if(need_to_be_free[i]) ndpi_free(expressions[i]); ndpi_free(expressions), ndpi_free(ids); ndpi_free(need_to_be_free); return(rc); } /* ******************************************************************** */ static void free_hyperscan_memory(struct hs *h) { if(h) { hs_free_scratch(h->scratch); hs_free_database(h->database); ndpi_free(h); } } /* ******************************************************************** */ static void destroy_hyperscan(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str->hyperscan) free_hyperscan_memory((struct hs*)ndpi_str->hyperscan); } #endif /* ******************************************************************** */ static void init_string_based_protocols(struct ndpi_detection_module_struct *ndpi_str) { int i; #ifdef HAVE_HYPERSCAN // TODO check return value init_hyperscan(ndpi_str); #endif for(i=0; host_match[i].string_to_match != NULL; i++) ndpi_init_protocol_match(ndpi_str, &host_match[i]); ndpi_enable_loaded_categories(ndpi_str); #ifdef MATCH_DEBUG // ac_automata_display(ndpi_str->host_automa.ac_automa, 'n'); #endif for(i=0; ndpi_en_bigrams[i] != NULL; i++) ndpi_string_to_automa(ndpi_str, &ndpi_str->bigrams_automa, (char*)ndpi_en_bigrams[i], 1, 1, 1); for(i=0; ndpi_en_impossible_bigrams[i] != NULL; i++) ndpi_string_to_automa(ndpi_str, &ndpi_str->impossible_bigrams_automa, (char*)ndpi_en_impossible_bigrams[i], 1, 1, 1); } /* ******************************************************************** */ int ndpi_set_detection_preferences(struct ndpi_detection_module_struct *ndpi_str, ndpi_detection_preference pref, int value) { switch(pref) { case ndpi_pref_direction_detect_disable: ndpi_str->direction_detect_disable = (u_int8_t)value; break; case ndpi_pref_disable_metadata_export: ndpi_str->disable_metadata_export = (u_int8_t)value; break; default: return(-1); } return(0); } /* ******************************************************************** */ static void ndpi_validate_protocol_initialization(struct ndpi_detection_module_struct *ndpi_str) { int i; for(i=0; i<(int)ndpi_str->ndpi_num_supported_protocols; i++) { if(ndpi_str->proto_defaults[i].protoName == NULL) { NDPI_LOG_ERR(ndpi_str, "[NDPI] INTERNAL ERROR missing protoName initialization for [protoId=%d]: recovering\n", i); } else { if((i != NDPI_PROTOCOL_UNKNOWN) && (ndpi_str->proto_defaults[i].protoCategory == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)) { NDPI_LOG_ERR(ndpi_str, "[NDPI] INTERNAL ERROR missing category [protoId=%d/%s] initialization: recovering\n", i, ndpi_str->proto_defaults[i].protoName ? ndpi_str->proto_defaults[i].protoName : "???"); } } } } /* ******************************************************************** */ /* This function is used to map protocol name and default ports and it MUST be updated whenever a new protocol is added to NDPI. Do NOT add web services (NDPI_SERVICE_xxx) here. */ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndpi_str) { ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS]; u_int16_t no_master[2] = { NDPI_PROTOCOL_NO_MASTER_PROTO, NDPI_PROTOCOL_NO_MASTER_PROTO }, custom_master[2]; /* Reset all settings */ memset(ndpi_str->proto_defaults, 0, sizeof(ndpi_str->proto_defaults)); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNRATED, NDPI_PROTOCOL_UNKNOWN, 0 /* can_have_a_subprotocol */, no_master, no_master, "Unknown", NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_FTP_CONTROL, 0 /* can_have_a_subprotocol */, no_master, no_master, "FTP_CONTROL", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 21, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_FTP_DATA, 0 /* can_have_a_subprotocol */, no_master, no_master, "FTP_DATA", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 20, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_MAIL_POP, 0 /* can_have_a_subprotocol */, no_master, no_master, "POP3", NDPI_PROTOCOL_CATEGORY_MAIL, ndpi_build_default_ports(ports_a, 110, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_MAIL_POPS, 0 /* can_have_a_subprotocol */, no_master, no_master, "POPS", NDPI_PROTOCOL_CATEGORY_MAIL, ndpi_build_default_ports(ports_a, 995, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MAIL_SMTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SMTP", NDPI_PROTOCOL_CATEGORY_MAIL, ndpi_build_default_ports(ports_a, 25, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_MAIL_SMTPS, 0 /* can_have_a_subprotocol */, no_master, no_master, "SMTPS", NDPI_PROTOCOL_CATEGORY_MAIL, ndpi_build_default_ports(ports_a, 465, 587, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_MAIL_IMAP, 0 /* can_have_a_subprotocol */, no_master, no_master, "IMAP", NDPI_PROTOCOL_CATEGORY_MAIL, ndpi_build_default_ports(ports_a, 143, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_MAIL_IMAPS, 0 /* can_have_a_subprotocol */, no_master, no_master, "IMAPS", NDPI_PROTOCOL_CATEGORY_MAIL, ndpi_build_default_ports(ports_a, 993, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DNS, 1 /* can_have_a_subprotocol */, no_master, no_master, "DNS", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 53, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 53, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IPP, 0 /* can_have_a_subprotocol */, no_master, no_master, "IPP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IMO, 0 /* can_have_a_subprotocol */, no_master, no_master, "IMO", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HTTP, 1 /* can_have_a_subprotocol */, no_master, no_master, "HTTP", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 80, 0 /* ntop */, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MDNS, 1 /* can_have_a_subprotocol */, no_master, no_master, "MDNS", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5353, 5354, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "NTP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 123, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NETBIOS, 0 /* can_have_a_subprotocol */, no_master, no_master, "NetBIOS", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 139, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 137, 138, 139, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NFS, 0 /* can_have_a_subprotocol */, no_master, no_master, "NFS", NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, ndpi_build_default_ports(ports_a, 2049, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 2049, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SSDP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SSDP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_BGP, 0 /* can_have_a_subprotocol */, no_master, no_master, "BGP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 179, 2605, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SNMP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SNMP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 161, 162, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_XDMCP, 0 /* can_have_a_subprotocol */, no_master, no_master, "XDMCP", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 177, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 177, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_DANGEROUS, NDPI_PROTOCOL_SMBV1, 0 /* can_have_a_subprotocol */, no_master, no_master, "SMBv1", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SYSLOG, 0 /* can_have_a_subprotocol */, no_master, no_master, "Syslog", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 514, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 514, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DHCP, 0 /* can_have_a_subprotocol */, no_master, no_master, "DHCP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 67, 68, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_POSTGRES, 0 /* can_have_a_subprotocol */, no_master, no_master, "PostgreSQL", NDPI_PROTOCOL_CATEGORY_DATABASE, ndpi_build_default_ports(ports_a, 5432, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MYSQL, 0 /* can_have_a_subprotocol */, no_master, no_master, "MySQL", NDPI_PROTOCOL_CATEGORY_DATABASE, ndpi_build_default_ports(ports_a, 3306, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_DIRECT_DOWNLOAD_LINK, 0 /* can_have_a_subprotocol */, no_master, no_master, "Direct_Download_Link", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_APPLEJUICE, 0 /* can_have_a_subprotocol */, no_master, no_master, "AppleJuice", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_DIRECTCONNECT, 0 /* can_have_a_subprotocol */, no_master, no_master, "DirectConnect", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_NTOP, 0 /* can_have_a_subprotocol */, no_master, no_master, "ntop", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_VMWARE, 0 /* can_have_a_subprotocol */, no_master, no_master, "VMware", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 903, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 902, 903, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_FBZERO, 0 /* can_have_a_subprotocol */, no_master, no_master, "FacebookZero", NDPI_PROTOCOL_CATEGORY_SOCIAL_NETWORK, ndpi_build_default_ports(ports_a, 443, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_KONTIKI, 0 /* can_have_a_subprotocol */, no_master, no_master, "Kontiki", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_OPENFT, 0 /* can_have_a_subprotocol */, no_master, no_master, "OpenFT", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_FASTTRACK, 0 /* can_have_a_subprotocol */, no_master, no_master, "FastTrack", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_GNUTELLA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Gnutella", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_EDONKEY, 0 /* can_have_a_subprotocol */, no_master, no_master, "eDonkey", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_BITTORRENT, 0 /* can_have_a_subprotocol */, no_master, no_master, "BitTorrent", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 51413, 53646, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 6771, 51413, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SKYPE, 0 /* can_have_a_subprotocol */, no_master, no_master, "Skype", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SKYPE_CALL, 0 /* can_have_a_subprotocol */, no_master, no_master, "SkypeCall", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_TIKTOK, 0 /* can_have_a_subprotocol */, no_master, no_master, "TikTok", NDPI_PROTOCOL_CATEGORY_SOCIAL_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TEREDO, 0 /* can_have_a_subprotocol */, no_master, no_master, "Teredo", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 3544, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_WECHAT, 0 /* can_have_a_subprotocol */, no_master, /* wechat.com */ no_master, "WeChat", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MEMCACHED, 0 /* can_have_a_subprotocol */, no_master, no_master, "Memcached", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 11211, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 11211, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SMBV23, 0 /* can_have_a_subprotocol */, no_master, no_master, "SMBv23", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 445, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_MINING, 0 /* can_have_a_subprotocol */, no_master, no_master, "Mining", CUSTOM_CATEGORY_MINING, ndpi_build_default_ports(ports_a, 8333, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NEST_LOG_SINK, 0 /* can_have_a_subprotocol */, no_master, no_master, "NestLogSink", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 11095, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MODBUS, 1 /* no subprotocol */, no_master, no_master, "Modbus", NDPI_PROTOCOL_CATEGORY_NETWORK, /* Perhaps IoT in the future */ ndpi_build_default_ports(ports_a, 502, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP_CALL, 0 /* can_have_a_subprotocol */, no_master, no_master, "WhatsAppCall", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_DATASAVER, 0 /* can_have_a_subprotocol */, no_master, no_master, "DataSaver", NDPI_PROTOCOL_CATEGORY_WEB /* dummy */, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_SIGNAL, 0 /* can_have_a_subprotocol */, no_master, /* https://signal.org */ no_master, "Signal", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_DOH_DOT, 0 /* can_have_a_subprotocol */, no_master, no_master, "DoH_DoT", NDPI_PROTOCOL_CATEGORY_NETWORK /* dummy */, ndpi_build_default_ports(ports_a, 853, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_LINE, 0 /* can_have_a_subprotocol */, no_master, no_master, "Line", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WIREGUARD, 0 /* can_have_a_subprotocol */, no_master, no_master, "WireGuard", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 51820, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_PPSTREAM, 0 /* can_have_a_subprotocol */, no_master, no_master, "PPStream", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_XBOX, 0 /* can_have_a_subprotocol */, no_master, no_master, "Xbox", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 3074, 3076, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 3074, 3076, 500, 3544, 4500) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_PLAYSTATION, 0 /* can_have_a_subprotocol */, no_master, no_master, "Playstation", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 1935, 3478, 3479, 3480, 0) /* TCP */, ndpi_build_default_ports(ports_b, 3478, 3479, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_QQ, 0 /* can_have_a_subprotocol */, no_master, no_master, "QQ", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_RTSP, 0 /* can_have_a_subprotocol */, no_master, no_master, "RTSP", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 554, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 554, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_ICECAST, 0 /* can_have_a_subprotocol */, no_master, no_master, "IceCast", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_PPLIVE, 0 /* can_have_a_subprotocol */, no_master, no_master, "PPLive", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_PPSTREAM, 0 /* can_have_a_subprotocol */, no_master, no_master, "PPStream", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_ZATTOO, 0 /* can_have_a_subprotocol */, no_master, no_master, "Zattoo", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_SHOUTCAST, 0 /* can_have_a_subprotocol */, no_master, no_master, "ShoutCast", NDPI_PROTOCOL_CATEGORY_MUSIC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_SOPCAST, 0 /* can_have_a_subprotocol */, no_master, no_master, "Sopcast", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_TVANTS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Tvants", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_TVUPLAYER, 0 /* can_have_a_subprotocol */, no_master, no_master, "TVUplayer", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HTTP_DOWNLOAD, 1 /* can_have_a_subprotocol */, no_master, no_master, "HTTP_Download", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_QQLIVE, 0 /* can_have_a_subprotocol */, no_master, no_master, "QQLive", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_THUNDER, 0 /* can_have_a_subprotocol */, no_master, no_master, "Thunder", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_SOULSEEK, 0 /* can_have_a_subprotocol */, no_master, no_master, "Soulseek", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_PS_VUE, 0 /* can_have_a_subprotocol */, no_master, no_master, "PS_VUE", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_IRC, 0 /* can_have_a_subprotocol */, no_master, no_master, "IRC", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 194, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 194, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_AYIYA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Ayiya", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5072, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_UNENCRYPTED_JABBER, 0 /* can_have_a_subprotocol */, no_master, no_master, "Unencrypted_Jabber", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_OSCAR, 0 /* can_have_a_subprotocol */, no_master, no_master, "Oscar", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_BATTLEFIELD, 0 /* can_have_a_subprotocol */, no_master, no_master, "BattleField", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_VRRP, 0 /* can_have_a_subprotocol */, no_master, no_master, "VRRP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_STEAM, 0 /* can_have_a_subprotocol */, no_master, no_master, "Steam", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_HALFLIFE2, 0 /* can_have_a_subprotocol */, no_master, no_master, "HalfLife2", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_WORLDOFWARCRAFT, 0 /* can_have_a_subprotocol */, no_master, no_master, "WorldOfWarcraft", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_HOTSPOT_SHIELD, 0 /* can_have_a_subprotocol */, no_master, no_master, "HotspotShield", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_TELNET, 0 /* can_have_a_subprotocol */, no_master, no_master, "Telnet", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 23, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); custom_master[0] = NDPI_PROTOCOL_SIP, custom_master[1] = NDPI_PROTOCOL_H323; ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_STUN, 0 /* can_have_a_subprotocol */, no_master, custom_master, "STUN", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 3478, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_IP_IPSEC, 0 /* can_have_a_subprotocol */, no_master, no_master, "IPsec", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 500, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 500, 4500, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_GRE, 0 /* can_have_a_subprotocol */, no_master, no_master, "GRE", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_ICMP, 0 /* can_have_a_subprotocol */, no_master, no_master, "ICMP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_IGMP, 0 /* can_have_a_subprotocol */, no_master, no_master, "IGMP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_EGP, 0 /* can_have_a_subprotocol */, no_master, no_master, "EGP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_SCTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SCTP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_OSPF, 0 /* can_have_a_subprotocol */, no_master, no_master, "OSPF", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 2604, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_IP_IN_IP, 0 /* can_have_a_subprotocol */, no_master, no_master, "IP_in_IP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "RTP", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RDP, 0 /* can_have_a_subprotocol */, no_master, no_master, "RDP", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 3389, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 3389, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_VNC, 0 /* can_have_a_subprotocol */, no_master, no_master, "VNC", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 5900, 5901, 5800, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_PCANYWHERE, 0 /* can_have_a_subprotocol */, no_master, no_master, "PcAnywhere", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_ZOOM, 0 /* can_have_a_subprotocol */, no_master, no_master, "Zoom", NDPI_PROTOCOL_CATEGORY_VIDEO, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP_FILES, 0 /* can_have_a_subprotocol */, no_master, no_master, "WhatsAppFiles", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP, 0 /* can_have_a_subprotocol */, no_master, no_master, "WhatsApp", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_TLS, 1 /* can_have_a_subprotocol */, no_master, no_master, "TLS", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 443, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SSH, 0 /* can_have_a_subprotocol */, no_master, no_master, "SSH", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 22, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_USENET, 0 /* can_have_a_subprotocol */, no_master, no_master, "Usenet", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MGCP, 0 /* can_have_a_subprotocol */, no_master, no_master, "MGCP", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IAX, 0 /* can_have_a_subprotocol */, no_master, no_master, "IAX", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 4569, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 4569, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_AFP, 0 /* can_have_a_subprotocol */, no_master, no_master, "AFP", NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, ndpi_build_default_ports(ports_a, 548, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 548, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_HULU, 0 /* can_have_a_subprotocol */, no_master, no_master, "Hulu", NDPI_PROTOCOL_CATEGORY_STREAMING, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_CHECKMK, 0 /* can_have_a_subprotocol */, no_master, no_master, "CHECKMK", NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, ndpi_build_default_ports(ports_a, 6556, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_STEALTHNET, 0 /* can_have_a_subprotocol */, no_master, no_master, "Stealthnet", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_AIMINI, 0 /* can_have_a_subprotocol */, no_master, no_master, "Aimini", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SIP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SIP", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 5060, 5061, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5060, 5061, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TRUPHONE, 0 /* can_have_a_subprotocol */, no_master, no_master, "TruPhone", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_IP_ICMPV6, 0 /* can_have_a_subprotocol */, no_master, no_master, "ICMPV6", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DHCPV6, 0 /* can_have_a_subprotocol */, no_master, no_master, "DHCPV6", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_ARMAGETRON, 0 /* can_have_a_subprotocol */, no_master, no_master, "Armagetron", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_CROSSFIRE, 0 /* can_have_a_subprotocol */, no_master, no_master, "Crossfire", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_DOFUS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Dofus", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_FIESTA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Fiesta", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_FLORENSIA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Florensia", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_GUILDWARS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Guildwars", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HTTP_ACTIVESYNC, 1 /* can_have_a_subprotocol */, no_master, no_master, "HTTP_ActiveSync", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_KERBEROS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Kerberos", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 88, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 88, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_LDAP, 0 /* can_have_a_subprotocol */, no_master, no_master, "LDAP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 389, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 389, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_MAPLESTORY, 0 /* can_have_a_subprotocol */, no_master, no_master, "MapleStory", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MSSQL_TDS, 0 /* can_have_a_subprotocol */, no_master, no_master, "MsSQL-TDS", NDPI_PROTOCOL_CATEGORY_DATABASE, ndpi_build_default_ports(ports_a, 1433, 1434, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_PPTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "PPTP", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_WARCRAFT3, 0 /* can_have_a_subprotocol */, no_master, no_master, "Warcraft3", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_WORLD_OF_KUNG_FU, 0 /* can_have_a_subprotocol */, no_master, no_master, "WorldOfKungFu", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DCERPC, 0 /* can_have_a_subprotocol */, no_master, no_master, "DCE_RPC", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 135, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NETFLOW, 0 /* can_have_a_subprotocol */, no_master, no_master, "NetFlow", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 2055, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SFLOW, 0 /* can_have_a_subprotocol */, no_master, no_master, "sFlow", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 6343, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HTTP_CONNECT, 1 /* can_have_a_subprotocol */, no_master, no_master, "HTTP_Connect", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HTTP_PROXY, 1 /* can_have_a_subprotocol */, no_master, no_master, "HTTP_Proxy", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 8080, 3128, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_CITRIX, 0 /* can_have_a_subprotocol */, no_master, no_master, "Citrix", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 1494, 2598, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WEBEX, 0 /* can_have_a_subprotocol */, no_master, no_master, "Webex", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RADIUS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Radius", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 1812, 1813, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 1812, 1813, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TEAMVIEWER, 0 /* can_have_a_subprotocol */, no_master, no_master, "TeamViewer", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 5938, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5938, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_LOTUS_NOTES, 0 /* can_have_a_subprotocol */, no_master, no_master, "LotusNotes", NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, ndpi_build_default_ports(ports_a, 1352, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SAP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SAP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 3201, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); /* Missing dissector: port based only */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_GTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "GTP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 2152, 2123, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_UPNP, 0 /* can_have_a_subprotocol */, no_master, no_master, "UPnP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 1780, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 1900, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TELEGRAM, 0 /* can_have_a_subprotocol */, no_master, no_master, "Telegram", NDPI_PROTOCOL_CATEGORY_CHAT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_QUIC, 1 /* can_have_a_subprotocol */, no_master, no_master, "QUIC", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 443, 80, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DIAMETER, 0 /* can_have_a_subprotocol */, no_master, no_master, "Diameter", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 3868, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_APPLE_PUSH, 0 /* can_have_a_subprotocol */, no_master, no_master, "ApplePush", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 1, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DROPBOX, 0 /* can_have_a_subprotocol */, no_master, no_master, "Dropbox", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 17500, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SPOTIFY, 0 /* can_have_a_subprotocol */, no_master, no_master, "Spotify", NDPI_PROTOCOL_CATEGORY_MUSIC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MESSENGER, 0 /* can_have_a_subprotocol */, no_master, no_master, "Messenger", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_LISP, 0 /* can_have_a_subprotocol */, no_master, no_master, "LISP", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 4342, 4341, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_EAQ, 0 /* can_have_a_subprotocol */, no_master, no_master, "EAQ", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 6000, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_KAKAOTALK_VOICE, 0 /* can_have_a_subprotocol */, no_master, no_master, "KakaoTalk_Voice", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_MPEGTS, 0 /* can_have_a_subprotocol */, no_master, no_master, "MPEG_TS", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); /* http://en.wikipedia.org/wiki/Link-local_Multicast_Name_Resolution */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_LLMNR, 0 /* can_have_a_subprotocol */, no_master, no_master, "LLMNR", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 5355, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5355, 0, 0, 0, 0) /* UDP */); /* Missing dissector: port based only */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, NDPI_PROTOCOL_REMOTE_SCAN, 0 /* can_have_a_subprotocol */, no_master, no_master, "RemoteScan", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 6077, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 6078, 0, 0, 0, 0) /* UDP */); /* Missing dissector: port based only */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_H323, 0 /* can_have_a_subprotocol */, no_master, no_master,"H323", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 1719, 1720, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 1719, 1720, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_OPENVPN, 0 /* can_have_a_subprotocol */, no_master, no_master, "OpenVPN", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 1194, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 1194, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_NOE, 0 /* can_have_a_subprotocol */, no_master, no_master, "NOE", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_CISCOVPN, 0 /* can_have_a_subprotocol */, no_master, no_master, "CiscoVPN", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 10000, 8008, 8009, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 10000, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TEAMSPEAK, 0 /* can_have_a_subprotocol */, no_master, no_master, "TeamSpeak", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SKINNY, 0 /* can_have_a_subprotocol */, no_master, no_master, "CiscoSkinny", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 2000, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RTCP, 0 /* can_have_a_subprotocol */, no_master, no_master, "RTCP", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RSYNC, 0 /* can_have_a_subprotocol */, no_master, no_master, "RSYNC", NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, ndpi_build_default_ports(ports_a, 873, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_ORACLE, 0 /* can_have_a_subprotocol */, no_master, no_master, "Oracle", NDPI_PROTOCOL_CATEGORY_DATABASE, ndpi_build_default_ports(ports_a, 1521, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_CORBA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Corba", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_UBUNTUONE, 0 /* can_have_a_subprotocol */, no_master, no_master, "UbuntuONE", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHOIS_DAS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Whois-DAS", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 43, 4343, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_COLLECTD, 0 /* can_have_a_subprotocol */, no_master, no_master, "Collectd", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 25826, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SOCKS, 0 /* can_have_a_subprotocol */, no_master, no_master, "SOCKS", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 1080, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 1080, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TFTP, 0 /* can_have_a_subprotocol */, no_master, no_master, "TFTP", NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 69, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RTMP, 0 /* can_have_a_subprotocol */, no_master, no_master, "RTMP", NDPI_PROTOCOL_CATEGORY_MEDIA, ndpi_build_default_ports(ports_a, 1935, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_PANDO, 0 /* can_have_a_subprotocol */, no_master, no_master, "Pando_Media_Booster", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MEGACO, 0 /* can_have_a_subprotocol */, no_master, no_master, "Megaco", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 2944 , 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_REDIS, 0 /* can_have_a_subprotocol */, no_master, no_master, "Redis", NDPI_PROTOCOL_CATEGORY_DATABASE, ndpi_build_default_ports(ports_a, 6379, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0 , 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_ZMQ, 0 /* can_have_a_subprotocol */, no_master, no_master, "ZeroMQ", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0 , 0, 0, 0, 0) ); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_VHUA, 0 /* can_have_a_subprotocol */, no_master, no_master, "VHUA", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 58267, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_STARCRAFT, 0 /* can_have_a_subprotocol */, no_master, no_master, "Starcraft", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 1119, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 1119, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_UBNTAC2, 0 /* can_have_a_subprotocol */, no_master, no_master, "UBNTAC2", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 10001, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_VIBER, 0 /* can_have_a_subprotocol */, no_master, no_master, "Viber", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 7985, 5242, 5243, 4244, 0), /* TCP */ ndpi_build_default_ports(ports_b, 7985, 7987, 5242, 5243, 4244)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_COAP, 0 /* can_have_a_subprotocol */, no_master, no_master, "COAP", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 5683, 5684, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MQTT, 0 /* can_have_a_subprotocol */, no_master, no_master, "MQTT", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 1883, 8883, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SOMEIP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SOMEIP", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 30491, 30501, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 30491, 30501, 30490, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_RX, 0 /* can_have_a_subprotocol */, no_master, no_master, "RX", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_GIT, 0 /* can_have_a_subprotocol */, no_master, no_master, "Git", NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, ndpi_build_default_ports(ports_a, 9418, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DRDA, 0 /* can_have_a_subprotocol */, no_master, no_master, "DRDA", NDPI_PROTOCOL_CATEGORY_DATABASE, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_HANGOUT_DUO, 0 /* can_have_a_subprotocol */, no_master, no_master, "GoogleHangoutDuo", NDPI_PROTOCOL_CATEGORY_VOIP, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_BJNP, 0 /* can_have_a_subprotocol */, no_master, no_master, "BJNP", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 8612, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SMPP, 0 /* can_have_a_subprotocol */, no_master, no_master, "SMPP", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_OOKLA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Ookla", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_AMQP, 0 /* can_have_a_subprotocol */, no_master, no_master, "AMQP", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_DNSCRYPT, 0 /* can_have_a_subprotocol */, no_master, no_master, "DNScrypt", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), /* TCP */ ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0)); /* UDP */ ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TINC, 0 /* can_have_a_subprotocol */, no_master, no_master, "TINC", NDPI_PROTOCOL_CATEGORY_VPN, ndpi_build_default_ports(ports_a, 655, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 655, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_FIX, 0 /* can_have_a_subprotocol */, no_master, no_master, "FIX", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_NINTENDO, 0 /* can_have_a_subprotocol */, no_master, no_master, "Nintendo", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_CSGO, 0 /* can_have_a_subprotocol */, no_master, no_master, "CSGO", NDPI_PROTOCOL_CATEGORY_GAME, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_AJP, 0 /* can_have_a_subprotocol */, no_master, no_master, "AJP", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 8009, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TARGUS_GETDATA, 0 /* can_have_a_subprotocol */, no_master, no_master, "Targus Dataspeed", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 5001, 5201, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5001, 5201, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_AMAZON_VIDEO, 0 /* can_have_a_subprotocol */, no_master, no_master, "AmazonVideo", NDPI_PROTOCOL_CATEGORY_CLOUD, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DNP3, 1 /* no subprotocol */, no_master, no_master, "DNP3", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 20000, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_104, 1 /* no subprotocol */, no_master, no_master, "104", NDPI_PROTOCOL_CATEGORY_NETWORK, /* Perhaps IoT in the future */ ndpi_build_default_ports(ports_a, 2404, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_BLOOMBERG, 1 /* no subprotocol */, no_master, no_master, "Bloomberg", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_CAPWAP, 1 /* no subprotocol */, no_master, no_master, "CAPWAP", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 5246, 5247, 0, 0, 0) /* UDP */ ); ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_ZABBIX, 1 /* no subprotocol */, no_master, no_master, "Zabbix", NDPI_PROTOCOL_CATEGORY_NETWORK, ndpi_build_default_ports(ports_a, 10050, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */ ); #ifdef CUSTOM_NDPI_PROTOCOLS #include "../../../nDPI-custom/custom_ndpi_main.c" #endif /* calling function for host and content matched protocols */ init_string_based_protocols(ndpi_str); ndpi_validate_protocol_initialization(ndpi_str); } /* ****************************************************** */ #ifdef CUSTOM_NDPI_PROTOCOLS #include "../../../nDPI-custom/custom_ndpi_protocols.c" #endif /* ****************************************************** */ static int ac_match_handler(AC_MATCH_t *m, AC_TEXT_t *txt, AC_REP_t *match) { int min_len = (txt->length < m->patterns->length) ? txt->length : m->patterns->length; char buf[64] = { '\0' }; int min_buf_len = (txt->length > 63 /* sizeof(buf)-1 */) ? 63 : txt->length; u_int buf_len = strlen(buf); strncpy(buf, txt->astring, min_buf_len); buf[min_buf_len] = '\0'; #ifdef MATCH_DEBUG printf("Searching [to search: %s/%u][pattern: %s/%u] [len: %d][match_num: %u][%s]\n", buf, (unigned int)txt->length, m->patterns->astring, m->patterns->length, min_len, m->match_num, m->patterns->astring); #endif { char *whatfound = strstr(buf, m->patterns->astring); #ifdef MATCH_DEBUG printf("[NDPI] %s() [searching=%s][pattern=%s][%s][%c]\n", __FUNCTION__, buf, m->patterns->astring, whatfound ? whatfound : "", whatfound[-1]); #endif /* The patch below allows in case of pattern ws.amazon.com to avoid matching aws.amazon.com whereas a.ws.amazon.com has to match */ if(whatfound && (whatfound != buf) && (m->patterns->astring[0] != '.') /* The searched pattern does not start with . */ && strchr(m->patterns->astring, '.') /* The matched pattern has a . (e.g. numeric or sym IPs) */) { if(whatfound[-1] != '.') { return(0); } else { memcpy(match, &m->patterns[0].rep, sizeof(AC_REP_t)); /* Partial match? */ return(0); /* Keep searching as probably there is a better match */ } } } /* Return 1 for stopping to the first match. We might consider searching for the more specific match, paying more cpu cycles. */ memcpy(match, &m->patterns[0].rep, sizeof(AC_REP_t)); if(((buf_len >= min_len) && (strncmp(&buf[buf_len-min_len], m->patterns->astring, min_len) == 0)) || (strncmp(buf, m->patterns->astring, min_len) == 0) /* begins with */ ) { #ifdef MATCH_DEBUG printf("Found match [%s][%s] [len: %d]" // "[proto_id: %u]" "\n", buf, m->patterns->astring, min_len /* , *matching_protocol_id */); #endif return(1); /* If the pattern found matches the string at the beginning we stop here */ } else { #ifdef MATCH_DEBUG printf("NO match found: continue\n"); #endif return(0); /* 0 to continue searching, !0 to stop */ } } /* ******************************************************************** */ static int fill_prefix_v4(prefix_t *p, const struct in_addr *a, int b, int mb) { do { if(b < 0 || b > mb) return(-1); memset(p, 0, sizeof(prefix_t)); memcpy(&p->add.sin, a, (mb+7)/8); p->family = AF_INET; p->bitlen = b; p->ref_count = 0; } while(0); return(0); } /* ******************************************* */ static int fill_prefix_v6(prefix_t *prefix, const struct in6_addr *addr, int bits, int maxbits) { if(bits < 0 || bits > maxbits) return -1; memcpy(&prefix->add.sin6, addr, (maxbits + 7) / 8); prefix->family = AF_INET6, prefix->bitlen = bits, prefix->ref_count = 0; return 0; } /* ******************************************* */ u_int16_t ndpi_network_ptree_match(struct ndpi_detection_module_struct *ndpi_str, struct in_addr *pin /* network byte order */) { prefix_t prefix; patricia_node_t *node; /* Make sure all in network byte order otherwise compares wont work */ fill_prefix_v4(&prefix, pin, 32, ((patricia_tree_t*)ndpi_str->protocols_ptree)->maxbits); node = ndpi_patricia_search_best(ndpi_str->protocols_ptree, &prefix); return(node ? node->value.user_value : NDPI_PROTOCOL_UNKNOWN); } /* ******************************************* */ #if 0 static u_int8_t tor_ptree_match(struct ndpi_detection_module_struct *ndpi_str, struct in_addr *pin) { return((ndpi_network_ptree_match(ndpi_str, pin) == NDPI_PROTOCOL_TOR) ? 1 : 0); } #endif /* ******************************************* */ u_int8_t ndpi_is_tor_flow(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; if(packet->tcp != NULL) { if(packet->iph) { if(flow->guessed_host_protocol_id == NDPI_PROTOCOL_TOR) return(1); } } return(0); } /* ******************************************* */ static patricia_node_t* add_to_ptree(patricia_tree_t *tree, int family, void *addr, int bits) { prefix_t prefix; patricia_node_t *node; fill_prefix_v4(&prefix, (struct in_addr*)addr, bits, tree->maxbits); node = ndpi_patricia_lookup(tree, &prefix); return(node); } /* ******************************************* */ /* Load a file containing IPv4 addresses in CIDR format as 'protocol_id' Return: the number of entries loaded or -1 in case of error */ int ndpi_load_ipv4_ptree(struct ndpi_detection_module_struct *ndpi_str, const char *path, u_int16_t protocol_id) { char buffer[128], *line, *addr, *cidr, *saveptr; FILE *fd; int len; u_int num_loaded = 0; fd = fopen(path, "r"); if(fd == NULL) { NDPI_LOG_ERR(ndpi_str, "Unable to open file %s [%s]\n", path, strerror(errno)); return(-1); } while(fd) { line = fgets(buffer, sizeof(buffer), fd); if(line == NULL) break; len = strlen(line); if((len <= 1) || (line[0] == '#')) continue; line[len-1] = '\0'; addr = strtok_r(line, "/", &saveptr); if(addr) { struct in_addr pin; patricia_node_t *node; cidr = strtok_r(NULL, "\n", &saveptr); pin.s_addr = inet_addr(addr); if((node = add_to_ptree(ndpi_str->protocols_ptree, AF_INET, &pin, cidr ? atoi(cidr) : 32 /* bits */)) != NULL) node->value.user_value = protocol_id, num_loaded++; } } fclose(fd); return(num_loaded); } /* ******************************************* */ static void ndpi_init_ptree_ipv4(struct ndpi_detection_module_struct *ndpi_str, void *ptree, ndpi_network host_list[], u_int8_t skip_tor_hosts) { int i; for(i=0; host_list[i].network != 0x0; i++) { struct in_addr pin; patricia_node_t *node; if(skip_tor_hosts && (host_list[i].value == NDPI_PROTOCOL_TOR)) continue; pin.s_addr = htonl(host_list[i].network); if((node = add_to_ptree(ptree, AF_INET, &pin, host_list[i].cidr /* bits */)) != NULL) node->value.user_value = host_list[i].value; } } /* ******************************************* */ static int ndpi_add_host_ip_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *value, int protocol_id) { patricia_node_t *node; struct in_addr pin; int bits = 32; char *ptr = strrchr(value, '/'); if(ptr) { ptr[0] = '\0'; ptr++; if(atoi(ptr)>=0 && atoi(ptr)<=32) bits = atoi(ptr); } inet_pton(AF_INET, value, &pin); if((node = add_to_ptree(ndpi_str->protocols_ptree, AF_INET, &pin, bits)) != NULL) node->value.user_value = protocol_id; return(0); } void set_ndpi_malloc(void* (*__ndpi_malloc)(size_t size)) { _ndpi_malloc = __ndpi_malloc; } void set_ndpi_flow_malloc(void* (*__ndpi_flow_malloc)(size_t size)) { _ndpi_flow_malloc = __ndpi_flow_malloc; } void set_ndpi_free(void (*__ndpi_free)(void *ptr)) { _ndpi_free = __ndpi_free; } void set_ndpi_flow_free(void (*__ndpi_flow_free)(void *ptr)) { _ndpi_flow_free = __ndpi_flow_free; } void ndpi_debug_printf(unsigned int proto, struct ndpi_detection_module_struct *ndpi_str, ndpi_log_level_t log_level, const char *file_name, const char *func_name, int line_number, const char * format, ...) { #ifdef NDPI_ENABLE_DEBUG_MESSAGES va_list args; #define MAX_STR_LEN 250 char str[MAX_STR_LEN]; if(ndpi_str != NULL && log_level > NDPI_LOG_ERROR && proto > 0 && proto < NDPI_MAX_SUPPORTED_PROTOCOLS && !NDPI_ISSET(&ndpi_str->debug_bitmask,proto)) return; va_start(args, format); vsnprintf(str,sizeof(str)-1, format, args); va_end(args); if(ndpi_str != NULL) { printf("%s:%s:%-3d - [%s]: %s", file_name, func_name, line_number, ndpi_get_proto_name(ndpi_str, proto), str); } else { printf("Proto: %u, %s", proto, str); } #endif } void set_ndpi_debug_function(struct ndpi_detection_module_struct *ndpi_str, ndpi_debug_function_ptr ndpi_debug_printf) { #ifdef NDPI_ENABLE_DEBUG_MESSAGES ndpi_str->ndpi_debug_printf = ndpi_debug_printf; #endif } /* ****************************************** */ /* Keep it in order and in sync with ndpi_protocol_category_t in ndpi_typedefs.h */ static const char* categories[] = { "Unspecified", "Media", "VPN", "Email", "DataTransfer", "Web", "SocialNetwork", "Download-FileTransfer-FileSharing", "Game", "Chat", "VoIP", "Database", "RemoteAccess", "Cloud", "Network", "Collaborative", "RPC", "Streaming", "System", "SoftwareUpdate", "", "", "", "", "", "Music", "Video", "Shopping", "Productivity", "FileSharing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Mining", /* 99 */ "Malware", "Advertisement", "Banned_Site", "Site_Unavailable", "Allowed_Site", "Antimalware", }; /* ******************************************************************** */ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs prefs) { struct ndpi_detection_module_struct *ndpi_str = ndpi_malloc(sizeof(struct ndpi_detection_module_struct)); int i; if(ndpi_str == NULL) { #ifdef NDPI_ENABLE_DEBUG_MESSAGES NDPI_LOG_ERR(ndpi_str, "ndpi_init_detection_module initial malloc failed for ndpi_str\n"); #endif /* NDPI_ENABLE_DEBUG_MESSAGES */ return(NULL); } memset(ndpi_str, 0, sizeof(struct ndpi_detection_module_struct)); #ifdef NDPI_ENABLE_DEBUG_MESSAGES set_ndpi_debug_function(ndpi_str, (ndpi_debug_function_ptr)ndpi_debug_printf); #endif /* NDPI_ENABLE_DEBUG_MESSAGES */ if((ndpi_str->protocols_ptree = ndpi_New_Patricia(32 /* IPv4 */)) != NULL) ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, host_protocol_list, prefs & ndpi_dont_load_tor_hosts); NDPI_BITMASK_RESET(ndpi_str->detection_bitmask); #ifdef NDPI_ENABLE_DEBUG_MESSAGES ndpi_str->user_data = NULL; #endif ndpi_str->ticks_per_second = 1000; /* ndpi_str->ticks_per_second */ ndpi_str->tcp_max_retransmission_window_size = NDPI_DEFAULT_MAX_TCP_RETRANSMISSION_WINDOW_SIZE; ndpi_str->directconnect_connection_ip_tick_timeout = NDPI_DIRECTCONNECT_CONNECTION_IP_TICK_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->rtsp_connection_timeout = NDPI_RTSP_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->tvants_connection_timeout = NDPI_TVANTS_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->irc_timeout = NDPI_IRC_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->gnutella_timeout = NDPI_GNUTELLA_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->battlefield_timeout = NDPI_BATTLEFIELD_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->thunder_timeout = NDPI_THUNDER_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->yahoo_detect_http_connections = NDPI_YAHOO_DETECT_HTTP_CONNECTIONS; ndpi_str->yahoo_lan_video_timeout = NDPI_YAHOO_LAN_VIDEO_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->zattoo_connection_timeout = NDPI_ZATTOO_CONNECTION_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->jabber_stun_timeout = NDPI_JABBER_STUN_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->jabber_file_transfer_timeout = NDPI_JABBER_FT_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->soulseek_connection_ip_tick_timeout = NDPI_SOULSEEK_CONNECTION_IP_TICK_TIMEOUT * ndpi_str->ticks_per_second; ndpi_str->ndpi_num_supported_protocols = NDPI_MAX_SUPPORTED_PROTOCOLS; ndpi_str->ndpi_num_custom_protocols = 0; ndpi_str->host_automa.ac_automa = ac_automata_init(ac_match_handler); ndpi_str->content_automa.ac_automa = ac_automata_init(ac_match_handler); ndpi_str->bigrams_automa.ac_automa = ac_automata_init(ac_match_handler); ndpi_str->impossible_bigrams_automa.ac_automa = ac_automata_init(ac_match_handler); if((sizeof(categories)/sizeof(char*)) != NDPI_PROTOCOL_NUM_CATEGORIES) { NDPI_LOG_ERR(ndpi_str, "[NDPI] invalid categories length: expected %u, got %u\n", NDPI_PROTOCOL_NUM_CATEGORIES, (unsigned int)(sizeof(categories)/sizeof(char*))); return(NULL); } #ifdef HAVE_HYPERSCAN ndpi_str->custom_categories.num_to_load = 0, ndpi_str->custom_categories.to_load = NULL; ndpi_str->custom_categories.hostnames = NULL; #else ndpi_str->custom_categories.hostnames.ac_automa = ac_automata_init(ac_match_handler); ndpi_str->custom_categories.hostnames_shadow.ac_automa = ac_automata_init(ac_match_handler); #endif ndpi_str->custom_categories.ipAddresses = ndpi_New_Patricia(32 /* IPv4 */); ndpi_str->custom_categories.ipAddresses_shadow = ndpi_New_Patricia(32 /* IPv4 */); if((ndpi_str->custom_categories.ipAddresses == NULL) || (ndpi_str->custom_categories.ipAddresses_shadow == NULL)) return(NULL); ndpi_init_protocol_defaults(ndpi_str); for(i=0; icustom_category_labels[i], CUSTOM_CATEGORY_LABEL_LEN, "User custom category %u", (unsigned int)(i+1)); return(ndpi_str); } /* *********************************************** */ void ndpi_finalize_initalization(struct ndpi_detection_module_struct *ndpi_str) { u_int i; for(i=0; i<4; i++) { ndpi_automa *automa; switch(i) { case 0: automa = &ndpi_str->host_automa; break; case 1: automa = &ndpi_str->content_automa; break; case 2: automa = &ndpi_str->bigrams_automa; break; case 3: automa = &ndpi_str->impossible_bigrams_automa; break; } ac_automata_finalize((AC_AUTOMATA_t*)automa->ac_automa); automa->ac_automa_finalized = 1; } } /* *********************************************** */ /* Wrappers */ void* ndpi_init_automa(void) { return(ac_automata_init(ac_match_handler)); } int ndpi_add_string_value_to_automa(void *_automa, char *str, unsigned long num) { AC_PATTERN_t ac_pattern; AC_AUTOMATA_t *automa = (AC_AUTOMATA_t*)_automa; if(automa == NULL) return(-1); memset(&ac_pattern, 0, sizeof(ac_pattern)); ac_pattern.astring = str; ac_pattern.rep.number = num; ac_pattern.length = strlen(ac_pattern.astring); return(ac_automata_add(automa, &ac_pattern) == ACERR_SUCCESS ? 0 : -1); } int ndpi_add_string_to_automa(void *_automa, char *str) { return(ndpi_add_string_value_to_automa(_automa, str, 1)); } void ndpi_free_automa(void *_automa) { ac_automata_release((AC_AUTOMATA_t*)_automa, 0); } void ndpi_finalize_automa(void *_automa) { ac_automata_finalize((AC_AUTOMATA_t*)_automa); } /* ****************************************************** */ int ndpi_match_string(void *_automa, char *string_to_match) { AC_REP_t match = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED }; AC_TEXT_t ac_input_text; AC_AUTOMATA_t *automa = (AC_AUTOMATA_t*)_automa; int rc; if((automa == NULL) || (string_to_match == NULL) || (string_to_match[0] == '\0')) return(-2); ac_input_text.astring = string_to_match, ac_input_text.length = strlen(string_to_match); rc = ac_automata_search(automa, &ac_input_text, &match); /* As ac_automata_search can detect partial matches and continue the search process in case rc == 0 (i.e. no match), we need to check if there is a partial match and in this case return it */ if((rc == 0) && (match.number != 0)) rc = 1; return(rc ? match.number : 0); } /* ****************************************************** */ int ndpi_match_string_id(void *_automa, char *string_to_match, u_int match_len, unsigned long *id) { AC_TEXT_t ac_input_text; AC_AUTOMATA_t *automa = (AC_AUTOMATA_t*)_automa; AC_REP_t match = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED }; int rc; *id = -1; if((automa == NULL) || (string_to_match == NULL) || (string_to_match[0] == '\0')) return(-2); ac_input_text.astring = string_to_match, ac_input_text.length = match_len; rc = ac_automata_search(automa, &ac_input_text, &match); /* As ac_automata_search can detect partial matches and continue the search process in case rc == 0 (i.e. no match), we need to check if there is a partial match and in this case return it */ if((rc == 0) && (match.number != 0)) rc = 1; *id = rc ? match.number : NDPI_PROTOCOL_UNKNOWN; return(*id != NDPI_PROTOCOL_UNKNOWN ? 0 : -1); } /* *********************************************** */ #ifdef HAVE_HYPERSCAN static int hyperscanCustomEventHandler(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *ctx) { *((unsigned long *)ctx) = (unsigned long)id; #ifdef DEBUG printf("[HS] Found category %u\n", id); #endif return(HS_SCAN_TERMINATED); } #endif /* *********************************************** */ int ndpi_match_custom_category(struct ndpi_detection_module_struct *ndpi_str, char *name, u_int name_len, unsigned long *id) { #ifdef HAVE_HYPERSCAN if(ndpi_str->custom_categories.hostnames == NULL) return(-1); else { hs_error_t rc; *id = (unsigned long)-1; rc = hs_scan(ndpi_str->custom_categories.hostnames->database, name, name_len, 0, ndpi_str->custom_categories.hostnames->scratch, hyperscanCustomEventHandler, id); if(rc == HS_SCAN_TERMINATED) { #ifdef DEBUG printf("[HS] Found category %lu for %s\n", *id, name); #endif return(0); } else return(-1); } #else return(ndpi_match_string_id(ndpi_str->custom_categories.hostnames.ac_automa, name, name_len, id)); #endif } /* *********************************************** */ int ndpi_get_custom_category_match(struct ndpi_detection_module_struct *ndpi_str, char *name_or_ip, u_int name_len, unsigned long *id) { char ipbuf[64], *ptr; struct in_addr pin; u_int cp_len = ndpi_min(sizeof(ipbuf)-1, name_len); if(!ndpi_str->custom_categories.categories_loaded) return(-1); if(cp_len > 0) { memcpy(ipbuf, name_or_ip, cp_len); ipbuf[cp_len] = '\0'; } else ipbuf[0] = '\0'; ptr = strrchr(ipbuf, '/'); if(ptr) ptr[0] = '\0'; if(inet_pton(AF_INET, ipbuf, &pin) == 1) { /* Search IP */ prefix_t prefix; patricia_node_t *node; /* Make sure all in network byte order otherwise compares wont work */ fill_prefix_v4(&prefix, &pin, 32, ((patricia_tree_t*)ndpi_str->protocols_ptree)->maxbits); node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); if(node) { *id = node->value.user_value; return(0); } return(-1); } else /* Search Host */ return(ndpi_match_custom_category(ndpi_str, name_or_ip, name_len, id)); } /* *********************************************** */ static void free_ptree_data(void *data) { ; } /* ****************************************************** */ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str != NULL) { int i; for(i=0; i<(int)ndpi_str->ndpi_num_supported_protocols; i++) { if(ndpi_str->proto_defaults[i].protoName) ndpi_free(ndpi_str->proto_defaults[i].protoName); } /* NDPI_PROTOCOL_TINC */ if(ndpi_str->tinc_cache) cache_free((cache_t)(ndpi_str->tinc_cache)); if(ndpi_str->ookla_cache) ndpi_lru_free_cache(ndpi_str->ookla_cache); if(ndpi_str->stun_cache) ndpi_lru_free_cache(ndpi_str->stun_cache); if(ndpi_str->protocols_ptree) ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_str->protocols_ptree, free_ptree_data); if(ndpi_str->udpRoot != NULL) ndpi_tdestroy(ndpi_str->udpRoot, ndpi_free); if(ndpi_str->tcpRoot != NULL) ndpi_tdestroy(ndpi_str->tcpRoot, ndpi_free); if(ndpi_str->host_automa.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t*)ndpi_str->host_automa.ac_automa, 1 /* free patterns strings memory */); if(ndpi_str->content_automa.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t*)ndpi_str->content_automa.ac_automa, 0); if(ndpi_str->bigrams_automa.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t*)ndpi_str->bigrams_automa.ac_automa, 0); if(ndpi_str->impossible_bigrams_automa.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t*)ndpi_str->impossible_bigrams_automa.ac_automa, 0); #ifdef HAVE_HYPERSCAN destroy_hyperscan(ndpi_str); while(ndpi_str->custom_categories.to_load != NULL) { struct hs_list *next = ndpi_str->custom_categories.to_load->next; ndpi_free(ndpi_str->custom_categories.to_load->expression); ndpi_free(ndpi_str->custom_categories.to_load); ndpi_str->custom_categories.to_load = next; } free_hyperscan_memory(ndpi_str->custom_categories.hostnames); #else if(ndpi_str->custom_categories.hostnames.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t*)ndpi_str->custom_categories.hostnames.ac_automa, 1 /* free patterns strings memory */); if(ndpi_str->custom_categories.hostnames_shadow.ac_automa != NULL) ac_automata_release((AC_AUTOMATA_t*)ndpi_str->custom_categories.hostnames_shadow.ac_automa, 1 /* free patterns strings memory */); #endif if(ndpi_str->custom_categories.ipAddresses != NULL) ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_str->custom_categories.ipAddresses, free_ptree_data); if(ndpi_str->custom_categories.ipAddresses_shadow != NULL) ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_str->custom_categories.ipAddresses_shadow, free_ptree_data); ndpi_free(ndpi_str); } } /* ****************************************************** */ int ndpi_get_protocol_id_master_proto(struct ndpi_detection_module_struct *ndpi_str, u_int16_t protocol_id, u_int16_t** tcp_master_proto, u_int16_t** udp_master_proto) { if(protocol_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) { *tcp_master_proto = ndpi_str->proto_defaults[NDPI_PROTOCOL_UNKNOWN].master_tcp_protoId, *udp_master_proto = ndpi_str->proto_defaults[NDPI_PROTOCOL_UNKNOWN].master_udp_protoId; return(-1); } *tcp_master_proto = ndpi_str->proto_defaults[protocol_id].master_tcp_protoId, *udp_master_proto = ndpi_str->proto_defaults[protocol_id].master_udp_protoId; return(0); } /* ****************************************************** */ static ndpi_default_ports_tree_node_t* ndpi_get_guessed_protocol_id(struct ndpi_detection_module_struct *ndpi_str, u_int8_t proto, u_int16_t sport, u_int16_t dport) { ndpi_default_ports_tree_node_t node; if(sport && dport) { int low = ndpi_min(sport, dport); int high = ndpi_max(sport, dport); const void *ret; node.default_port = low; /* Check server port first */ ret = ndpi_tfind(&node, (proto == IPPROTO_TCP) ? (void*)&ndpi_str->tcpRoot : (void*)&ndpi_str->udpRoot, ndpi_default_ports_tree_node_t_cmp); if(ret == NULL) { node.default_port = high; ret = ndpi_tfind(&node, (proto == IPPROTO_TCP) ? (void*)&ndpi_str->tcpRoot : (void*)&ndpi_str->udpRoot, ndpi_default_ports_tree_node_t_cmp); } if(ret) return(*(ndpi_default_ports_tree_node_t**)ret); } return(NULL); } /* ****************************************************** */ /* These are UDP protocols that must fit a single packet and thus that if have NOT been detected they cannot be guessed as they have been excluded */ u_int8_t is_udp_guessable_protocol(u_int16_t l7_guessed_proto) { switch(l7_guessed_proto) { case NDPI_PROTOCOL_QUIC: case NDPI_PROTOCOL_SNMP: case NDPI_PROTOCOL_NETFLOW: /* TODO: add more protocols (if any missing) */ return(1); } return(0); } /* ****************************************************** */ u_int16_t ndpi_guess_protocol_id(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int8_t proto, u_int16_t sport, u_int16_t dport, u_int8_t *user_defined_proto) { *user_defined_proto = 0; /* Default */ if(sport && dport) { ndpi_default_ports_tree_node_t *found = ndpi_get_guessed_protocol_id(ndpi_str, proto, sport, dport); if(found != NULL) { u_int16_t guessed_proto = found->proto->protoId; /* We need to check if the guessed protocol isn't excluded by nDPI */ if(flow && (proto == IPPROTO_UDP) && NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, guessed_proto) && is_udp_guessable_protocol(guessed_proto) ) return(NDPI_PROTOCOL_UNKNOWN); else { *user_defined_proto = found->customUserProto; return(guessed_proto); } } } else { /* No TCP/UDP */ switch(proto) { case NDPI_IPSEC_PROTOCOL_ESP: case NDPI_IPSEC_PROTOCOL_AH: return(NDPI_PROTOCOL_IP_IPSEC); break; case NDPI_GRE_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_GRE); break; case NDPI_ICMP_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_ICMP); break; case NDPI_IGMP_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_IGMP); break; case NDPI_EGP_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_EGP); break; case NDPI_SCTP_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_SCTP); break; case NDPI_OSPF_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_OSPF); break; case NDPI_IPIP_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_IP_IN_IP); break; case NDPI_ICMPV6_PROTOCOL_TYPE: return(NDPI_PROTOCOL_IP_ICMPV6); break; case 112: return(NDPI_PROTOCOL_IP_VRRP); break; } } return(NDPI_PROTOCOL_UNKNOWN); } /* ******************************************************************** */ u_int ndpi_get_num_supported_protocols(struct ndpi_detection_module_struct *ndpi_str) { return(ndpi_str->ndpi_num_supported_protocols); } /* ******************************************************************** */ #ifdef WIN32 char * strsep(char **sp, char *sep) { char *p, *s; if(sp == NULL || *sp == NULL || **sp == '\0') return(NULL); s = *sp; p = s + strcspn(s, sep); if(*p != '\0') *p++ = '\0'; *sp = p; return(s); } #endif /* ******************************************************************** */ int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, char* rule, u_int8_t do_add) { char *at, *proto, *elem; ndpi_proto_defaults_t *def; int subprotocol_id, i; at = strrchr(rule, '@'); if(at == NULL) { NDPI_LOG_ERR(ndpi_str, "Invalid rule '%s'\n", rule); return(-1); } else at[0] = 0, proto = &at[1]; for(i=0; proto[i] != '\0'; i++) { switch(proto[i]) { case '/': case '&': case '^': case ':': case ';': case '\'': case '"': case ' ': proto[i] = '_'; break; } } for(i=0, def = NULL; i<(int)ndpi_str->ndpi_num_supported_protocols; i++) { if(ndpi_str->proto_defaults[i].protoName && strcasecmp(ndpi_str->proto_defaults[i].protoName, proto) == 0) { def = &ndpi_str->proto_defaults[i]; subprotocol_id = i; break; } } if(def == NULL) { if(!do_add) { /* We need to remove a rule */ NDPI_LOG_ERR(ndpi_str, "Unable to find protocol '%s': skipping rule '%s'\n", proto, rule); return(-3); } else { ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS]; u_int16_t no_master[2] = { NDPI_PROTOCOL_NO_MASTER_PROTO, NDPI_PROTOCOL_NO_MASTER_PROTO }; if(ndpi_str->ndpi_num_custom_protocols >= (NDPI_MAX_NUM_CUSTOM_PROTOCOLS-1)) { NDPI_LOG_ERR(ndpi_str, "Too many protocols defined (%u): skipping protocol %s\n", ndpi_str->ndpi_num_custom_protocols, proto); return(-2); } ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, ndpi_str->ndpi_num_supported_protocols, 0 /* can_have_a_subprotocol */, no_master, no_master, proto, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, /* TODO add protocol category support in rules */ ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); def = &ndpi_str->proto_defaults[ndpi_str->ndpi_num_supported_protocols]; subprotocol_id = ndpi_str->ndpi_num_supported_protocols; ndpi_str->ndpi_num_supported_protocols++, ndpi_str->ndpi_num_custom_protocols++; } } while((elem = strsep(&rule, ",")) != NULL) { char *attr = elem, *value = NULL; ndpi_port_range range; int is_tcp = 0, is_udp = 0, is_ip = 0; if(strncmp(attr, "tcp:", 4) == 0) is_tcp = 1, value = &attr[4]; else if(strncmp(attr, "udp:", 4) == 0) is_udp = 1, value = &attr[4]; else if(strncmp(attr, "ip:", 3) == 0) is_ip = 1, value = &attr[3]; else if(strncmp(attr, "host:", 5) == 0) { /* host:"",host:"",.....@ */ value = &attr[5]; if(value[0] == '"') value++; /* remove leading " */ if(value[strlen(value)-1] == '"') value[strlen(value)-1] = '\0'; /* remove trailing " */ } if(is_tcp || is_udp) { u_int p_low, p_high; if(sscanf(value, "%u-%u", &p_low, &p_high) == 2) range.port_low = p_low, range.port_high = p_high; else range.port_low = range.port_high = atoi(&elem[4]); if(do_add) addDefaultPort(ndpi_str, &range, def, 1 /* Custom user proto */, is_tcp ? &ndpi_str->tcpRoot : &ndpi_str->udpRoot, __FUNCTION__,__LINE__); else removeDefaultPort(&range, def, is_tcp ? &ndpi_str->tcpRoot : &ndpi_str->udpRoot); } else if(is_ip) { /* NDPI_PROTOCOL_TOR */ ndpi_add_host_ip_subprotocol(ndpi_str, value, subprotocol_id); } else { if(do_add) ndpi_add_host_url_subprotocol(ndpi_str, value, subprotocol_id, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_ACCEPTABLE); else ndpi_remove_host_url_subprotocol(ndpi_str, value, subprotocol_id); } } return(0); } /* ******************************************************************** */ /* * Format: * * * * Notes: * - host and category are separated by a single TAB * - empty lines or lines starting with # are ignored */ int ndpi_load_categories_file(struct ndpi_detection_module_struct *ndpi_str, const char* path) { char buffer[512], *line, *name, *category, *saveptr; FILE *fd; int len; fd = fopen(path, "r"); if(fd == NULL) { NDPI_LOG_ERR(ndpi_str, "Unable to open file %s [%s]\n", path, strerror(errno)); return(-1); } while(fd) { line = fgets(buffer, sizeof(buffer), fd); if(line == NULL) break; len = strlen(line); if((len <= 1) || (line[0] == '#')) continue; line[len-1] = '\0'; name = strtok_r(line, "\t", &saveptr); if(name) { category = strtok_r(NULL, "\t", &saveptr); if(category) ndpi_load_category(ndpi_str, name, (ndpi_protocol_category_t) atoi(category)); } } fclose(fd); ndpi_enable_loaded_categories(ndpi_str); return(0); } /* ******************************************************************** */ /* Format: :,:,.....@ Subprotocols Format: host:"",host:"",.....@ IP based Subprotocols Format ( is IP or CIDR): ip:,ip:,.....@ Example: tcp:80,tcp:3128@HTTP udp:139@NETBIOS */ int ndpi_load_protocols_file(struct ndpi_detection_module_struct *ndpi_str, const char* path) { FILE *fd; char *buffer, *old_buffer; int chunk_len = 512, buffer_len = chunk_len, old_buffer_len; int i, rc = -1; fd = fopen(path, "r"); if(fd == NULL) { NDPI_LOG_ERR(ndpi_str, "Unable to open file %s [%s]\n", path, strerror(errno)); goto error; } buffer = ndpi_malloc(buffer_len); if(buffer == NULL) { NDPI_LOG_ERR(ndpi_str, "Memory allocation failure\n"); goto close_fd; } while(1) { char *line = buffer; int line_len = buffer_len; while((line = fgets(line, line_len, fd)) != NULL && line[strlen(line)-1] != '\n') { i = strlen(line); old_buffer = buffer; old_buffer_len = buffer_len; buffer_len += chunk_len; buffer = ndpi_realloc(old_buffer, old_buffer_len, buffer_len); if(buffer == NULL) { NDPI_LOG_ERR(ndpi_str, "Memory allocation failure\n"); ndpi_free(old_buffer); goto close_fd; } line = &buffer[i]; line_len = chunk_len; } if(!line) /* safety check */ break; i = strlen(buffer); if((i <= 1) || (buffer[0] == '#')) continue; else buffer[i-1] = '\0'; ndpi_handle_rule(ndpi_str, buffer, 1); } rc = 0; ndpi_free(buffer); close_fd: fclose(fd); error: return(rc); } /* ******************************************************************** */ /* ntop */ void ndpi_set_bitmask_protocol_detection(char * label, struct ndpi_detection_module_struct *ndpi_str, const NDPI_PROTOCOL_BITMASK * detection_bitmask, const u_int32_t idx, u_int16_t ndpi_protocol_id, void (*func) (struct ndpi_detection_module_struct *, struct ndpi_flow_struct *flow), const NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_bitmask, u_int8_t b_save_bitmask_unknow, u_int8_t b_add_detection_bitmask) { /* Compare specify protocol bitmask with main detection bitmask */ if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(*detection_bitmask, ndpi_protocol_id) != 0) { #ifdef DEBUG NDPI_LOG_DBG2(ndpi_str "[NDPI] ndpi_set_bitmask_protocol_detection: %s : [callback_buffer] idx= %u, [proto_defaults] protocol_id=%u\n", label, idx, ndpi_protocol_id); #endif if(ndpi_str->proto_defaults[ndpi_protocol_id].protoIdx != 0) { NDPI_LOG_DBG2(ndpi_str, "[NDPI] Internal error: protocol %s/%u has been already registered\n", label, ndpi_protocol_id); #ifdef DEBUG } else { NDPI_LOG_DBG2(ndpi_str, "[NDPI] Adding %s with protocol id %d\n", label, ndpi_protocol_id); #endif } /* Set function and index protocol within proto_default structure for port protocol detection and callback_buffer function for DPI protocol detection */ ndpi_str->proto_defaults[ndpi_protocol_id].protoIdx = idx; ndpi_str->proto_defaults[ndpi_protocol_id].func = ndpi_str->callback_buffer[idx].func = func; /* Set ndpi_selection_bitmask for protocol */ ndpi_str->callback_buffer[idx].ndpi_selection_bitmask = ndpi_selection_bitmask; /* Reset protocol detection bitmask via NDPI_PROTOCOL_UNKNOWN and than add specify protocol bitmast to callback buffer. */ if(b_save_bitmask_unknow) NDPI_SAVE_AS_BITMASK(ndpi_str->callback_buffer[idx].detection_bitmask, NDPI_PROTOCOL_UNKNOWN); if(b_add_detection_bitmask) NDPI_ADD_PROTOCOL_TO_BITMASK(ndpi_str->callback_buffer[idx].detection_bitmask, ndpi_protocol_id); NDPI_SAVE_AS_BITMASK(ndpi_str->callback_buffer[idx].excluded_protocol_bitmask, ndpi_protocol_id); } } /* ******************************************************************** */ void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_str, const NDPI_PROTOCOL_BITMASK * dbm) { NDPI_PROTOCOL_BITMASK detection_bitmask_local; NDPI_PROTOCOL_BITMASK *detection_bitmask = &detection_bitmask_local; u_int32_t a = 0; NDPI_BITMASK_SET(detection_bitmask_local, *dbm); NDPI_BITMASK_SET(ndpi_str->detection_bitmask, *dbm); /* set this here to zero to be interrupt safe */ ndpi_str->callback_buffer_size = 0; /* HTTP */ init_http_dissector(ndpi_str, &a, detection_bitmask); /* STARCRAFT */ init_starcraft_dissector(ndpi_str, &a, detection_bitmask); /* TLS */ init_tls_dissector(ndpi_str, &a, detection_bitmask); /* STUN */ init_stun_dissector(ndpi_str, &a, detection_bitmask); /* RTP */ init_rtp_dissector(ndpi_str, &a, detection_bitmask); /* RTSP */ init_rtsp_dissector(ndpi_str, &a, detection_bitmask); /* RDP */ init_rdp_dissector(ndpi_str, &a, detection_bitmask); /* SIP */ init_sip_dissector(ndpi_str, &a, detection_bitmask); /* IMO */ init_imo_dissector(ndpi_str, &a, detection_bitmask); /* Teredo */ init_teredo_dissector(ndpi_str, &a, detection_bitmask); /* EDONKEY */ init_edonkey_dissector(ndpi_str, &a, detection_bitmask); /* FASTTRACK */ init_fasttrack_dissector(ndpi_str, &a, detection_bitmask); /* GNUTELLA */ init_gnutella_dissector(ndpi_str, &a, detection_bitmask); /* DIRECTCONNECT */ init_directconnect_dissector(ndpi_str, &a, detection_bitmask); /* MSN */ init_msn_dissector(ndpi_str, &a, detection_bitmask); /* YAHOO */ init_yahoo_dissector(ndpi_str, &a, detection_bitmask); /* OSCAR */ init_oscar_dissector(ndpi_str, &a, detection_bitmask); /* APPLEJUICE */ init_applejuice_dissector(ndpi_str, &a, detection_bitmask); /* SOULSEEK */ init_soulseek_dissector(ndpi_str, &a, detection_bitmask); /* SOCKS */ init_socks_dissector(ndpi_str, &a, detection_bitmask); /* IRC */ init_irc_dissector(ndpi_str, &a, detection_bitmask); /* JABBER */ init_jabber_dissector(ndpi_str, &a, detection_bitmask); /* MAIL_POP */ init_mail_pop_dissector(ndpi_str, &a, detection_bitmask); /* MAIL_IMAP */ init_mail_imap_dissector(ndpi_str, &a, detection_bitmask); /* MAIL_SMTP */ init_mail_smtp_dissector(ndpi_str, &a, detection_bitmask); /* USENET */ init_usenet_dissector(ndpi_str, &a, detection_bitmask); /* DNS */ init_dns_dissector(ndpi_str, &a, detection_bitmask); /* FILETOPIA */ init_fbzero_dissector(ndpi_str, &a, detection_bitmask); /* VMWARE */ init_vmware_dissector(ndpi_str, &a, detection_bitmask); /* NON_TCP_UDP */ init_non_tcp_udp_dissector(ndpi_str, &a, detection_bitmask); /* TVANTS */ init_tvants_dissector(ndpi_str, &a, detection_bitmask); /* SOPCAST */ init_sopcast_dissector(ndpi_str, &a, detection_bitmask); /* TVUPLAYER */ init_tvuplayer_dissector(ndpi_str, &a, detection_bitmask); /* PPSTREAM */ init_ppstream_dissector(ndpi_str, &a, detection_bitmask); /* PPLIVE */ init_pplive_dissector(ndpi_str, &a, detection_bitmask); /* IAX */ init_iax_dissector(ndpi_str, &a, detection_bitmask); /* MGPC */ init_mgpc_dissector(ndpi_str, &a, detection_bitmask); /* ZATTOO */ init_zattoo_dissector(ndpi_str, &a, detection_bitmask); /* QQ */ init_qq_dissector(ndpi_str, &a, detection_bitmask); /* SSH */ init_ssh_dissector(ndpi_str, &a, detection_bitmask); /* AYIYA */ init_ayiya_dissector(ndpi_str, &a, detection_bitmask); /* THUNDER */ init_thunder_dissector(ndpi_str, &a, detection_bitmask); /* VNC */ init_vnc_dissector(ndpi_str, &a, detection_bitmask); /* LINE */ init_line_dissector(ndpi_str, &a, detection_bitmask); /* TEAMVIEWER */ init_teamviewer_dissector(ndpi_str, &a, detection_bitmask); /* DHCP */ init_dhcp_dissector(ndpi_str, &a, detection_bitmask); /* STEAM */ init_steam_dissector(ndpi_str, &a, detection_bitmask); /* HALFLIFE2 */ init_halflife2_dissector(ndpi_str, &a, detection_bitmask); /* XBOX */ init_xbox_dissector(ndpi_str, &a, detection_bitmask); /* HTTP_APPLICATION_ACTIVESYNC */ init_http_activesync_dissector(ndpi_str, &a, detection_bitmask); /* SMB */ init_smb_dissector(ndpi_str, &a, detection_bitmask); /* MINING */ init_mining_dissector(ndpi_str, &a, detection_bitmask); /* TELNET */ init_telnet_dissector(ndpi_str, &a, detection_bitmask); /* NTP */ init_ntp_dissector(ndpi_str, &a, detection_bitmask); /* NFS */ init_nfs_dissector(ndpi_str, &a, detection_bitmask); /* SSDP */ init_ssdp_dissector(ndpi_str, &a, detection_bitmask); /* WORLD_OF_WARCRAFT */ init_world_of_warcraft_dissector(ndpi_str, &a, detection_bitmask); /* POSTGRES */ init_postgres_dissector(ndpi_str, &a, detection_bitmask); /* MYSQL */ init_mysql_dissector(ndpi_str, &a, detection_bitmask); /* BGP */ init_bgp_dissector(ndpi_str, &a, detection_bitmask); /* BATTLEFIELD */ init_battlefield_dissector(ndpi_str, &a, detection_bitmask); /* PCANYWHERE */ init_pcanywhere_dissector(ndpi_str, &a, detection_bitmask); /* SNMP */ init_snmp_dissector(ndpi_str, &a, detection_bitmask); /* KONTIKI */ init_kontiki_dissector(ndpi_str, &a, detection_bitmask); /* ICECAST */ init_icecast_dissector(ndpi_str, &a, detection_bitmask); /* SHOUTCAST */ init_shoutcast_dissector(ndpi_str, &a, detection_bitmask); /* KERBEROS */ init_kerberos_dissector(ndpi_str, &a, detection_bitmask); /* OPENFT */ init_openft_dissector(ndpi_str, &a, detection_bitmask); /* SYSLOG */ init_syslog_dissector(ndpi_str, &a, detection_bitmask); /* DIRECT_DOWNLOAD_LINK */ init_directdownloadlink_dissector(ndpi_str, &a, detection_bitmask); /* NETBIOS */ init_netbios_dissector(ndpi_str, &a, detection_bitmask); /* MDNS */ init_mdns_dissector(ndpi_str, &a, detection_bitmask); /* IPP */ init_ipp_dissector(ndpi_str, &a, detection_bitmask); /* LDAP */ init_ldap_dissector(ndpi_str, &a, detection_bitmask); /* WARCRAFT3 */ init_warcraft3_dissector(ndpi_str, &a, detection_bitmask); /* XDMCP */ init_xdmcp_dissector(ndpi_str, &a, detection_bitmask); /* TFTP */ init_tftp_dissector(ndpi_str, &a, detection_bitmask); /* MSSQL_TDS */ init_mssql_tds_dissector(ndpi_str, &a, detection_bitmask); /* PPTP */ init_pptp_dissector(ndpi_str, &a, detection_bitmask); /* STEALTHNET */ init_stealthnet_dissector(ndpi_str, &a, detection_bitmask); /* DHCPV6 */ init_dhcpv6_dissector(ndpi_str, &a, detection_bitmask); /* AFP */ init_afp_dissector(ndpi_str, &a, detection_bitmask); /* check_mk */ init_checkmk_dissector(ndpi_str, &a, detection_bitmask); /* AIMINI */ init_aimini_dissector(ndpi_str, &a, detection_bitmask); /* FLORENSIA */ init_florensia_dissector(ndpi_str, &a, detection_bitmask); /* MAPLESTORY */ init_maplestory_dissector(ndpi_str, &a, detection_bitmask); /* DOFUS */ init_dofus_dissector(ndpi_str, &a, detection_bitmask); /* WORLD_OF_KUNG_FU */ init_world_of_kung_fu_dissector(ndpi_str, &a, detection_bitmask); /* FIESTA */ init_fiesta_dissector(ndpi_str, &a, detection_bitmask); /* CROSSIFIRE */ init_crossfire_dissector(ndpi_str, &a, detection_bitmask); /* GUILDWARS */ init_guildwars_dissector(ndpi_str, &a, detection_bitmask); /* ARMAGETRON */ init_armagetron_dissector(ndpi_str, &a, detection_bitmask); /* DROPBOX */ init_dropbox_dissector(ndpi_str, &a, detection_bitmask); /* SPOTIFY */ init_spotify_dissector(ndpi_str, &a, detection_bitmask); /* RADIUS */ init_radius_dissector(ndpi_str, &a, detection_bitmask); /* CITRIX */ init_citrix_dissector(ndpi_str, &a, detection_bitmask); /* LOTUS_NOTES */ init_lotus_notes_dissector(ndpi_str, &a, detection_bitmask); /* GTP */ init_gtp_dissector(ndpi_str, &a, detection_bitmask); /* DCERPC */ init_dcerpc_dissector(ndpi_str, &a, detection_bitmask); /* NETFLOW */ init_netflow_dissector(ndpi_str, &a, detection_bitmask); /* SFLOW */ init_sflow_dissector(ndpi_str, &a, detection_bitmask); /* H323 */ init_h323_dissector(ndpi_str, &a, detection_bitmask); /* OPENVPN */ init_openvpn_dissector(ndpi_str, &a, detection_bitmask); /* NOE */ init_noe_dissector(ndpi_str, &a, detection_bitmask); /* CISCOVPN */ init_ciscovpn_dissector(ndpi_str, &a, detection_bitmask); /* TEAMSPEAK */ init_teamspeak_dissector(ndpi_str, &a, detection_bitmask); /* TOR */ init_tor_dissector(ndpi_str, &a, detection_bitmask); /* SKINNY */ init_skinny_dissector(ndpi_str, &a, detection_bitmask); /* RTCP */ init_rtcp_dissector(ndpi_str, &a, detection_bitmask); /* RSYNC */ init_rsync_dissector(ndpi_str, &a, detection_bitmask); /* WHOIS_DAS */ init_whois_das_dissector(ndpi_str, &a, detection_bitmask); /* ORACLE */ init_oracle_dissector(ndpi_str, &a, detection_bitmask); /* CORBA */ init_corba_dissector(ndpi_str, &a, detection_bitmask); /* RTMP */ init_rtmp_dissector(ndpi_str, &a, detection_bitmask); /* FTP_CONTROL */ init_ftp_control_dissector(ndpi_str, &a, detection_bitmask); /* FTP_DATA */ init_ftp_data_dissector(ndpi_str, &a, detection_bitmask); /* PANDO */ init_pando_dissector(ndpi_str, &a, detection_bitmask); /* MEGACO */ init_megaco_dissector(ndpi_str, &a, detection_bitmask); /* REDIS */ init_redis_dissector(ndpi_str, &a, detection_bitmask); /* UPnP */ init_upnp_dissector(ndpi_str, &a, detection_bitmask); /* VHUA */ init_vhua_dissector(ndpi_str, &a, detection_bitmask); /* ZMQ */ init_zmq_dissector(ndpi_str, &a, detection_bitmask); /* TELEGRAM */ init_telegram_dissector(ndpi_str, &a, detection_bitmask); /* QUIC */ init_quic_dissector(ndpi_str, &a, detection_bitmask); /* DIAMETER */ init_diameter_dissector(ndpi_str, &a, detection_bitmask); /* APPLE_PUSH */ init_apple_push_dissector(ndpi_str, &a, detection_bitmask); /* EAQ */ init_eaq_dissector(ndpi_str, &a, detection_bitmask); /* KAKAOTALK_VOICE */ init_kakaotalk_voice_dissector(ndpi_str, &a, detection_bitmask); /* MPEGTS */ init_mpegts_dissector(ndpi_str, &a, detection_bitmask); /* UBNTAC2 */ init_ubntac2_dissector(ndpi_str, &a, detection_bitmask); /* COAP */ init_coap_dissector(ndpi_str, &a, detection_bitmask); /* MQTT */ init_mqtt_dissector(ndpi_str, &a, detection_bitmask); /* SOME/IP */ init_someip_dissector(ndpi_str, &a, detection_bitmask); /* RX */ init_rx_dissector(ndpi_str, &a, detection_bitmask); /* GIT */ init_git_dissector(ndpi_str, &a, detection_bitmask); /* HANGOUT */ init_hangout_dissector(ndpi_str, &a, detection_bitmask); /* DRDA */ init_drda_dissector(ndpi_str, &a, detection_bitmask); /* BJNP */ init_bjnp_dissector(ndpi_str, &a, detection_bitmask); /* SMPP */ init_smpp_dissector(ndpi_str, &a, detection_bitmask); /* TINC */ init_tinc_dissector(ndpi_str, &a, detection_bitmask); /* FIX */ init_fix_dissector(ndpi_str, &a, detection_bitmask); /* NINTENDO */ init_nintendo_dissector(ndpi_str, &a, detection_bitmask); /* MODBUS */ init_modbus_dissector(ndpi_str, &a, detection_bitmask); /* CAPWAP */ init_capwap_dissector(ndpi_str, &a, detection_bitmask); /* ZABBIX */ init_zabbix_dissector(ndpi_str, &a, detection_bitmask); /*** Put false-positive sensitive protocols at the end ***/ /* VIBER */ init_viber_dissector(ndpi_str, &a, detection_bitmask); /* SKYPE */ init_skype_dissector(ndpi_str, &a, detection_bitmask); /* BITTORRENT */ init_bittorrent_dissector(ndpi_str, &a, detection_bitmask); /* WHATSAPP */ init_whatsapp_dissector(ndpi_str, &a, detection_bitmask); /* OOKLA */ init_ookla_dissector(ndpi_str, &a, detection_bitmask); /* AMQP */ init_amqp_dissector(ndpi_str, &a, detection_bitmask); /* CSGO */ init_csgo_dissector(ndpi_str, &a, detection_bitmask); /* LISP */ init_lisp_dissector(ndpi_str, &a, detection_bitmask); /* AJP */ init_ajp_dissector(ndpi_str, &a, detection_bitmask); /* Memcached */ init_memcached_dissector(ndpi_str, &a, detection_bitmask); /* Nest Log Sink */ init_nest_log_sink_dissector(ndpi_str, &a, detection_bitmask); /* WireGuard VPN */ init_wireguard_dissector(ndpi_str, &a, detection_bitmask); /* Amazon_Video */ init_amazon_video_dissector(ndpi_str, &a, detection_bitmask); /* Targus Getdata */ init_targus_getdata_dissector(ndpi_str, &a, detection_bitmask); #ifdef CUSTOM_NDPI_PROTOCOLS #include "../../../nDPI-custom/custom_ndpi_main_init.c" #endif /* ----------------------------------------------------------------- */ ndpi_str->callback_buffer_size = a; NDPI_LOG_DBG2(ndpi_str, "callback_buffer_size is %u\n", ndpi_str->callback_buffer_size); /* now build the specific buffer for tcp, udp and non_tcp_udp */ ndpi_str->callback_buffer_size_tcp_payload = 0; ndpi_str->callback_buffer_size_tcp_no_payload = 0; for(a = 0; a < ndpi_str->callback_buffer_size; a++) { if((ndpi_str->callback_buffer[a].ndpi_selection_bitmask & (NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC)) != 0) { if(_ndpi_debug_callbacks) NDPI_LOG_DBG2(ndpi_str, "callback_buffer_tcp_payload, adding buffer %u as entry %u\n", a, ndpi_str->callback_buffer_size_tcp_payload); memcpy(&ndpi_str->callback_buffer_tcp_payload[ndpi_str->callback_buffer_size_tcp_payload], &ndpi_str->callback_buffer[a], sizeof(struct ndpi_call_function_struct)); ndpi_str->callback_buffer_size_tcp_payload++; if((ndpi_str-> callback_buffer[a].ndpi_selection_bitmask & NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD) == 0) { if(_ndpi_debug_callbacks) NDPI_LOG_DBG2(ndpi_str, "\tcallback_buffer_tcp_no_payload, additional adding buffer %u to no_payload process\n", a); memcpy(&ndpi_str->callback_buffer_tcp_no_payload [ndpi_str->callback_buffer_size_tcp_no_payload], &ndpi_str->callback_buffer[a], sizeof(struct ndpi_call_function_struct)); ndpi_str->callback_buffer_size_tcp_no_payload++; } } } ndpi_str->callback_buffer_size_udp = 0; for(a = 0; a < ndpi_str->callback_buffer_size; a++) { if((ndpi_str->callback_buffer[a].ndpi_selection_bitmask & (NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC)) != 0) { if(_ndpi_debug_callbacks) NDPI_LOG_DBG2(ndpi_str, "callback_buffer_size_udp: adding buffer : %u as entry %u\n", a, ndpi_str->callback_buffer_size_udp); memcpy(&ndpi_str->callback_buffer_udp[ndpi_str->callback_buffer_size_udp], &ndpi_str->callback_buffer[a], sizeof(struct ndpi_call_function_struct)); ndpi_str->callback_buffer_size_udp++; } } ndpi_str->callback_buffer_size_non_tcp_udp = 0; for(a = 0; a < ndpi_str->callback_buffer_size; a++) { if((ndpi_str->callback_buffer[a].ndpi_selection_bitmask & (NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP)) == 0 || (ndpi_str-> callback_buffer[a].ndpi_selection_bitmask & NDPI_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC) != 0) { if(_ndpi_debug_callbacks) NDPI_LOG_DBG2(ndpi_str, "callback_buffer_non_tcp_udp: adding buffer : %u as entry %u\n", a, ndpi_str->callback_buffer_size_non_tcp_udp); memcpy(&ndpi_str->callback_buffer_non_tcp_udp[ndpi_str->callback_buffer_size_non_tcp_udp], &ndpi_str->callback_buffer[a], sizeof(struct ndpi_call_function_struct)); ndpi_str->callback_buffer_size_non_tcp_udp++; } } } #ifdef NDPI_DETECTION_SUPPORT_IPV6 /* handle extension headers in IPv6 packets * arguments: * l4ptr: pointer to the byte following the initial IPv6 header * l4len: the length of the IPv6 packet excluding the IPv6 header * nxt_hdr: next header value from the IPv6 header * result: * l4ptr: pointer to the start of the actual packet payload * l4len: length of the actual payload * nxt_hdr: protocol of the actual payload * returns 0 upon success and 1 upon failure */ static int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi_str, const u_int8_t ** l4ptr, u_int16_t * l4len, u_int8_t * nxt_hdr) { while((*nxt_hdr == 0 || *nxt_hdr == 43 || *nxt_hdr == 44 || *nxt_hdr == 60 || *nxt_hdr == 135 || *nxt_hdr == 59)) { u_int16_t ehdr_len; // no next header if(*nxt_hdr == 59) { return(1); } // fragment extension header has fixed size of 8 bytes and the first byte is the next header type if(*nxt_hdr == 44) { if(*l4len < 8) { return(1); } *nxt_hdr = (*l4ptr)[0]; *l4len -= 8; (*l4ptr) += 8; continue; } // the other extension headers have one byte for the next header type // and one byte for the extension header length in 8 byte steps minus the first 8 bytes if (*l4len < 2) { return(1); } ehdr_len = (*l4ptr)[1]; ehdr_len *= 8; ehdr_len += 8; if(*l4len < ehdr_len) { return(1); } *nxt_hdr = (*l4ptr)[0]; *l4len -= ehdr_len; (*l4ptr) += ehdr_len; } return(0); } #endif /* NDPI_DETECTION_SUPPORT_IPV6 */ static u_int8_t ndpi_iph_is_valid_and_not_fragmented(const struct ndpi_iphdr *iph, const u_int16_t ipsize) { //#ifdef REQUIRE_FULL_PACKETS if(ipsize < iph->ihl * 4 || ipsize < ntohs(iph->tot_len) || ntohs(iph->tot_len) < iph->ihl * 4 || (iph->frag_off & htons(0x1FFF)) != 0) { return(0); } //#endif return(1); } static u_int8_t ndpi_detection_get_l4_internal(struct ndpi_detection_module_struct *ndpi_str, const u_int8_t * l3, u_int16_t l3_len, const u_int8_t ** l4_return, u_int16_t * l4_len_return, u_int8_t * l4_protocol_return, u_int32_t flags) { const struct ndpi_iphdr *iph = NULL; #ifdef NDPI_DETECTION_SUPPORT_IPV6 const struct ndpi_ipv6hdr *iph_v6 = NULL; #endif u_int16_t l4len = 0; const u_int8_t *l4ptr = NULL; u_int8_t l4protocol = 0; if(l3 == NULL || l3_len < sizeof(struct ndpi_iphdr)) return(1); iph = (const struct ndpi_iphdr *) l3; if(iph->version == IPVERSION && iph->ihl >= 5) { NDPI_LOG_DBG2(ndpi_str, "ipv4 header\n"); } #ifdef NDPI_DETECTION_SUPPORT_IPV6 else if(iph->version == 6 && l3_len >= sizeof(struct ndpi_ipv6hdr)) { NDPI_LOG_DBG2(ndpi_str, "ipv6 header\n"); iph_v6 = (const struct ndpi_ipv6hdr *) l3; iph = NULL; } #endif else { return(1); } if((flags & NDPI_DETECTION_ONLY_IPV6) && iph != NULL) { NDPI_LOG_DBG2(ndpi_str, "ipv4 header found but excluded by flag\n"); return(1); } #ifdef NDPI_DETECTION_SUPPORT_IPV6 else if((flags & NDPI_DETECTION_ONLY_IPV4) && iph_v6 != NULL) { NDPI_LOG_DBG2(ndpi_str, "ipv6 header found but excluded by flag\n"); return(1); } #endif if(iph != NULL && ndpi_iph_is_valid_and_not_fragmented(iph, l3_len)) { u_int16_t len = ntohs(iph->tot_len); u_int16_t hlen = (iph->ihl * 4); l4ptr = (((const u_int8_t *) iph) + iph->ihl * 4); if(len == 0) len = l3_len; l4len = (len > hlen) ? (len - hlen) : 0; l4protocol = iph->protocol; } #ifdef NDPI_DETECTION_SUPPORT_IPV6 else if(iph_v6 != NULL && (l3_len - sizeof(struct ndpi_ipv6hdr)) >= ntohs(iph_v6->ip6_hdr.ip6_un1_plen)) { l4ptr = (((const u_int8_t *) iph_v6) + sizeof(struct ndpi_ipv6hdr)); l4len = ntohs(iph_v6->ip6_hdr.ip6_un1_plen); l4protocol = iph_v6->ip6_hdr.ip6_un1_nxt; // we need to handle IPv6 extension headers if present if(ndpi_handle_ipv6_extension_headers(ndpi_str, &l4ptr, &l4len, &l4protocol) != 0) { return(1); } } #endif else { return(1); } if(l4_return != NULL) { *l4_return = l4ptr; } if(l4_len_return != NULL) { *l4_len_return = l4len; } if(l4_protocol_return != NULL) { *l4_protocol_return = l4protocol; } return(0); } void ndpi_apply_flow_protocol_to_packet(struct ndpi_flow_struct *flow, struct ndpi_packet_struct *packet) { memcpy(&packet->detected_protocol_stack, &flow->detected_protocol_stack, sizeof(packet->detected_protocol_stack)); memcpy(&packet->protocol_stack_info, &flow->protocol_stack_info, sizeof(packet->protocol_stack_info)); } static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, unsigned short packetlen) { const struct ndpi_iphdr *decaps_iph = NULL; u_int16_t l3len; u_int16_t l4len; const u_int8_t *l4ptr; u_int8_t l4protocol; u_int8_t l4_result; if (!flow) return(1); /* reset payload_packet_len, will be set if ipv4 tcp or udp */ flow->packet.payload_packet_len = 0; flow->packet.l4_packet_len = 0; flow->packet.l3_packet_len = packetlen; flow->packet.tcp = NULL, flow->packet.udp = NULL; flow->packet.generic_l4_ptr = NULL; #ifdef NDPI_DETECTION_SUPPORT_IPV6 flow->packet.iphv6 = NULL; #endif /* NDPI_DETECTION_SUPPORT_IPV6 */ ndpi_apply_flow_protocol_to_packet(flow, &flow->packet); l3len = flow->packet.l3_packet_len; #ifdef NDPI_DETECTION_SUPPORT_IPV6 if(flow->packet.iph != NULL) { #endif /* NDPI_DETECTION_SUPPORT_IPV6 */ decaps_iph = flow->packet.iph; #ifdef NDPI_DETECTION_SUPPORT_IPV6 } #endif /* NDPI_DETECTION_SUPPORT_IPV6 */ if(decaps_iph && decaps_iph->version == IPVERSION && decaps_iph->ihl >= 5) { NDPI_LOG_DBG2(ndpi_str, "ipv4 header\n"); } #ifdef NDPI_DETECTION_SUPPORT_IPV6 else if(decaps_iph && decaps_iph->version == 6 && l3len >= sizeof(struct ndpi_ipv6hdr) && (ndpi_str->ip_version_limit & NDPI_DETECTION_ONLY_IPV4) == 0) { NDPI_LOG_DBG2(ndpi_str, "ipv6 header\n"); flow->packet.iphv6 = (struct ndpi_ipv6hdr *)flow->packet.iph; flow->packet.iph = NULL; } #endif else { flow->packet.iph = NULL; return(1); } /* needed: * - unfragmented packets * - ip header <= packet len * - ip total length >= packet len */ l4ptr = NULL; l4len = 0; l4protocol = 0; l4_result = ndpi_detection_get_l4_internal(ndpi_str, (const u_int8_t *) decaps_iph, l3len, &l4ptr, &l4len, &l4protocol, 0); if(l4_result != 0) { return(1); } flow->packet.l4_protocol = l4protocol; flow->packet.l4_packet_len = l4len; flow->l4_proto = l4protocol; /* tcp / udp detection */ if(l4protocol == IPPROTO_TCP && flow->packet.l4_packet_len >= 20 /* min size of tcp */ ) { /* tcp */ flow->packet.tcp = (struct ndpi_tcphdr *) l4ptr; if(flow->packet.l4_packet_len >=flow->packet.tcp->doff * 4) { flow->packet.payload_packet_len = flow->packet.l4_packet_len -flow->packet.tcp->doff * 4; flow->packet.actual_payload_len = flow->packet.payload_packet_len; flow->packet.payload = ((u_int8_t *)flow->packet.tcp) + (flow->packet.tcp->doff * 4); /* check for new tcp syn packets, here * idea: reset detection state if a connection is unknown */ if(flow->packet.tcp->syn != 0 && flow->packet.tcp->ack == 0 && flow->init_finished != 0 && flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { u_int8_t backup; u_int16_t backup1, backup2; if(flow->http.url) ndpi_free(flow->http.url); if(flow->http.content_type) ndpi_free(flow->http.content_type); if(flow->http.user_agent) ndpi_free(flow->http.user_agent); backup = flow->num_processed_pkts; backup1 = flow->guessed_protocol_id; backup2 = flow->guessed_host_protocol_id; memset(flow, 0, sizeof(*(flow))); flow->num_processed_pkts = backup; flow->guessed_protocol_id = backup1; flow->guessed_host_protocol_id = backup2; NDPI_LOG_DBG(ndpi_str, "tcp syn packet for unknown protocol, reset detection state\n"); } } else { /* tcp header not complete */ flow->packet.tcp = NULL; } } else if(l4protocol == IPPROTO_UDP && flow->packet.l4_packet_len >= 8 /* size of udp */ ) { flow->packet.udp = (struct ndpi_udphdr *) l4ptr; flow->packet.payload_packet_len =flow->packet.l4_packet_len - 8; flow->packet.payload = ((u_int8_t *)flow->packet.udp) + 8; } else { flow->packet.generic_l4_ptr = l4ptr; } return(0); } void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { if(!flow) { return; } else { /* const for gcc code optimization and cleaner code */ struct ndpi_packet_struct *packet = &flow->packet; const struct ndpi_iphdr *iph = packet->iph; #ifdef NDPI_DETECTION_SUPPORT_IPV6 const struct ndpi_ipv6hdr *iphv6 = packet->iphv6; #endif const struct ndpi_tcphdr *tcph = packet->tcp; const struct ndpi_udphdr *udph = flow->packet.udp; packet->tcp_retransmission = 0, packet->packet_direction = 0; if(ndpi_str->direction_detect_disable) { packet->packet_direction = flow->packet_direction; } else { if(iph != NULL && ntohl(iph->saddr) < ntohl(iph->daddr)) packet->packet_direction = 1; #ifdef NDPI_DETECTION_SUPPORT_IPV6 if(iphv6 != NULL && NDPI_COMPARE_IPV6_ADDRESS_STRUCTS(&iphv6->ip6_src, &iphv6->ip6_dst) != 0) packet->packet_direction = 1; #endif } packet->packet_lines_parsed_complete = 0; if(flow->init_finished == 0) { flow->init_finished = 1; flow->setup_packet_direction = packet->packet_direction; } if(tcph != NULL) { /* reset retried bytes here before setting it */ packet->num_retried_bytes = 0; if(!ndpi_str->direction_detect_disable) packet->packet_direction = (ntohs(tcph->source) < ntohs(tcph->dest)) ? 1 : 0; if(tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0 && flow->l4.tcp.seen_ack == 0) { flow->l4.tcp.seen_syn = 1; } if(tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0 && flow->l4.tcp.seen_ack == 0) { flow->l4.tcp.seen_syn_ack = 1; } if(tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1 && flow->l4.tcp.seen_ack == 0) { flow->l4.tcp.seen_ack = 1; } if((flow->next_tcp_seq_nr[0] == 0 && flow->next_tcp_seq_nr[1] == 0) || (flow->next_tcp_seq_nr[0] == 0 || flow->next_tcp_seq_nr[1] == 0)) { /* initialize tcp sequence counters */ /* the ack flag needs to be set to get valid sequence numbers from the other * direction. Usually it will catch the second packet syn+ack but it works * also for asymmetric traffic where it will use the first data packet * * if the syn flag is set add one to the sequence number, * otherwise use the payload length. */ if(tcph->ack != 0) { flow->next_tcp_seq_nr[flow->packet.packet_direction] = ntohl(tcph->seq) + (tcph->syn ? 1 : packet->payload_packet_len); flow->next_tcp_seq_nr[1 -flow->packet.packet_direction] = ntohl(tcph->ack_seq); } } else if(packet->payload_packet_len > 0) { /* check tcp sequence counters */ if(((u_int32_t)(ntohl(tcph->seq) - flow->next_tcp_seq_nr[packet->packet_direction])) > ndpi_str->tcp_max_retransmission_window_size) { packet->tcp_retransmission = 1; /* CHECK IF PARTIAL RETRY IS HAPPENING */ if((flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq) < packet->payload_packet_len)) { /* num_retried_bytes actual_payload_len hold info about the partial retry analyzer which require this info can make use of this info Other analyzer can use packet->payload_packet_len */ packet->num_retried_bytes = (u_int16_t)(flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq)); packet->actual_payload_len = packet->payload_packet_len - packet->num_retried_bytes; flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; } } /* normal path actual_payload_len is initialized to payload_packet_len during tcp header parsing itself. It will be changed only in case of retransmission */ else { packet->num_retried_bytes = 0; flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; } } if(tcph->rst) { flow->next_tcp_seq_nr[0] = 0; flow->next_tcp_seq_nr[1] = 0; } } else if(udph != NULL) { if(!ndpi_str->direction_detect_disable) packet->packet_direction = (htons(udph->source) < htons(udph->dest)) ? 1 : 0; } if(flow->packet_counter < MAX_PACKET_COUNTER && packet->payload_packet_len) { flow->packet_counter++; } if(flow->packet_direction_counter[packet->packet_direction] < MAX_PACKET_COUNTER && packet->payload_packet_len) { flow->packet_direction_counter[packet->packet_direction]++; } if(flow->byte_counter[packet->packet_direction] + packet->payload_packet_len > flow->byte_counter[packet->packet_direction]) { flow->byte_counter[packet->packet_direction] += packet->payload_packet_len; } } } void check_ndpi_other_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { if (!flow) { return; } void *func = NULL; u_int32_t a; u_int16_t proto_index = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoIdx; int16_t proto_id = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoId; NDPI_PROTOCOL_BITMASK detection_bitmask; NDPI_SAVE_AS_BITMASK(detection_bitmask, flow->packet.detected_protocol_stack[0]); if((proto_id != NDPI_PROTOCOL_UNKNOWN) && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer[proto_index].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[proto_index].detection_bitmask, detection_bitmask) != 0 && (ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask) { if((flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (ndpi_str->proto_defaults[flow->guessed_protocol_id].func != NULL)) ndpi_str->proto_defaults[flow->guessed_protocol_id].func(ndpi_str, flow), func = ndpi_str->proto_defaults[flow->guessed_protocol_id].func; } for(a = 0; a < ndpi_str->callback_buffer_size_non_tcp_udp; a++) { if((func != ndpi_str->callback_buffer_non_tcp_udp[a].func) && (ndpi_str->callback_buffer_non_tcp_udp[a].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer_non_tcp_udp[a].ndpi_selection_bitmask && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer_non_tcp_udp[a].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer_non_tcp_udp[a].detection_bitmask, detection_bitmask) != 0) { if(ndpi_str->callback_buffer_non_tcp_udp[a].func != NULL) ndpi_str->callback_buffer_non_tcp_udp[a].func(ndpi_str, flow); if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) break; /* Stop after detecting the first protocol */ } } } void check_ndpi_udp_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { void *func = NULL; u_int32_t a; u_int16_t proto_index = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoIdx; int16_t proto_id = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoId; NDPI_PROTOCOL_BITMASK detection_bitmask; NDPI_SAVE_AS_BITMASK(detection_bitmask, flow->packet.detected_protocol_stack[0]); if((proto_id != NDPI_PROTOCOL_UNKNOWN) && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer[proto_index].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[proto_index].detection_bitmask, detection_bitmask) != 0 && (ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask) { if((flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (ndpi_str->proto_defaults[flow->guessed_protocol_id].func != NULL)) ndpi_str->proto_defaults[flow->guessed_protocol_id].func(ndpi_str, flow), func = ndpi_str->proto_defaults[flow->guessed_protocol_id].func; } for(a = 0; a < ndpi_str->callback_buffer_size_udp; a++) { if((func != ndpi_str->callback_buffer_udp[a].func) && (ndpi_str->callback_buffer_udp[a].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer_udp[a].ndpi_selection_bitmask && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer_udp[a].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer_udp[a].detection_bitmask, detection_bitmask) != 0) { ndpi_str->callback_buffer_udp[a].func(ndpi_str, flow); // NDPI_LOG_DBG(ndpi_str, "[UDP,CALL] dissector of protocol as callback_buffer idx = %d\n",a); if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) break; /* Stop after detecting the first protocol */ } else if(_ndpi_debug_callbacks) NDPI_LOG_DBG2(ndpi_str, "[UDP,SKIP] dissector of protocol as callback_buffer idx = %d\n",a); } } void check_ndpi_tcp_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { void *func = NULL; u_int32_t a; u_int16_t proto_index = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoIdx; int16_t proto_id = ndpi_str->proto_defaults[flow->guessed_protocol_id].protoId; NDPI_PROTOCOL_BITMASK detection_bitmask; NDPI_SAVE_AS_BITMASK(detection_bitmask, flow->packet.detected_protocol_stack[0]); if(flow->packet.payload_packet_len != 0) { if((proto_id != NDPI_PROTOCOL_UNKNOWN) && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer[proto_index].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[proto_index].detection_bitmask, detection_bitmask) != 0 && (ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask) { if((flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (ndpi_str->proto_defaults[flow->guessed_protocol_id].func != NULL)) ndpi_str->proto_defaults[flow->guessed_protocol_id].func(ndpi_str, flow), func = ndpi_str->proto_defaults[flow->guessed_protocol_id].func; } if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { for(a = 0; a < ndpi_str->callback_buffer_size_tcp_payload; a++) { if((func != ndpi_str->callback_buffer_tcp_payload[a].func) && (ndpi_str->callback_buffer_tcp_payload[a].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer_tcp_payload[a].ndpi_selection_bitmask && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer_tcp_payload[a].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer_tcp_payload[a].detection_bitmask, detection_bitmask) != 0) { ndpi_str->callback_buffer_tcp_payload[a].func(ndpi_str, flow); if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) break; /* Stop after detecting the first protocol */ } } } } else { /* no payload */ if((proto_id != NDPI_PROTOCOL_UNKNOWN) && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer[proto_index].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer[proto_index].detection_bitmask, detection_bitmask) != 0 && (ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer[proto_index].ndpi_selection_bitmask) { if((flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (ndpi_str->proto_defaults[flow->guessed_protocol_id].func != NULL) && ((ndpi_str->callback_buffer[flow->guessed_protocol_id].ndpi_selection_bitmask & NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD) == 0)) ndpi_str->proto_defaults[flow->guessed_protocol_id].func(ndpi_str, flow), func = ndpi_str->proto_defaults[flow->guessed_protocol_id].func; } for(a = 0; a < ndpi_str->callback_buffer_size_tcp_no_payload; a++) { if((func != ndpi_str->callback_buffer_tcp_payload[a].func) && (ndpi_str->callback_buffer_tcp_no_payload[a].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_str->callback_buffer_tcp_no_payload[a].ndpi_selection_bitmask && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_str->callback_buffer_tcp_no_payload[a].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_str->callback_buffer_tcp_no_payload[a].detection_bitmask, detection_bitmask) != 0) { ndpi_str->callback_buffer_tcp_no_payload[a].func(ndpi_str, flow); if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) break; /* Stop after detecting the first protocol */ } } } } /* ********************************************************************************* */ void ndpi_check_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { if(flow->packet.tcp != NULL) check_ndpi_tcp_flow_func(ndpi_str, flow, ndpi_selection_packet); else if(flow->packet.udp != NULL) check_ndpi_udp_flow_func(ndpi_str, flow, ndpi_selection_packet); else check_ndpi_other_flow_func(ndpi_str, flow, ndpi_selection_packet); } /* ********************************************************************************* */ u_int16_t ndpi_guess_host_protocol_id(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { u_int16_t ret = NDPI_PROTOCOL_UNKNOWN; if(flow->packet.iph) { struct in_addr addr; addr.s_addr = flow->packet.iph->saddr; /* guess host protocol */ ret = ndpi_network_ptree_match(ndpi_str, &addr); if(ret == NDPI_PROTOCOL_UNKNOWN) { addr.s_addr = flow->packet.iph->daddr; ret = ndpi_network_ptree_match(ndpi_str, &addr); } } return(ret); } /* ********************************************************************************* */ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int8_t enable_guess, u_int8_t *protocol_was_guessed) { ndpi_protocol ret = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED }; *protocol_was_guessed = 0; if(flow == NULL) return(ret); /* Init defaults */ ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; ret.category = flow->category; /* Ensure that we don't change our mind if detection is already complete */ if((ret.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (ret.app_protocol != NDPI_PROTOCOL_UNKNOWN)) return(ret); /* TODO: add the remaining stage_XXXX protocols */ if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { u_int16_t guessed_protocol_id, guessed_host_protocol_id; if(flow->guessed_protocol_id == NDPI_PROTOCOL_STUN) goto check_stun_export; else if((flow->guessed_protocol_id == NDPI_PROTOCOL_HANGOUT_DUO) || (flow->guessed_protocol_id == NDPI_PROTOCOL_MESSENGER) || (flow->guessed_protocol_id == NDPI_PROTOCOL_WHATSAPP_CALL)) ndpi_set_detected_protocol(ndpi_str, flow, flow->guessed_protocol_id, NDPI_PROTOCOL_UNKNOWN); else if((flow->l4.tcp.tls_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) { ndpi_set_detected_protocol(ndpi_str, flow, NDPI_PROTOCOL_TLS, NDPI_PROTOCOL_UNKNOWN); } else { if((flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) && (flow->packet.l4_protocol == IPPROTO_TCP) && (flow->l4.tcp.tls_stage > 1)) flow->guessed_protocol_id = NDPI_PROTOCOL_TLS; guessed_protocol_id = flow->guessed_protocol_id, guessed_host_protocol_id = flow->guessed_host_protocol_id; if((guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) && ((flow->packet.l4_protocol == IPPROTO_UDP) && NDPI_ISSET(&flow->excluded_protocol_bitmask, guessed_host_protocol_id) && is_udp_guessable_protocol(guessed_host_protocol_id) )) flow->guessed_host_protocol_id = guessed_host_protocol_id = NDPI_PROTOCOL_UNKNOWN; /* Ignore guessed protocol if they have been discarded */ if((guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) // && (guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) && (flow->packet.l4_protocol == IPPROTO_UDP) && NDPI_ISSET(&flow->excluded_protocol_bitmask, guessed_protocol_id) && is_udp_guessable_protocol(guessed_protocol_id)) flow->guessed_protocol_id = guessed_protocol_id = NDPI_PROTOCOL_UNKNOWN; if((guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) || (guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN)) { if((guessed_protocol_id == 0) && (flow->protos.stun_ssl.stun.num_binding_requests > 0) && (flow->protos.stun_ssl.stun.num_processed_pkts > 0)) guessed_protocol_id = NDPI_PROTOCOL_STUN; if(flow->host_server_name[0] != '\0') { ndpi_protocol_match_result ret_match; ndpi_match_host_subprotocol(ndpi_str, flow, (char *)flow->host_server_name, strlen((const char*)flow->host_server_name), &ret_match, NDPI_PROTOCOL_DNS); if(ret_match.protocol_id != NDPI_PROTOCOL_UNKNOWN) guessed_host_protocol_id = ret_match.protocol_id; } ndpi_int_change_protocol(ndpi_str, flow, guessed_host_protocol_id, guessed_protocol_id); } } } else { flow->detected_protocol_stack[1] = flow->guessed_protocol_id, flow->detected_protocol_stack[0] = flow->guessed_host_protocol_id; if(flow->detected_protocol_stack[1] == flow->detected_protocol_stack[0]) flow->detected_protocol_stack[1] = flow->guessed_host_protocol_id; } if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) && (flow->guessed_protocol_id == NDPI_PROTOCOL_STUN)) { check_stun_export: if(flow->protos.stun_ssl.stun.num_processed_pkts || flow->protos.stun_ssl.stun.num_udp_pkts) { // if(/* (flow->protos.stun_ssl.stun.num_processed_pkts >= NDPI_MIN_NUM_STUN_DETECTION) */ ndpi_set_detected_protocol(ndpi_str, flow, flow->guessed_host_protocol_id, NDPI_PROTOCOL_STUN); } } ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; if(ret.master_protocol == NDPI_PROTOCOL_STUN) { if(ret.app_protocol == NDPI_PROTOCOL_FACEBOOK) ret.app_protocol = NDPI_PROTOCOL_MESSENGER; else if(ret.app_protocol == NDPI_PROTOCOL_GOOGLE) { /* As Google has recently introduced Duo, we need to distinguish between it and hangout thing that should be handled by the STUN dissector */ ret.app_protocol = NDPI_PROTOCOL_HANGOUT_DUO; } } if(ret.app_protocol != NDPI_PROTOCOL_UNKNOWN) ndpi_fill_protocol_category(ndpi_str, flow, &ret); return(ret); } /* ********************************************************************************* */ void ndpi_process_extra_packet(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, const unsigned char *packet, const unsigned short packetlen, const u_int64_t current_tick_l, struct ndpi_id_struct *src, struct ndpi_id_struct *dst) { if(flow == NULL) return; if(flow->server_id == NULL) flow->server_id = dst; /* Default */ /* need at least 20 bytes for ip header */ if(packetlen < 20) { return; } flow->packet.tick_timestamp_l = current_tick_l; flow->packet.tick_timestamp = (u_int32_t)(current_tick_l/ndpi_str->ticks_per_second); /* parse packet */ flow->packet.iph = (struct ndpi_iphdr *)packet; /* we are interested in ipv4 packet */ /* set up the packet headers for the extra packet function to use if it wants */ if(ndpi_init_packet_header(ndpi_str, flow, packetlen) != 0) return; /* detect traffic for tcp or udp only */ flow->src = src, flow->dst = dst; ndpi_connection_tracking(ndpi_str, flow); /* call the extra packet function (which may add more data/info to flow) */ if(flow->extra_packets_func) { if((flow->extra_packets_func(ndpi_str, flow)) == 0) flow->check_extra_packets = 0; } flow->num_extra_packets_checked++; } /* ********************************************************************************* */ int ndpi_load_ip_category(struct ndpi_detection_module_struct *ndpi_str, const char *ip_address_and_mask, ndpi_protocol_category_t category) { patricia_node_t *node; struct in_addr pin; int bits = 32; char *ptr; char ipbuf[64]; strncpy(ipbuf, ip_address_and_mask, sizeof(ipbuf)); ipbuf[sizeof(ipbuf) - 1] = '\0'; ptr = strrchr(ipbuf, '/'); if(ptr) { *(ptr++) = '\0'; if(atoi(ptr)>=0 && atoi(ptr)<=32) bits = atoi(ptr); } if(inet_pton(AF_INET, ipbuf, &pin) != 1) { NDPI_LOG_DBG2(ndpi_str, "Invalid ip/ip+netmask: %s\n", ip_address_and_mask); return(-1); } if((node = add_to_ptree(ndpi_str->custom_categories.ipAddresses_shadow, AF_INET, &pin, bits)) != NULL) node->value.user_value = (int)category; return(0); } /* ********************************************************************************* */ int ndpi_load_hostname_category(struct ndpi_detection_module_struct *ndpi_str, const char *name_to_add, ndpi_protocol_category_t category) { char *name; if(name_to_add == NULL) return(-1); name = ndpi_strdup(name_to_add); if(name == NULL) return(-1); #if 0 printf("===> %s() Loading %s as %u\n", __FUNCTION__, name, category); #endif #ifdef HAVE_HYPERSCAN { struct hs_list *h = (struct hs_list*)ndpi_malloc(sizeof(struct hs_list)); if(h) { h->expression = name, h->id = (unsigned int)category; h->next = ndpi_str->custom_categories.to_load; ndpi_str->custom_categories.to_load = h; ndpi_str->custom_categories.num_to_load++; } else { free(name); return(-1); } } #else AC_PATTERN_t ac_pattern; memset(&ac_pattern, 0, sizeof(ac_pattern)); if(ndpi_str->custom_categories.hostnames_shadow.ac_automa == NULL) { free(name); return(-1); } ac_pattern.astring = name, ac_pattern.length = strlen(ac_pattern.astring); ac_pattern.rep.number = (int)category; if(ac_automata_add(ndpi_str->custom_categories.hostnames_shadow.ac_automa, &ac_pattern) != ACERR_SUCCESS) { free(name); return(-1); } #endif return(0); } /* ********************************************************************************* */ /* Loads an IP or name category */ int ndpi_load_category(struct ndpi_detection_module_struct *ndpi_struct, const char *ip_or_name, ndpi_protocol_category_t category) { int rv; /* Try to load as IP address first */ rv = ndpi_load_ip_category(ndpi_struct, ip_or_name, category); if(rv < 0) { /* IP load failed, load as hostname */ rv = ndpi_load_hostname_category(ndpi_struct, ip_or_name, category); } return(rv); } /* ********************************************************************************* */ int ndpi_enable_loaded_categories(struct ndpi_detection_module_struct *ndpi_str) { int i; /* First add the nDPI known categories matches */ for(i=0; category_match[i].string_to_match != NULL; i++) ndpi_load_category(ndpi_str, category_match[i].string_to_match, category_match[i].protocol_category); #ifdef HAVE_HYPERSCAN if(ndpi_str->custom_categories.num_to_load > 0) { const char **expressions; unsigned int *ids; int rc; struct hs_list *head = ndpi_str->custom_categories.to_load; expressions = (const char**)ndpi_calloc(sizeof(char*), ndpi_str->custom_categories.num_to_load+1); if(!expressions) return(-1); ids = (unsigned int*)ndpi_calloc(sizeof(unsigned int), ndpi_str->custom_categories.num_to_load+1); if(!ids) { ndpi_free(expressions); return(-1); } for(i=0; head != NULL; i++) { #ifdef DEBUG printf("[HS] Loading category %u for %s\n", head->id, head->expression); #endif expressions[i] = head->expression, ids[i] = head->id; head = head->next; } if(i != ndpi_str->custom_categories.num_to_load){ ndpi_free(expressions); return(-1); } free_hyperscan_memory(ndpi_str->custom_categories.hostnames); ndpi_str->custom_categories.hostnames = (struct hs*)ndpi_malloc(sizeof(struct hs)); if(ndpi_str->custom_categories.hostnames == NULL) { ndpi_free(expressions); ndpi_free(ids); return(-1); /* Failed */ } rc = hyperscan_load_patterns(ndpi_str->custom_categories.hostnames, ndpi_str->custom_categories.num_to_load, expressions, ids); ndpi_free(expressions), ndpi_free(ids); head = ndpi_str->custom_categories.to_load; while(head != NULL) { struct hs_list *next = head->next; ndpi_free(head->expression); ndpi_free(head); head = next; } ndpi_str->custom_categories.to_load = NULL; ndpi_str->custom_categories.num_to_load = 0; if(rc < 0) { ndpi_free(ndpi_str->custom_categories.hostnames); ndpi_str->custom_categories.hostnames = NULL; } } #else /* Free */ ac_automata_release((AC_AUTOMATA_t*)ndpi_str->custom_categories.hostnames.ac_automa, 1 /* free patterns strings memory */); /* Finalize */ ac_automata_finalize((AC_AUTOMATA_t*)ndpi_str->custom_categories.hostnames_shadow.ac_automa); /* Swap */ ndpi_str->custom_categories.hostnames.ac_automa = ndpi_str->custom_categories.hostnames_shadow.ac_automa; /* Realloc */ ndpi_str->custom_categories.hostnames_shadow.ac_automa = ac_automata_init(ac_match_handler); #endif if(ndpi_str->custom_categories.ipAddresses != NULL) ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_str->custom_categories.ipAddresses, free_ptree_data); ndpi_str->custom_categories.ipAddresses = ndpi_str->custom_categories.ipAddresses_shadow; ndpi_str->custom_categories.ipAddresses_shadow = ndpi_New_Patricia(32 /* IPv4 */); ndpi_str->custom_categories.categories_loaded = 1; return(0); } /* ********************************************************************************* */ int ndpi_fill_ip_protocol_category(struct ndpi_detection_module_struct *ndpi_str, u_int32_t saddr, u_int32_t daddr, ndpi_protocol *ret) { if(ndpi_str->custom_categories.categories_loaded) { prefix_t prefix; patricia_node_t *node; if(saddr == 0) node = NULL; else { /* Make sure all in network byte order otherwise compares wont work */ fill_prefix_v4(&prefix, (struct in_addr *)&saddr, 32, ((patricia_tree_t*)ndpi_str->protocols_ptree)->maxbits); node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); } if(!node) { if(daddr != 0) fill_prefix_v4(&prefix, (struct in_addr *)&daddr, 32, ((patricia_tree_t*)ndpi_str->protocols_ptree)->maxbits); node = ndpi_patricia_search_best(ndpi_str->custom_categories.ipAddresses, &prefix); } if(node) { ret->category = (ndpi_protocol_category_t)node->value.user_value; return(1); } } ret->category = ndpi_get_proto_category(ndpi_str, *ret); return(0); } /* ********************************************************************************* */ void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, ndpi_protocol *ret) { if(ndpi_str->custom_categories.categories_loaded) { if(flow->guessed_header_category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) { flow->category = ret->category = flow->guessed_header_category; return; } if(flow->host_server_name[0] != '\0') { unsigned long id; int rc = ndpi_match_custom_category(ndpi_str, (char *)flow->host_server_name, strlen((char *)flow->host_server_name), &id); if(rc == 0) { flow->category = ret->category = (ndpi_protocol_category_t)id; return; } } if((flow->l4.tcp.tls_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) { unsigned long id; int rc = ndpi_match_custom_category(ndpi_str, (char *)flow->protos.stun_ssl.ssl.client_certificate, strlen(flow->protos.stun_ssl.ssl.client_certificate), &id); if(rc == 0) { flow->category = ret->category = (ndpi_protocol_category_t)id; return; } } } flow->category = ret->category = ndpi_get_proto_category(ndpi_str, *ret); } /* ********************************************************************************* */ static void ndpi_reset_packet_line_info(struct ndpi_packet_struct *packet) { packet->parsed_lines = 0, packet->empty_line_position_set = 0, packet->host_line.ptr = NULL, packet->host_line.len = 0, packet->referer_line.ptr = NULL, packet->referer_line.len = 0, packet->content_line.ptr = NULL, packet->content_line.len = 0, packet->accept_line.ptr = NULL, packet->accept_line.len = 0, packet->user_agent_line.ptr = NULL, packet->user_agent_line.len = 0, packet->http_url_name.ptr = NULL, packet->http_url_name.len = 0, packet->http_encoding.ptr = NULL, packet->http_encoding.len = 0, packet->http_transfer_encoding.ptr = NULL, packet->http_transfer_encoding.len = 0, packet->http_contentlen.ptr = NULL, packet->http_contentlen.len = 0, packet->http_cookie.ptr = NULL, packet->http_cookie.len = 0, packet->http_origin.len = 0, packet->http_origin.ptr = NULL, packet->http_x_session_type.ptr = NULL, packet->http_x_session_type.len = 0, packet->server_line.ptr = NULL, packet->server_line.len = 0, packet->http_method.ptr = NULL, packet->http_method.len = 0, packet->http_response.ptr = NULL, packet->http_response.len = 0, packet->http_num_headers = 0; } /* ********************************************************************************* */ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, const unsigned char *packet, const unsigned short packetlen, const u_int64_t current_tick_l, struct ndpi_id_struct *src, struct ndpi_id_struct *dst) { NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet; u_int32_t a; ndpi_protocol ret = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED }; if(ndpi_str->ndpi_log_level >= NDPI_LOG_TRACE) NDPI_LOG(flow ? flow->detected_protocol_stack[0]:NDPI_PROTOCOL_UNKNOWN, ndpi_str, NDPI_LOG_TRACE, "START packet processing\n"); if(flow == NULL) return(ret); else ret.category = flow->category; flow->num_processed_pkts++; /* Init default */ ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; if(flow->server_id == NULL) flow->server_id = dst; /* Default */ if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) { if(flow->check_extra_packets) { ndpi_process_extra_packet(ndpi_str, flow, packet, packetlen, current_tick_l, src, dst); /* Update in case of new match */ ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; return(ret); } else goto ret_protocols; } /* need at least 20 bytes for ip header */ if(packetlen < 20) { /* reset protocol which is normally done in init_packet_header */ ndpi_int_reset_packet_protocol(&flow->packet); goto invalidate_ptr; } flow->packet.tick_timestamp_l = current_tick_l; flow->packet.tick_timestamp = (u_int32_t)(current_tick_l/ndpi_str->ticks_per_second); /* parse packet */ flow->packet.iph = (struct ndpi_iphdr *)packet; /* we are interested in ipv4 packet */ if(ndpi_init_packet_header(ndpi_str, flow, packetlen) != 0) goto invalidate_ptr; /* detect traffic for tcp or udp only */ flow->src = src, flow->dst = dst; ndpi_connection_tracking(ndpi_str, flow); /* build ndpi_selection packet bitmask */ ndpi_selection_packet = NDPI_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC; if(flow->packet.iph != NULL) ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_IP | NDPI_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6; if(flow->packet.tcp != NULL) ndpi_selection_packet |= (NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP); if(flow->packet.udp != NULL) ndpi_selection_packet |= (NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP | NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP); if(flow->packet.payload_packet_len != 0) ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD; if(flow->packet.tcp_retransmission == 0) ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_NO_TCP_RETRANSMISSION; #ifdef NDPI_DETECTION_SUPPORT_IPV6 if(flow->packet.iphv6 != NULL) ndpi_selection_packet |= NDPI_SELECTION_BITMASK_PROTOCOL_IPV6 | NDPI_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6; #endif /* NDPI_DETECTION_SUPPORT_IPV6 */ if((!flow->protocol_id_already_guessed) && ( #ifdef NDPI_DETECTION_SUPPORT_IPV6 flow->packet.iphv6 || #endif flow->packet.iph)) { u_int16_t sport, dport; u_int8_t protocol; u_int8_t user_defined_proto; flow->protocol_id_already_guessed = 1; #ifdef NDPI_DETECTION_SUPPORT_IPV6 if(flow->packet.iphv6 != NULL) { protocol = flow->packet.iphv6->ip6_hdr.ip6_un1_nxt; } else #endif { protocol = flow->packet.iph->protocol; } if(flow->packet.udp) sport = ntohs(flow->packet.udp->source), dport = ntohs(flow->packet.udp->dest); else if(flow->packet.tcp) sport = ntohs(flow->packet.tcp->source), dport = ntohs(flow->packet.tcp->dest); else sport = dport = 0; /* guess protocol */ flow->guessed_protocol_id = (int16_t)ndpi_guess_protocol_id(ndpi_str, flow, protocol, sport, dport, &user_defined_proto); flow->guessed_host_protocol_id = ndpi_guess_host_protocol_id(ndpi_str, flow); if(ndpi_str->custom_categories.categories_loaded && flow->packet.iph) { ndpi_fill_ip_protocol_category(ndpi_str, flow->packet.iph->saddr, flow->packet.iph->daddr, &ret); flow->guessed_header_category = ret.category; } else flow->guessed_header_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED; if(flow->guessed_protocol_id > NDPI_MAX_SUPPORTED_PROTOCOLS) { /* This is a custom protocol and it has priority over everything else */ ret.master_protocol = NDPI_PROTOCOL_UNKNOWN, ret.app_protocol = flow->guessed_protocol_id ? flow->guessed_protocol_id : flow->guessed_host_protocol_id; ndpi_fill_protocol_category(ndpi_str, flow, &ret); goto invalidate_ptr; } if(user_defined_proto && flow->guessed_protocol_id != NDPI_PROTOCOL_UNKNOWN) { if(flow->packet.iph) { if(flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) { u_int8_t protocol_was_guessed; /* ret.master_protocol = flow->guessed_protocol_id , ret.app_protocol = flow->guessed_host_protocol_id; /\* ****** *\/ */ ret = ndpi_detection_giveup(ndpi_str, flow, 0, &protocol_was_guessed); } ndpi_fill_protocol_category(ndpi_str, flow, &ret); goto invalidate_ptr; } } else { /* guess host protocol */ if(flow->packet.iph) { struct in_addr addr; addr.s_addr = flow->packet.iph->saddr; flow->guessed_host_protocol_id = ndpi_network_ptree_match(ndpi_str, &addr); if(flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) { addr.s_addr = flow->packet.iph->daddr; flow->guessed_host_protocol_id = ndpi_network_ptree_match(ndpi_str, &addr); } } } } if(flow->guessed_host_protocol_id > NDPI_MAX_SUPPORTED_PROTOCOLS) { /* This is a custom protocol and it has priority over everything else */ ret.master_protocol = NDPI_PROTOCOL_UNKNOWN, ret.app_protocol = flow->guessed_host_protocol_id; if(flow->packet.tcp && (ret.master_protocol == NDPI_PROTOCOL_UNKNOWN)) { /* Minimal guess for HTTP/SSL-based protocols */ int i; for(i=0; i<2; i++) { u_int16_t port = (i == 0) ? ntohs(flow->packet.tcp->dest) : ntohs(flow->packet.tcp->source); switch(port) { case 80: ret.master_protocol = NDPI_PROTOCOL_HTTP; break; case 443: ret.master_protocol = NDPI_PROTOCOL_TLS; /* QUIC could also match */ break; } if(ret.master_protocol != NDPI_PROTOCOL_UNKNOWN) break; } } ndpi_check_flow_func(ndpi_str, flow, &ndpi_selection_packet); ndpi_fill_protocol_category(ndpi_str, flow, &ret); goto invalidate_ptr; } ndpi_check_flow_func(ndpi_str, flow, &ndpi_selection_packet); a = flow->packet.detected_protocol_stack[0]; if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_str->detection_bitmask, a) == 0) a = NDPI_PROTOCOL_UNKNOWN; if(a != NDPI_PROTOCOL_UNKNOWN) { int i; for(i=0; ihost_server_name); i++) { if(flow->host_server_name[i] != '\0') flow->host_server_name[i] = tolower(flow->host_server_name[i]); else { flow->host_server_name[i] ='\0'; break; } } } ret_protocols: if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) { ret.master_protocol = flow->detected_protocol_stack[1], ret.app_protocol = flow->detected_protocol_stack[0]; if(ret.app_protocol == ret.master_protocol) ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; } else ret.app_protocol = flow->detected_protocol_stack[0]; /* Don't overwrite the category if already set */ if(flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) ndpi_fill_protocol_category(ndpi_str, flow, &ret); else ret.category = flow->category; if((flow->num_processed_pkts == 1) && (ret.master_protocol == NDPI_PROTOCOL_UNKNOWN) && (ret.app_protocol == NDPI_PROTOCOL_UNKNOWN) && flow->packet.tcp && (flow->packet.tcp->syn == 0) && (flow->guessed_protocol_id == 0) ) { u_int8_t protocol_was_guessed; /* This is a TCP flow - whose first packet is NOT a SYN - no protocol has been detected We don't see how future packets can match anything hence we giveup here */ ret = ndpi_detection_giveup(ndpi_str, flow, 0, &protocol_was_guessed); } invalidate_ptr: /* Invalidate packet memory to avoid accessing the pointers below when the packet is no longer accessible */ flow->packet.iph = NULL, flow->packet.tcp = NULL, flow->packet.udp = NULL, flow->packet.payload = NULL; ndpi_reset_packet_line_info(&flow->packet); return(ret); } /* ********************************************************************************* */ u_int32_t ndpi_bytestream_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read) { u_int32_t val; val = 0; // cancel if eof, ' ' or line end chars are reached while(*str >= '0' && *str <= '9' && max_chars_to_read > 0) { val *= 10; val += *str - '0'; str++; max_chars_to_read = max_chars_to_read - 1; *bytes_read = *bytes_read + 1; } return(val); } /* ********************************************************************************* */ #ifdef CODE_UNUSED u_int32_t ndpi_bytestream_dec_or_hex_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read) { u_int32_t val; val = 0; if(max_chars_to_read <= 2 || str[0] != '0' || str[1] != 'x') { return(ndpi_bytestream_to_number(str, max_chars_to_read, bytes_read)); } else { /*use base 16 system */ str += 2; max_chars_to_read -= 2; *bytes_read = *bytes_read + 2; while(max_chars_to_read > 0) { if(*str >= '0' && *str <= '9') { val *= 16; val += *str - '0'; } else if(*str >= 'a' && *str <= 'f') { val *= 16; val += *str + 10 - 'a'; } else if(*str >= 'A' && *str <= 'F') { val *= 16; val += *str + 10 - 'A'; } else { break; } str++; max_chars_to_read = max_chars_to_read - 1; *bytes_read = *bytes_read + 1; } } return(val); } #endif /* ********************************************************************************* */ u_int64_t ndpi_bytestream_to_number64(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read) { u_int64_t val; val = 0; // cancel if eof, ' ' or line end chars are reached while(max_chars_to_read > 0 && *str >= '0' && *str <= '9') { val *= 10; val += *str - '0'; str++; max_chars_to_read = max_chars_to_read - 1; *bytes_read = *bytes_read + 1; } return(val); } /* ********************************************************************************* */ u_int64_t ndpi_bytestream_dec_or_hex_to_number64(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read) { u_int64_t val; val = 0; if(max_chars_to_read <= 2 || str[0] != '0' || str[1] != 'x') { return(ndpi_bytestream_to_number64(str, max_chars_to_read, bytes_read)); } else { /*use base 16 system */ str += 2; max_chars_to_read -= 2; *bytes_read = *bytes_read + 2; while(max_chars_to_read > 0) { if(*str >= '0' && *str <= '9') { val *= 16; val += *str - '0'; } else if(*str >= 'a' && *str <= 'f') { val *= 16; val += *str + 10 - 'a'; } else if(*str >= 'A' && *str <= 'F') { val *= 16; val += *str + 10 - 'A'; } else { break; } str++; max_chars_to_read = max_chars_to_read - 1; *bytes_read = *bytes_read + 1; } } return(val); } /* ********************************************************************************* */ u_int32_t ndpi_bytestream_to_ipv4(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read) { u_int32_t val; u_int16_t read = 0; u_int16_t oldread; u_int32_t c; /* ip address must be X.X.X.X with each X between 0 and 255 */ oldread = read; c = ndpi_bytestream_to_number(str, max_chars_to_read, &read); if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') return(0); read++; val = c << 24; oldread = read; c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') return(0); read++; val = val + (c << 16); oldread = read; c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') return(0); read++; val = val + (c << 8); oldread = read; c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); if(c > 255 || oldread == read || max_chars_to_read == read) return(0); val = val + c; *bytes_read = *bytes_read + read; return(htonl(val)); } /* ********************************************************************************* */ /* internal function for every detection to parse one packet and to increase the info buffer */ void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { u_int32_t a; struct ndpi_packet_struct *packet = &flow->packet; if(packet->packet_lines_parsed_complete != 0) return; packet->packet_lines_parsed_complete = 1; ndpi_reset_packet_line_info(packet); if((packet->payload_packet_len < 3) || (packet->payload == NULL)) return; packet->line[packet->parsed_lines].ptr = packet->payload; packet->line[packet->parsed_lines].len = 0; for(a = 0; (a < packet->payload_packet_len) && (packet->parsed_lines < NDPI_MAX_PARSE_LINES_PER_PACKET); a++) { if((a + 1) == packet->payload_packet_len) return; /* Return if only one byte remains (prevent invalid reads past end-of-buffer) */ if(get_u_int16_t(packet->payload, a) == ntohs(0x0d0a)) { /* If end of line char sequence CR+NL "\r\n", process line */ packet->line[packet->parsed_lines].len = (u_int16_t)(((unsigned long) &packet->payload[a]) - ((unsigned long) packet->line[packet->parsed_lines].ptr)); /* First line of a HTTP response parsing. Expected a "HTTP/1.? ???" */ if(packet->parsed_lines == 0 && packet->line[0].len >= NDPI_STATICSTRING_LEN("HTTP/1.X 200 ") && strncasecmp((const char *)packet->line[0].ptr, "HTTP/1.", NDPI_STATICSTRING_LEN("HTTP/1.")) == 0 && packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.X ")] > '0' && /* response code between 000 and 699 */ packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.X ")] < '6') { packet->http_response.ptr = &packet->line[0].ptr[NDPI_STATICSTRING_LEN("HTTP/1.1 ")]; packet->http_response.len = packet->line[0].len - NDPI_STATICSTRING_LEN("HTTP/1.1 "); packet->http_num_headers++; /* Set server HTTP response code */ if(packet->payload_packet_len >= 12) { char buf[4]; /* Set server HTTP response code */ strncpy(buf, (char*)&packet->payload[9], 3); buf[3] = '\0'; flow->http.response_status_code = atoi(buf); /* https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ if((flow->http.response_status_code < 100) || (flow->http.response_status_code > 509)) flow->http.response_status_code = 0; /* Out of range */ } } /* "Server:" header line in HTTP response */ if(packet->line[packet->parsed_lines].len > NDPI_STATICSTRING_LEN("Server:") + 1 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Server:", NDPI_STATICSTRING_LEN("Server:")) == 0) { // some stupid clients omit a space and place the servername directly after the colon if(packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:")] == ' ') { packet->server_line.ptr = &packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:") + 1]; packet->server_line.len = packet->line[packet->parsed_lines].len - (NDPI_STATICSTRING_LEN("Server:") + 1); } else { packet->server_line.ptr = &packet->line[packet->parsed_lines].ptr[NDPI_STATICSTRING_LEN("Server:")]; packet->server_line.len = packet->line[packet->parsed_lines].len - NDPI_STATICSTRING_LEN("Server:"); } packet->http_num_headers++; } /* "Host:" header line in HTTP request */ if(packet->line[packet->parsed_lines].len > 6 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Host:", 5) == 0) { // some stupid clients omit a space and place the hostname directly after the colon if(packet->line[packet->parsed_lines].ptr[5] == ' ') { packet->host_line.ptr = &packet->line[packet->parsed_lines].ptr[6]; packet->host_line.len = packet->line[packet->parsed_lines].len - 6; } else { packet->host_line.ptr = &packet->line[packet->parsed_lines].ptr[5]; packet->host_line.len = packet->line[packet->parsed_lines].len - 5; } packet->http_num_headers++; } /* "X-Forwarded-For:" header line in HTTP request. Commonly used for HTTP proxies. */ if(packet->line[packet->parsed_lines].len > 17 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "X-Forwarded-For:", 16) == 0) { // some stupid clients omit a space and place the hostname directly after the colon if(packet->line[packet->parsed_lines].ptr[16] == ' ') { packet->forwarded_line.ptr = &packet->line[packet->parsed_lines].ptr[17]; packet->forwarded_line.len = packet->line[packet->parsed_lines].len - 17; } else { packet->forwarded_line.ptr = &packet->line[packet->parsed_lines].ptr[16]; packet->forwarded_line.len = packet->line[packet->parsed_lines].len - 16; } packet->http_num_headers++; } /* "Content-Type:" header line in HTTP. */ if(packet->line[packet->parsed_lines].len > 14 && (strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Content-Type: ", 14) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Content-type: ", 14) == 0)) { packet->content_line.ptr = &packet->line[packet->parsed_lines].ptr[14]; packet->content_line.len = packet->line[packet->parsed_lines].len - 14; while((packet->content_line.len > 0) && (packet->content_line.ptr[0] == ' ')) packet->content_line.len--, packet->content_line.ptr++; packet->http_num_headers++; } /* "Content-Type:" header line in HTTP AGAIN. Probably a bogus response without space after ":" */ if((packet->content_line.len == 0) && (packet->line[packet->parsed_lines].len > 13) && (strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Content-type:", 13) == 0)) { packet->content_line.ptr = &packet->line[packet->parsed_lines].ptr[13]; packet->content_line.len = packet->line[packet->parsed_lines].len - 13; packet->http_num_headers++; } if(packet->content_line.len > 0) { /* application/json; charset=utf-8 */ char separator[] = { ';', '\r', '\0' }; int i; for(i=0; separator[i] != '\0'; i++) { char *c = memchr((char*)packet->content_line.ptr, separator[i], packet->content_line.len); if(c != NULL) packet->content_line.len = c - (char*)packet->content_line.ptr; } } /* "Accept:" header line in HTTP request. */ if(packet->line[packet->parsed_lines].len > 8 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Accept: ", 8) == 0) { packet->accept_line.ptr = &packet->line[packet->parsed_lines].ptr[8]; packet->accept_line.len = packet->line[packet->parsed_lines].len - 8; packet->http_num_headers++; } /* "Referer:" header line in HTTP request. */ if(packet->line[packet->parsed_lines].len > 9 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Referer: ", 9) == 0) { packet->referer_line.ptr = &packet->line[packet->parsed_lines].ptr[9]; packet->referer_line.len = packet->line[packet->parsed_lines].len - 9; packet->http_num_headers++; } /* "User-Agent:" header line in HTTP request. */ if(packet->line[packet->parsed_lines].len > 12 && (strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "User-Agent: ", 12) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "User-agent: ", 12) == 0)) { packet->user_agent_line.ptr = &packet->line[packet->parsed_lines].ptr[12]; packet->user_agent_line.len = packet->line[packet->parsed_lines].len - 12; packet->http_num_headers++; } /* "Content-Encoding:" header line in HTTP response (and request?). */ if(packet->line[packet->parsed_lines].len > 18 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Content-Encoding: ", 18) == 0) { packet->http_encoding.ptr = &packet->line[packet->parsed_lines].ptr[18]; packet->http_encoding.len = packet->line[packet->parsed_lines].len - 18; packet->http_num_headers++; } /* "Transfer-Encoding:" header line in HTTP. */ if(packet->line[packet->parsed_lines].len > 19 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Transfer-Encoding: ", 19) == 0) { packet->http_transfer_encoding.ptr = &packet->line[packet->parsed_lines].ptr[19]; packet->http_transfer_encoding.len = packet->line[packet->parsed_lines].len - 19; packet->http_num_headers++; } /* "Content-Length:" header line in HTTP. */ if(packet->line[packet->parsed_lines].len > 16 && ((strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Content-Length: ", 16) == 0) || (strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "content-length: ", 16) == 0))) { packet->http_contentlen.ptr = &packet->line[packet->parsed_lines].ptr[16]; packet->http_contentlen.len = packet->line[packet->parsed_lines].len - 16; packet->http_num_headers++; } /* "Cookie:" header line in HTTP. */ if(packet->line[packet->parsed_lines].len > 8 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Cookie: ", 8) == 0) { packet->http_cookie.ptr = &packet->line[packet->parsed_lines].ptr[8]; packet->http_cookie.len = packet->line[packet->parsed_lines].len - 8; packet->http_num_headers++; } /* "Origin:" header line in HTTP. */ if(packet->line[packet->parsed_lines].len > 8 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Origin: ", 8) == 0) { packet->http_origin.ptr = &packet->line[packet->parsed_lines].ptr[8]; packet->http_origin.len = packet->line[packet->parsed_lines].len - 8; packet->http_num_headers++; } /* "X-Session-Type:" header line in HTTP. */ if(packet->line[packet->parsed_lines].len > 16 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "X-Session-Type: ", 16) == 0) { packet->http_x_session_type.ptr = &packet->line[packet->parsed_lines].ptr[16]; packet->http_x_session_type.len = packet->line[packet->parsed_lines].len - 16; packet->http_num_headers++; } /* Identification and counting of other HTTP headers. * We consider the most common headers, but there are many others, * which can be seen at references below: * - https://tools.ietf.org/html/rfc7230 * - https://en.wikipedia.org/wiki/List_of_HTTP_header_fields */ if((packet->line[packet->parsed_lines].len > 6 && ( strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Date: ", 6) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Vary: ", 6) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "ETag: ", 6) == 0 )) || (packet->line[packet->parsed_lines].len > 8 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Pragma: ", 8) == 0) || (packet->line[packet->parsed_lines].len > 9 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Expires: ", 9) == 0) || (packet->line[packet->parsed_lines].len > 12 && ( strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Set-Cookie: ", 12) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Keep-Alive: ", 12) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Connection: ", 12) == 0)) || (packet->line[packet->parsed_lines].len > 15 && ( strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Last-Modified: ", 15) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Accept-Ranges: ", 15) == 0)) || (packet->line[packet->parsed_lines].len > 17 && ( strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Accept-Language: ", 17) == 0 || strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Accept-Encoding: ", 17) == 0)) || (packet->line[packet->parsed_lines].len > 27 && strncasecmp((const char *)packet->line[packet->parsed_lines].ptr, "Upgrade-Insecure-Requests: ", 27) == 0)) { /* Just count. In the future, if needed, this if can be splited to parse these headers */ packet->http_num_headers++; } if(packet->line[packet->parsed_lines].len == 0) { packet->empty_line_position = a; packet->empty_line_position_set = 1; } if(packet->parsed_lines >= (NDPI_MAX_PARSE_LINES_PER_PACKET - 1)) return; packet->parsed_lines++; packet->line[packet->parsed_lines].ptr = &packet->payload[a + 2]; packet->line[packet->parsed_lines].len = 0; a++; /* next char in the payload */ } } if(packet->parsed_lines >= 1) { packet->line[packet->parsed_lines].len = (u_int16_t)(((unsigned long) &packet->payload[packet->payload_packet_len]) - ((unsigned long) packet->line[packet->parsed_lines].ptr)); packet->parsed_lines++; } } /* ********************************************************************************* */ void ndpi_parse_packet_line_info_any(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; u_int32_t a; u_int16_t end = packet->payload_packet_len; if(packet->packet_lines_parsed_complete != 0) return; packet->packet_lines_parsed_complete = 1; packet->parsed_lines = 0; if(packet->payload_packet_len == 0) return; packet->line[packet->parsed_lines].ptr = packet->payload; packet->line[packet->parsed_lines].len = 0; for(a = 0; a < end; a++) { if(packet->payload[a] == 0x0a) { packet->line[packet->parsed_lines].len = (u_int16_t)( ((unsigned long) &packet->payload[a]) - ((unsigned long) packet->line[packet->parsed_lines].ptr)); if(a > 0 && packet->payload[a-1] == 0x0d) packet->line[packet->parsed_lines].len--; if(packet->parsed_lines >= (NDPI_MAX_PARSE_LINES_PER_PACKET - 1)) break; packet->parsed_lines++; packet->line[packet->parsed_lines].ptr = &packet->payload[a + 1]; packet->line[packet->parsed_lines].len = 0; if((a + 1) >= packet->payload_packet_len) break; //a++; } } } /* ********************************************************************************* */ u_int16_t ndpi_check_for_email_address(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int16_t counter) { struct ndpi_packet_struct *packet = &flow->packet; NDPI_LOG_DBG2(ndpi_str, "called ndpi_check_for_email_address\n"); if(packet->payload_packet_len > counter && ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || packet->payload[counter] == '-' || packet->payload[counter] == '_')) { NDPI_LOG_DBG2(ndpi_str, "first letter\n"); counter++; while(packet->payload_packet_len > counter && ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || packet->payload[counter] == '-' || packet->payload[counter] == '_' || packet->payload[counter] == '.')) { NDPI_LOG_DBG2(ndpi_str, "further letter\n"); counter++; if(packet->payload_packet_len > counter && packet->payload[counter] == '@') { NDPI_LOG_DBG2(ndpi_str, "@\n"); counter++; while(packet->payload_packet_len > counter && ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') || (packet->payload[counter] >= 'A' && packet->payload[counter] <= 'Z') || (packet->payload[counter] >= '0' && packet->payload[counter] <= '9') || packet->payload[counter] == '-' || packet->payload[counter] == '_')) { NDPI_LOG_DBG2(ndpi_str, "letter\n"); counter++; if(packet->payload_packet_len > counter && packet->payload[counter] == '.') { NDPI_LOG_DBG2(ndpi_str, ".\n"); counter++; if(packet->payload_packet_len > counter + 1 && ((packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') && (packet->payload[counter + 1] >= 'a' && packet->payload[counter + 1] <= 'z'))) { NDPI_LOG_DBG2(ndpi_str, "two letters\n"); counter += 2; if(packet->payload_packet_len > counter && (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { NDPI_LOG_DBG2(ndpi_str, "whitespace1\n"); return(counter); } else if(packet->payload_packet_len > counter && packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') { NDPI_LOG_DBG2(ndpi_str, "one letter\n"); counter++; if(packet->payload_packet_len > counter && (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { NDPI_LOG_DBG2(ndpi_str, "whitespace2\n"); return(counter); } else if(packet->payload_packet_len > counter && packet->payload[counter] >= 'a' && packet->payload[counter] <= 'z') { counter++; if(packet->payload_packet_len > counter && (packet->payload[counter] == ' ' || packet->payload[counter] == ';')) { NDPI_LOG_DBG2(ndpi_str, "whitespace3\n"); return(counter); } else { return(0); } } else { return(0); } } else { return(0); } } else { return(0); } } } return(0); } } } return(0); } #ifdef NDPI_ENABLE_DEBUG_MESSAGES /* ********************************************************************************* */ void ndpi_debug_get_last_log_function_line(struct ndpi_detection_module_struct *ndpi_str, const char **file, const char **func, u_int32_t * line) { *file = ""; *func = ""; if(ndpi_str->ndpi_debug_print_file != NULL) *file = ndpi_str->ndpi_debug_print_file; if(ndpi_str->ndpi_debug_print_function != NULL) *func = ndpi_str->ndpi_debug_print_function; *line = ndpi_str->ndpi_debug_print_line; } #endif /* ********************************************************************************* */ u_int8_t ndpi_detection_get_l4(const u_int8_t * l3, u_int16_t l3_len, const u_int8_t ** l4_return, u_int16_t * l4_len_return, u_int8_t * l4_protocol_return, u_int32_t flags) { return(ndpi_detection_get_l4_internal(NULL, l3, l3_len, l4_return, l4_len_return, l4_protocol_return, flags)); } /* ********************************************************************************* */ void ndpi_set_detected_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { struct ndpi_id_struct *src = flow->src, *dst = flow->dst; ndpi_int_change_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); if(src != NULL) { NDPI_ADD_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, upper_detected_protocol); if(lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN) NDPI_ADD_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, lower_detected_protocol); } if(dst != NULL) { NDPI_ADD_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, upper_detected_protocol); if(lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN) NDPI_ADD_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, lower_detected_protocol); } } /* ********************************************************************************* */ u_int16_t ndpi_get_flow_masterprotocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { return(flow->detected_protocol_stack[1]); } /* ********************************************************************************* */ void ndpi_int_change_flow_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { if(!flow) return; flow->detected_protocol_stack[0] = upper_detected_protocol, flow->detected_protocol_stack[1] = lower_detected_protocol; } /* ********************************************************************************* */ void ndpi_int_change_packet_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { struct ndpi_packet_struct *packet = &flow->packet; /* NOTE: everything below is identically to change_flow_protocol * except flow->packet If you want to change something here, * don't! Change it for the flow function and apply it here * as well */ if(!packet) return; packet->detected_protocol_stack[0] = upper_detected_protocol, packet->detected_protocol_stack[1] = lower_detected_protocol; } /* ********************************************************************************* */ /* generic function for changing the protocol * * what it does is: * 1.update the flow protocol stack with the new protocol * 2.update the packet protocol stack with the new protocol */ void ndpi_int_change_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int16_t upper_detected_protocol, u_int16_t lower_detected_protocol) { if((upper_detected_protocol == NDPI_PROTOCOL_UNKNOWN) && (lower_detected_protocol != NDPI_PROTOCOL_UNKNOWN)) upper_detected_protocol = lower_detected_protocol; if(upper_detected_protocol == lower_detected_protocol) lower_detected_protocol = NDPI_PROTOCOL_UNKNOWN; if((upper_detected_protocol != NDPI_PROTOCOL_UNKNOWN) && (lower_detected_protocol == NDPI_PROTOCOL_UNKNOWN)) { if((flow->guessed_host_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (upper_detected_protocol != flow->guessed_host_protocol_id)) { if(ndpi_str->proto_defaults[upper_detected_protocol].can_have_a_subprotocol) { lower_detected_protocol = upper_detected_protocol; upper_detected_protocol = flow->guessed_host_protocol_id; } } } ndpi_int_change_flow_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); ndpi_int_change_packet_protocol(ndpi_str, flow, upper_detected_protocol, lower_detected_protocol); } /* ********************************************************************************* */ void ndpi_int_change_category(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, ndpi_protocol_category_t protocol_category) { flow->category = protocol_category; } /* ********************************************************************************* */ /* turns a packet back to unknown */ void ndpi_int_reset_packet_protocol(struct ndpi_packet_struct *packet) { int a; for(a = 0; a < NDPI_PROTOCOL_SIZE; a++) packet->detected_protocol_stack[a] = NDPI_PROTOCOL_UNKNOWN; } /* ********************************************************************************* */ void ndpi_int_reset_protocol(struct ndpi_flow_struct *flow) { if(flow) { int a; for(a = 0; a < NDPI_PROTOCOL_SIZE; a++) flow->detected_protocol_stack[a] = NDPI_PROTOCOL_UNKNOWN; } } /* ********************************************************************************* */ void NDPI_PROTOCOL_IP_clear(ndpi_ip_addr_t * ip) { memset(ip, 0, sizeof(ndpi_ip_addr_t)); } /* ********************************************************************************* */ #ifdef CODE_UNUSED /* NTOP */ int NDPI_PROTOCOL_IP_is_set(const ndpi_ip_addr_t * ip) { return(memcmp(ip, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(ndpi_ip_addr_t)) != 0); } #endif /* ********************************************************************************* */ /* check if the source ip address in packet and ip are equal */ /* NTOP */ int ndpi_packet_src_ip_eql(const struct ndpi_packet_struct *packet, const ndpi_ip_addr_t * ip) { #ifdef NDPI_DETECTION_SUPPORT_IPV6 /* IPv6 */ if(packet->iphv6 != NULL) { if(packet->iphv6->ip6_src.u6_addr.u6_addr32[0] == ip->ipv6.u6_addr.u6_addr32[0] && packet->iphv6->ip6_src.u6_addr.u6_addr32[1] == ip->ipv6.u6_addr.u6_addr32[1] && packet->iphv6->ip6_src.u6_addr.u6_addr32[2] == ip->ipv6.u6_addr.u6_addr32[2] && packet->iphv6->ip6_src.u6_addr.u6_addr32[3] == ip->ipv6.u6_addr.u6_addr32[3]) return(1); //else return(0); } #endif /* IPv4 */ if(packet->iph->saddr == ip->ipv4) return(1); return(0); } /* ********************************************************************************* */ /* check if the destination ip address in packet and ip are equal */ int ndpi_packet_dst_ip_eql(const struct ndpi_packet_struct *packet, const ndpi_ip_addr_t * ip) { #ifdef NDPI_DETECTION_SUPPORT_IPV6 /* IPv6 */ if(packet->iphv6 != NULL) { if(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0] == ip->ipv6.u6_addr.u6_addr32[0] && packet->iphv6->ip6_dst.u6_addr.u6_addr32[1] == ip->ipv6.u6_addr.u6_addr32[1] && packet->iphv6->ip6_dst.u6_addr.u6_addr32[2] == ip->ipv6.u6_addr.u6_addr32[2] && packet->iphv6->ip6_dst.u6_addr.u6_addr32[3] == ip->ipv6.u6_addr.u6_addr32[3]) return(1); //else return(0); } #endif /* IPv4 */ if(packet->iph->saddr == ip->ipv4) return(1); return(0); } /* ********************************************************************************* */ /* get the source ip address from packet and put it into ip */ /* NTOP */ void ndpi_packet_src_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t * ip) { NDPI_PROTOCOL_IP_clear(ip); #ifdef NDPI_DETECTION_SUPPORT_IPV6 /* IPv6 */ if(packet->iphv6 != NULL) { ip->ipv6.u6_addr.u6_addr32[0] = packet->iphv6->ip6_src.u6_addr.u6_addr32[0]; ip->ipv6.u6_addr.u6_addr32[1] = packet->iphv6->ip6_src.u6_addr.u6_addr32[1]; ip->ipv6.u6_addr.u6_addr32[2] = packet->iphv6->ip6_src.u6_addr.u6_addr32[2]; ip->ipv6.u6_addr.u6_addr32[3] = packet->iphv6->ip6_src.u6_addr.u6_addr32[3]; } else #endif /* IPv4 */ ip->ipv4 = packet->iph->saddr; } /* ********************************************************************************* */ /* get the destination ip address from packet and put it into ip */ /* NTOP */ void ndpi_packet_dst_ip_get(const struct ndpi_packet_struct *packet, ndpi_ip_addr_t * ip) { NDPI_PROTOCOL_IP_clear(ip); #ifdef NDPI_DETECTION_SUPPORT_IPV6 if(packet->iphv6 != NULL) { ip->ipv6.u6_addr.u6_addr32[0] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]; ip->ipv6.u6_addr.u6_addr32[1] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]; ip->ipv6.u6_addr.u6_addr32[2] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]; ip->ipv6.u6_addr.u6_addr32[3] = packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]; } else #endif ip->ipv4 = packet->iph->daddr; } /* ********************************************************************************* */ u_int8_t ndpi_is_ipv6(const ndpi_ip_addr_t *ip) { #ifdef NDPI_DETECTION_SUPPORT_IPV6 return(ip->ipv6.u6_addr.u6_addr32[1] != 0 || ip->ipv6.u6_addr.u6_addr32[2] != 0 || ip->ipv6.u6_addr.u6_addr32[3] != 0); #else return(0); #endif } /* ********************************************************************************* */ char *ndpi_get_ip_string(const ndpi_ip_addr_t * ip, char *buf, u_int buf_len) { const u_int8_t *a = (const u_int8_t *) &ip->ipv4; #ifdef NDPI_DETECTION_SUPPORT_IPV6 if(ndpi_is_ipv6(ip)) { if(inet_ntop(AF_INET6, &ip->ipv6.u6_addr, buf, buf_len) == NULL) buf[0] = '\0'; return(buf); } #endif snprintf(buf, buf_len, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); return(buf); } /* ****************************************************** */ /* Returns -1 on failutre, otherwise fills parsed_ip and returns the IP version */ int ndpi_parse_ip_string(const char *ip_str, ndpi_ip_addr_t *parsed_ip) { int rv = -1; memset(parsed_ip, 0, sizeof(*parsed_ip)); if(strchr(ip_str, '.')) { if(inet_pton(AF_INET, ip_str, &parsed_ip->ipv4) > 0) rv = 4; #ifdef NDPI_DETECTION_SUPPORT_IPV6 } else { if(inet_pton(AF_INET6, ip_str, &parsed_ip->ipv6) > 0) rv = 6; #endif } return(rv); } /* ****************************************************** */ u_int16_t ntohs_ndpi_bytestream_to_number(const u_int8_t * str, u_int16_t max_chars_to_read, u_int16_t * bytes_read) { u_int16_t val = ndpi_bytestream_to_number(str, max_chars_to_read, bytes_read); return(ntohs(val)); } /* ****************************************************** */ u_int8_t ndpi_is_proto(ndpi_protocol proto, u_int16_t p) { return(((proto.app_protocol == p) || (proto.master_protocol == p)) ? 1 : 0); } /* ****************************************************** */ u_int16_t ndpi_get_lower_proto(ndpi_protocol proto) { return((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) ? proto.master_protocol : proto.app_protocol); } /* ****************************************************** */ ndpi_protocol ndpi_guess_undetected_protocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, u_int8_t proto, u_int32_t shost /* host byte order */, u_int16_t sport, u_int32_t dhost /* host byte order */, u_int16_t dport) { u_int32_t rc; struct in_addr addr; ndpi_protocol ret = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED }; u_int8_t user_defined_proto; if((proto == IPPROTO_TCP) || (proto == IPPROTO_UDP)) { rc = ndpi_search_tcp_or_udp_raw(ndpi_str, flow, proto, shost, dhost, sport, dport); if(rc != NDPI_PROTOCOL_UNKNOWN) { if(flow && (proto == IPPROTO_UDP) && NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, rc) && is_udp_guessable_protocol(rc)) ; else { ret.app_protocol = rc, ret.master_protocol = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); if(ret.app_protocol == ret.master_protocol) ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; ret.category = ndpi_get_proto_category(ndpi_str, ret); return(ret); } } rc = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); if(rc != NDPI_PROTOCOL_UNKNOWN) { if(flow && (proto == IPPROTO_UDP) && NDPI_COMPARE_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, rc) && is_udp_guessable_protocol(rc)) ; else { ret.app_protocol = rc; if(rc == NDPI_PROTOCOL_TLS) goto check_guessed_skype; else { ret.category = ndpi_get_proto_category(ndpi_str, ret); return(ret); } } } check_guessed_skype: addr.s_addr = htonl(shost); if(ndpi_network_ptree_match(ndpi_str, &addr) == NDPI_PROTOCOL_SKYPE) { ret.app_protocol = NDPI_PROTOCOL_SKYPE; } else { addr.s_addr = htonl(dhost); if(ndpi_network_ptree_match(ndpi_str, &addr) == NDPI_PROTOCOL_SKYPE) ret.app_protocol = NDPI_PROTOCOL_SKYPE; } } else ret.app_protocol = ndpi_guess_protocol_id(ndpi_str, flow, proto, sport, dport, &user_defined_proto); ret.category = ndpi_get_proto_category(ndpi_str, ret); return(ret); } /* ****************************************************** */ char* ndpi_protocol2id(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol proto, char *buf, u_int buf_len) { if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (proto.master_protocol != proto.app_protocol)) { if(proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) snprintf(buf, buf_len, "%u.%u", proto.master_protocol, proto.app_protocol); else snprintf(buf, buf_len, "%u", proto.master_protocol); } else snprintf(buf, buf_len, "%u", proto.app_protocol); return(buf); } /* ****************************************************** */ char* ndpi_protocol2name(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol proto, char *buf, u_int buf_len) { if((proto.master_protocol != NDPI_PROTOCOL_UNKNOWN) && (proto.master_protocol != proto.app_protocol)) { if(proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) snprintf(buf, buf_len, "%s.%s", ndpi_get_proto_name(ndpi_str, proto.master_protocol), ndpi_get_proto_name(ndpi_str, proto.app_protocol)); else snprintf(buf, buf_len, "%s", ndpi_get_proto_name(ndpi_str, proto.master_protocol)); } else snprintf(buf, buf_len, "%s", ndpi_get_proto_name(ndpi_str, proto.app_protocol)); return(buf); } /* ****************************************************** */ int ndpi_is_custom_category(ndpi_protocol_category_t category) { switch(category) { case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: return(1); break; default: return(0); break; } } /* ****************************************************** */ void ndpi_category_set_name(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol_category_t category, char *name) { if(!name) return; switch(category) { case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: snprintf(ndpi_str->custom_category_labels[0], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); break; case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: snprintf(ndpi_str->custom_category_labels[1], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); break; case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: snprintf(ndpi_str->custom_category_labels[2], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); break; case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: snprintf(ndpi_str->custom_category_labels[3], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); break; case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: snprintf(ndpi_str->custom_category_labels[4], CUSTOM_CATEGORY_LABEL_LEN, "%s", name); break; default: break; } } /* ****************************************************** */ const char* ndpi_category_get_name(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol_category_t category) { if((!ndpi_str) || (category >= NDPI_PROTOCOL_NUM_CATEGORIES)) { static char b[24]; if(!ndpi_str) snprintf(b, sizeof(b), "NULL nDPI"); else snprintf(b, sizeof(b), "Invalid category %d", (int)category); return(b); } if((category >= NDPI_PROTOCOL_CATEGORY_CUSTOM_1) && (category <= NDPI_PROTOCOL_CATEGORY_CUSTOM_5)) { switch(category) { case NDPI_PROTOCOL_CATEGORY_CUSTOM_1: return(ndpi_str->custom_category_labels[0]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_2: return(ndpi_str->custom_category_labels[1]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_3: return(ndpi_str->custom_category_labels[2]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_4: return(ndpi_str->custom_category_labels[3]); case NDPI_PROTOCOL_CATEGORY_CUSTOM_5: return(ndpi_str->custom_category_labels[4]); case NDPI_PROTOCOL_NUM_CATEGORIES: return("Code should not use this internal constant"); default: return("Unspecified"); } } else return(categories[category]); } /* ****************************************************** */ ndpi_protocol_category_t ndpi_get_proto_category(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol proto) { if(proto.category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) return(proto.category); /* simple rule: sub protocol first, master after */ else if((proto.master_protocol == NDPI_PROTOCOL_UNKNOWN) || (ndpi_str->proto_defaults[proto.app_protocol].protoCategory != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)) return(ndpi_str->proto_defaults[proto.app_protocol].protoCategory); else return(ndpi_str->proto_defaults[proto.master_protocol].protoCategory); } /* ****************************************************** */ char* ndpi_get_proto_name(struct ndpi_detection_module_struct *ndpi_str, u_int16_t proto_id) { if((proto_id >= ndpi_str->ndpi_num_supported_protocols) || (proto_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) || (ndpi_str->proto_defaults[proto_id].protoName == NULL)) proto_id = NDPI_PROTOCOL_UNKNOWN; return(ndpi_str->proto_defaults[proto_id].protoName); } /* ****************************************************** */ ndpi_protocol_breed_t ndpi_get_proto_breed(struct ndpi_detection_module_struct *ndpi_str, u_int16_t proto_id) { if((proto_id >= ndpi_str->ndpi_num_supported_protocols) || (proto_id >= (NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) || (ndpi_str->proto_defaults[proto_id].protoName == NULL)) proto_id = NDPI_PROTOCOL_UNKNOWN; return(ndpi_str->proto_defaults[proto_id].protoBreed); } /* ****************************************************** */ char* ndpi_get_proto_breed_name(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol_breed_t breed_id) { switch(breed_id) { case NDPI_PROTOCOL_SAFE: return("Safe"); break; case NDPI_PROTOCOL_ACCEPTABLE: return("Acceptable"); break; case NDPI_PROTOCOL_FUN: return("Fun"); break; case NDPI_PROTOCOL_UNSAFE: return("Unsafe"); break; case NDPI_PROTOCOL_POTENTIALLY_DANGEROUS: return("Potentially Dangerous"); break; case NDPI_PROTOCOL_DANGEROUS: return("Dangerous"); break; case NDPI_PROTOCOL_UNRATED: default: return("Unrated"); break; } } /* ****************************************************** */ int ndpi_get_protocol_id(struct ndpi_detection_module_struct *ndpi_str, char *proto) { int i; for(i=0; i<(int)ndpi_str->ndpi_num_supported_protocols; i++) if(strcasecmp(proto, ndpi_str->proto_defaults[i].protoName) == 0) return(i); return(-1); } /* ****************************************************** */ int ndpi_get_category_id(struct ndpi_detection_module_struct *ndpi_str, char *cat) { int i; for(i = 0; i < NDPI_PROTOCOL_NUM_CATEGORIES; i++) { const char *name = ndpi_category_get_name(ndpi_str, i); if(strcasecmp(cat, name) == 0) return(i); } return(-1); } /* ****************************************************** */ void ndpi_dump_protocols(struct ndpi_detection_module_struct *ndpi_str) { int i; for(i=0; i<(int)ndpi_str->ndpi_num_supported_protocols; i++) printf("%3d %-22s %-8s %-12s %s\n", i, ndpi_str->proto_defaults[i].protoName, ndpi_get_l4_proto_name(ndpi_get_l4_proto_info(ndpi_str, i)), ndpi_get_proto_breed_name(ndpi_str, ndpi_str->proto_defaults[i].protoBreed), ndpi_category_get_name(ndpi_str, ndpi_str->proto_defaults[i].protoCategory) ); } /* ****************************************************** */ /* * Find the first occurrence of find in s, where the search is limited to the * first slen characters of s. */ char* ndpi_strnstr(const char *s, const char *find, size_t slen) { char c; size_t len; if((c = *find++) != '\0') { len = strnlen(find, slen); do { char sc; do { if(slen-- < 1 || (sc = *s++) == '\0') return(NULL); } while(sc != c); if(len > slen) return(NULL); } while(strncmp(s, find, len) != 0); s--; } return((char *)s); } /* ****************************************************** */ /* * Same as ndpi_strnstr but case-insensitive */ char* ndpi_strncasestr(const char *s, const char *find, size_t slen) { char c; size_t len; if((c = *find++) != '\0') { len = strlen(find); do { char sc; do { if(slen-- < 1 || (sc = *s++) == '\0') return(NULL); } while(sc != c); if(len > slen) return(NULL); } while(strncasecmp(s, find, len) != 0); s--; } return((char *)s); } /* ****************************************************** */ int ndpi_match_prefix(const u_int8_t *payload, size_t payload_len, const char *str, size_t str_len) { int rc = str_len <= payload_len ? memcmp(payload, str, str_len) == 0 : 0; return(rc); } /* ****************************************************** */ int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_str, char *string_to_match, u_int string_to_match_len, ndpi_protocol_match_result *ret_match, u_int8_t is_host_match) { AC_TEXT_t ac_input_text; ndpi_automa *automa = is_host_match ? &ndpi_str->host_automa : &ndpi_str->content_automa; AC_REP_t match = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED }; if((automa->ac_automa == NULL) || (string_to_match_len == 0)) return(NDPI_PROTOCOL_UNKNOWN); if(!automa->ac_automa_finalized) { printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initalization()\n", __FILE__, __LINE__); return(0); /* No matches */ } ac_input_text.astring = string_to_match, ac_input_text.length = string_to_match_len; ac_automata_search(((AC_AUTOMATA_t*)automa->ac_automa), &ac_input_text, &match); /* We need to take into account also rc==0 that is used for partial matches */ ret_match->protocol_id = match.number, ret_match->protocol_category = match.category, ret_match->protocol_breed = match.breed; return(match.number); } #ifdef HAVE_HYPERSCAN /* ******************************************************************** */ static int hyperscanEventHandler(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *ctx) { *((int *)ctx) = (int)id; NDPI_LOG_DBG2(ndpi_str, "[NDPI] Match with: %d [from: %llu][to: %llu]\n", id, from, to); /* return HS_SCAN_TERMINATED; */ return(0); /* keep searching */ } #endif /* **************************************** */ static u_int8_t ndpi_is_more_generic_protocol(u_int16_t previous_proto, u_int16_t new_proto) { /* Sometimes certificates are more generic than previously identified protocols */ if((previous_proto == NDPI_PROTOCOL_UNKNOWN) || (previous_proto == new_proto)) return(0); switch(previous_proto) { case NDPI_PROTOCOL_WHATSAPP_CALL: case NDPI_PROTOCOL_WHATSAPP_FILES: if(new_proto == NDPI_PROTOCOL_WHATSAPP) return(1); } return(0); } /* ****************************************************** */ static u_int16_t ndpi_automa_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, u_int16_t master_protocol_id, ndpi_protocol_match_result *ret_match, u_int8_t is_host_match) { int matching_protocol_id; struct ndpi_packet_struct *packet = &flow->packet; #ifndef HAVE_HYPERSCAN matching_protocol_id = ndpi_match_string_subprotocol(ndpi_str, string_to_match, string_to_match_len, ret_match, is_host_match); #else struct hs *hs = (struct hs*)ndpi_str->hyperscan; hs_error_t status; matching_protocol_id = NDPI_PROTOCOL_UNKNOWN; /* TODO HYPERSCAN In case of match fill up ret_match and set flow protocol + category */ status = hs_scan(hs->database, string_to_match, string_to_match_len, 0, hs->scratch, hyperscanEventHandler, &matching_protocol_id); if(status == HS_SUCCESS) { NDPI_LOG_DBG2(ndpi_str, "[NDPI] Hyperscan engine completed normally. Result: %s [%d][%s]\n", ndpi_get_proto_name(ndpi_str, matching_protocol_id), matching_protocol_id, string_to_match); } else if(status == HS_SCAN_TERMINATED) { NDPI_LOG_DBG2(ndpi_str, "[NDPI] Hyperscan engine was terminated by callback. Result: %s [%d][%s]\n", ndpi_get_proto_name(ndpi_str, matching_protocol_id), matching_protocol_id, string_to_match); } else { NDPI_LOG_DBG2(ndpi_str, "[NDPI] Hyperscan returned with error.\n"); } ret_match->protocol_id = matching_protocol_id, ret_match->protocol_category = ndpi_str->proto_defaults[matching_protocol_id].protoCategory, ret_match->protocol_breed = ndpi_str->proto_defaults[matching_protocol_id].protoBreed; #endif #ifdef DEBUG { char m[256]; int len = ndpi_min(sizeof(m), string_to_match_len); strncpy(m, string_to_match, len); m[len] = '\0'; NDPI_LOG_DBG2(ndpi_str, "[NDPI] ndpi_match_host_subprotocol(%s): %s\n", m, ndpi_str->proto_defaults[matching_protocol_id].protoName); } #endif if((matching_protocol_id != NDPI_PROTOCOL_UNKNOWN) && (!ndpi_is_more_generic_protocol(packet->detected_protocol_stack[0], matching_protocol_id))) { /* Move the protocol on slot 0 down one position */ packet->detected_protocol_stack[1] = master_protocol_id, packet->detected_protocol_stack[0] = matching_protocol_id; flow->detected_protocol_stack[0] = packet->detected_protocol_stack[0], flow->detected_protocol_stack[1] = packet->detected_protocol_stack[1]; if(flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) flow->category = ret_match->protocol_category; return(packet->detected_protocol_stack[0]); } #ifdef DEBUG string_to_match[string_to_match_len] = '\0'; NDPI_LOG_DBG2(ndpi_str, "[NTOP] Unable to find a match for '%s'\n", string_to_match); #endif ret_match->protocol_id = NDPI_PROTOCOL_UNKNOWN, ret_match->protocol_category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, ret_match->protocol_breed = NDPI_PROTOCOL_UNRATED; return(NDPI_PROTOCOL_UNKNOWN); } /* ****************************************************** */ u_int16_t ndpi_match_host_subprotocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, ndpi_protocol_match_result *ret_match, u_int16_t master_protocol_id) { u_int16_t rc = ndpi_automa_match_string_subprotocol(ndpi_str, flow, string_to_match, string_to_match_len, master_protocol_id, ret_match, 1); if((flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) && (ret_match->protocol_category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)) { unsigned long id = ret_match->protocol_category; if(ndpi_get_custom_category_match(ndpi_str, string_to_match, string_to_match_len, &id) != -1) { if(id != -1) { flow->category = ret_match->protocol_category = id; rc = master_protocol_id; } } } return(rc); } /* ****************************************************** */ u_int16_t ndpi_match_content_subprotocol(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, char *string_to_match, u_int string_to_match_len, ndpi_protocol_match_result *ret_match, u_int16_t master_protocol_id) { return(ndpi_automa_match_string_subprotocol(ndpi_str, flow, string_to_match, string_to_match_len, master_protocol_id, ret_match, 0)); } /* ****************************************************** */ int ndpi_match_bigram(struct ndpi_detection_module_struct *ndpi_str, ndpi_automa *automa, char *bigram_to_match) { AC_TEXT_t ac_input_text; AC_REP_t match = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NDPI_PROTOCOL_UNRATED }; int rc; if((automa->ac_automa == NULL) || (bigram_to_match == NULL)) return(-1); if(!automa->ac_automa_finalized) { printf("[%s:%d] [NDPI] Internal error: please call ndpi_finalize_initalization()\n", __FILE__, __LINE__); return(0); /* No matches */ } ac_input_text.astring = bigram_to_match, ac_input_text.length = 2; rc = ac_automata_search(((AC_AUTOMATA_t*)automa->ac_automa), &ac_input_text, &match); /* As ac_automata_search can detect partial matches and continue the search process in case rc == 0 (i.e. no match), we need to check if there is a partial match and in this case return it */ if((rc == 0) && (match.number != 0)) rc = 1; return(rc ? match.number : 0); } /* ****************************************************** */ void ndpi_free_flow(struct ndpi_flow_struct *flow) { if(flow) { if(flow->http.url) ndpi_free(flow->http.url); if(flow->http.content_type) ndpi_free(flow->http.content_type); if(flow->http.user_agent) ndpi_free(flow->http.user_agent); if(flow->l4_proto == IPPROTO_TCP) { if(flow->l4.tcp.tls_srv_cert_fingerprint_ctx) ndpi_free(flow->l4.tcp.tls_srv_cert_fingerprint_ctx); } ndpi_free(flow); } } /* ****************************************************** */ char* ndpi_revision() { return(NDPI_GIT_RELEASE); } /* ****************************************************** */ #ifdef WIN32 /* https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ int gettimeofday(struct timeval * tp, struct timezone * tzp) { // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) // until 00:00:00 January 1, 1970 static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); SYSTEMTIME system_time; FILETIME file_time; uint64_t time; GetSystemTime( &system_time ); SystemTimeToFileTime( &system_time, &file_time ); time = ((uint64_t)file_time.dwLowDateTime ) ; time += ((uint64_t)file_time.dwHighDateTime) << 32; tp->tv_sec = (long) ((time - EPOCH) / 10000000L); tp->tv_usec = (long) (system_time.wMilliseconds * 1000); return(0); } #endif int NDPI_BITMASK_COMPARE(NDPI_PROTOCOL_BITMASK a, NDPI_PROTOCOL_BITMASK b) { int i; for(i=0; iproto_defaults); } u_int ndpi_get_ndpi_num_supported_protocols(struct ndpi_detection_module_struct *ndpi_str) { return(ndpi_str->ndpi_num_supported_protocols); } u_int ndpi_get_ndpi_num_custom_protocols(struct ndpi_detection_module_struct *ndpi_str) { return(ndpi_str->ndpi_num_custom_protocols); } u_int ndpi_get_ndpi_detection_module_size() { return(sizeof(struct ndpi_detection_module_struct)); } void ndpi_set_log_level(struct ndpi_detection_module_struct *ndpi_str, u_int l) { ndpi_str->ndpi_log_level = l; } /* ******************************************************************** */ /* LRU cache */ struct ndpi_lru_cache* ndpi_lru_cache_init(u_int32_t num_entries) { struct ndpi_lru_cache *c = (struct ndpi_lru_cache*)ndpi_malloc(sizeof(struct ndpi_lru_cache)); if(!c) return(NULL); c->entries = (struct ndpi_lru_cache_entry*)ndpi_calloc(num_entries, sizeof(struct ndpi_lru_cache_entry)); if(!c->entries) { ndpi_free(c); return(NULL); } else c->num_entries = num_entries; return(c); } void ndpi_lru_free_cache(struct ndpi_lru_cache *c) { ndpi_free(c->entries); ndpi_free(c); } u_int8_t ndpi_lru_find_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t *value, u_int8_t clean_key_when_found) { u_int32_t slot = key % c->num_entries; if(c->entries[slot].is_full) { *value = c->entries[slot].value; if(clean_key_when_found) c->entries[slot].is_full = 0; return(1); } else return(0); } void ndpi_lru_add_to_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t value) { u_int32_t slot = key % c->num_entries; c->entries[slot].is_full = 1, c->entries[slot].key = key, c->entries[slot].value = value; } /* ******************************************************************** */ /* NOTE: - Leave fields empty/zero when information is missing (e.g. with ICMP ports are zero) - The hash_buf most be 30+1 bits or longer - Return code: 0 = OK, -1 otherwise */ int ndpi_flowv4_flow_hash(u_int8_t l4_proto, u_int32_t src_ip, u_int32_t dst_ip, u_int16_t src_port, u_int16_t dst_port, u_int8_t icmp_type, u_int8_t icmp_code, u_char *hash_buf, u_int8_t hash_buf_len) { return(0); /* OK */ } int ndpi_flowv6_flow_hash(u_int8_t l4_proto, struct ndpi_in6_addr *src_ip, struct ndpi_in6_addr *dst_ip, u_int16_t src_port, u_int16_t dst_port, u_int8_t icmp_type, u_int8_t icmp_code, u_char *hash_buf, u_int8_t hash_buf_len) { return(0); /* OK */ } /* ******************************************************************** */ /* This function tells if it's possible to further dissect a given flow 0 - All possible dissection has been completed 1 - Additional dissection is possible */ u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { u_int16_t proto = flow->detected_protocol_stack[1] ? flow->detected_protocol_stack[1] : flow->detected_protocol_stack[0]; #if 0 printf("[DEBUG] %s(%u.%u): %u\n", __FUNCTION__, flow->detected_protocol_stack[0], flow->detected_protocol_stack[1], proto); #endif switch(proto) { case NDPI_PROTOCOL_TLS: if(!flow->l4.tcp.tls_srv_cert_fingerprint_processed) return(1); break; case NDPI_PROTOCOL_HTTP: if((flow->host_server_name[0] == '\0') || (flow->http.response_status_code == 0)) return(1); break; case NDPI_PROTOCOL_DNS: if(flow->protos.dns.num_answers == 0) return(1); break; case NDPI_PROTOCOL_FTP_CONTROL: case NDPI_PROTOCOL_MAIL_POP: case NDPI_PROTOCOL_MAIL_IMAP: case NDPI_PROTOCOL_MAIL_SMTP: if(flow->protos.ftp_imap_pop_smtp.password[0] == '\0') return(1); break; case NDPI_PROTOCOL_SSH: if((flow->protos.ssh.hassh_client[0] == '\0') || (flow->protos.ssh.hassh_server[0] == '\0')) return(1); break; case NDPI_PROTOCOL_TELNET: if(!flow->protos.telnet.username_detected) return(1); break; } return(0); } /* ******************************************************************** */ const char* ndpi_get_l4_proto_name(ndpi_l4_proto_info proto) { switch(proto) { case ndpi_l4_proto_unknown: return(""); break; case ndpi_l4_proto_tcp_only: return("TCP"); break; case ndpi_l4_proto_udp_only: return("UDP"); break; case ndpi_l4_proto_tcp_and_udp: return("TCP/UDP"); break; } return(""); } /* ******************************************************************** */ ndpi_l4_proto_info ndpi_get_l4_proto_info(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t ndpi_proto_id) { if(ndpi_proto_id < ndpi_struct->ndpi_num_supported_protocols) { u_int16_t idx = ndpi_struct->proto_defaults[ndpi_proto_id].protoIdx; NDPI_SELECTION_BITMASK_PROTOCOL_SIZE bm = ndpi_struct->callback_buffer[idx].ndpi_selection_bitmask; if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP) return(ndpi_l4_proto_tcp_only); else if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_UDP) return(ndpi_l4_proto_udp_only); else if(bm & NDPI_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP) return(ndpi_l4_proto_tcp_and_udp); } return(ndpi_l4_proto_unknown); /* default */ } /* ******************************************************************** */ ndpi_ptree_t* ndpi_ptree_create(void) { ndpi_ptree_t *tree = (ndpi_ptree_t*) ndpi_malloc(sizeof(ndpi_ptree_t)); if(tree) { tree->v4 = ndpi_New_Patricia(32); tree->v6 = ndpi_New_Patricia(128); if((!tree->v4) || (!tree->v6)) { ndpi_ptree_destroy(tree); return(NULL); } } return(tree); } /* ******************************************************************** */ void ndpi_ptree_destroy(ndpi_ptree_t *tree) { if(tree) { if(tree->v4) ndpi_Destroy_Patricia(tree->v4, free_ptree_data); if(tree->v6) ndpi_Destroy_Patricia(tree->v6, free_ptree_data); ndpi_free(tree); } } /* ******************************************************************** */ int ndpi_ptree_insert(ndpi_ptree_t *tree, const ndpi_ip_addr_t *addr, u_int8_t bits, uint user_data) { u_int8_t is_v6 = ndpi_is_ipv6(addr); patricia_tree_t *ptree = is_v6 ? tree->v6 : tree->v4; prefix_t prefix; patricia_node_t *node; if(bits > ptree->maxbits) return(-1); if(is_v6) fill_prefix_v6(&prefix, (const struct in6_addr*)&addr->ipv6, bits, ptree->maxbits); else fill_prefix_v4(&prefix, (const struct in_addr*)&addr->ipv4, bits, ptree->maxbits); /* Verify that the node does not already exist */ node = ndpi_patricia_search_best(ptree, &prefix); if(node && (node->prefix->bitlen == bits)) return(-2); node = ndpi_patricia_lookup(ptree, &prefix); if(node != NULL) { node->value.user_value = user_data; return(0); } return(-3); } /* ******************************************************************** */ int ndpi_ptree_match_addr(ndpi_ptree_t *tree, const ndpi_ip_addr_t *addr, uint *user_data) { u_int8_t is_v6 = ndpi_is_ipv6(addr); patricia_tree_t *ptree = is_v6 ? tree->v6 : tree->v4; prefix_t prefix; patricia_node_t *node; int bits = ptree->maxbits; if(is_v6) fill_prefix_v6(&prefix, (const struct in6_addr*)&addr->ipv6, bits, ptree->maxbits); else fill_prefix_v4(&prefix, (const struct in_addr*)&addr->ipv4, bits, ptree->maxbits); node = ndpi_patricia_search_best(ptree, &prefix); if(node) { *user_data = node->value.user_value; return(0); } return(-1); }