diff options
-rw-r--r-- | example/ndpiReader.c | 20 | ||||
-rw-r--r-- | example/ndpi_util.c | 26 | ||||
-rw-r--r-- | src/include/ndpi_protocol_ids.h | 2 | ||||
-rw-r--r-- | src/lib/ndpi_content_match.c.inc | 1 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 4 | ||||
-rw-r--r-- | src/lib/protocols/btlib.c | 10 | ||||
-rw-r--r-- | src/lib/protocols/memcached.c | 160 | ||||
-rw-r--r-- | src/lib/protocols/openvpn.c | 69 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 191 | ||||
-rw-r--r-- | src/lib/protocols/viber.c | 2 |
10 files changed, 275 insertions, 210 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 25886af31..8551992bf 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -18,9 +18,7 @@ * */ -#ifdef HAVE_CONFIG_H #include "ndpi_config.h" -#endif #ifdef linux #define _GNU_SOURCE @@ -899,8 +897,8 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa if(flow->ssh_ssl.ja3_client[0] != '\0') json_object_object_add(jObj,"ja3c",json_object_new_string(flow->ssh_ssl.ja3_client)); - if(flow->ja3_server[0] != '\0') - json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ja3_server)); + if(flow->ssh_ssl.ja3_server[0] != '\0') + json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ssh_ssl.ja3_server)); if(flow->ssh_ssl.client_info[0] != '\0') json_object_object_add(sjObj, "client", json_object_new_string(flow->ssh_ssl.client_info)); @@ -1440,6 +1438,7 @@ static void node_idle_scan_walker(const void *node, ndpi_VISIT which, int depth, } } +/* *********************************************** */ /** * @brief On Protocol Discover - demo callback @@ -1450,6 +1449,8 @@ static void on_protocol_discovered(struct ndpi_workflow * workflow, ; } +/* *********************************************** */ + #if 0 /** * @brief Print debug @@ -1457,7 +1458,6 @@ static void on_protocol_discovered(struct ndpi_workflow * workflow, static void debug_printf(u_int32_t protocol, void *id_struct, ndpi_log_level_t log_level, const char *format, ...) { - va_list va_ap; #ifndef WIN32 struct tm result; @@ -1491,6 +1491,8 @@ static void debug_printf(u_int32_t protocol, void *id_struct, } #endif +/* *********************************************** */ + /** * @brief Setup for detection begin */ @@ -1578,6 +1580,7 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) { } } +/* *********************************************** */ /** * @brief End of detection and free flow @@ -1586,6 +1589,7 @@ static void terminateDetection(u_int16_t thread_id) { ndpi_workflow_free(ndpi_thread_info[thread_id].workflow); } +/* *********************************************** */ /** * @brief Traffic stats format @@ -1622,6 +1626,7 @@ char* formatTraffic(float numBits, int bits, char *buf) { return(buf); } +/* *********************************************** */ /** * @brief Packets stats format @@ -1640,6 +1645,7 @@ char* formatPackets(float numPkts, char *buf) { return(buf); } +/* *********************************************** */ /** * @brief JSON function init @@ -1651,6 +1657,8 @@ static void json_init() { jArray_topStats = json_object_new_array(); } +/* *********************************************** */ + static void json_open_stats_file() { if((file_first_time && ((stats_fp = fopen(_statsFilePath,"w")) == NULL)) || @@ -1661,6 +1669,8 @@ static void json_open_stats_file() { else file_first_time = 0; } +/* *********************************************** */ + static void json_close_stats_file() { json_object *jObjFinal = json_object_new_object(); diff --git a/example/ndpi_util.c b/example/ndpi_util.c index c8e0130ff..e453a3461 100644 --- a/example/ndpi_util.c +++ b/example/ndpi_util.c @@ -246,21 +246,21 @@ int ndpi_workflow_node_cmp(const void *a, const void *b) { if( ( - (fa->src_ip == fb->src_ip ) - && (fa->src_port == fb->src_port) - && (fa->dst_ip == fb->dst_ip ) - && (fa->dst_port == fb->dst_port) - ) + (fa->src_ip == fb->src_ip ) + && (fa->src_port == fb->src_port) + && (fa->dst_ip == fb->dst_ip ) + && (fa->dst_port == fb->dst_port) + ) || ( - (fa->src_ip == fb->dst_ip ) - && (fa->src_port == fb->dst_port) - && (fa->dst_ip == fb->src_ip ) - && (fa->dst_port == fb->src_port) - ) - ) + (fa->src_ip == fb->dst_ip ) + && (fa->src_port == fb->dst_port) + && (fa->dst_ip == fb->src_ip ) + && (fa->dst_port == fb->src_port) + ) + ) return(0); - + if(fa->src_ip < fb->src_ip ) return(-1); else { if(fa->src_ip > fb->src_ip ) return(1); } if(fa->src_port < fb->src_port) return(-1); else { if(fa->src_port > fb->src_port) return(1); } if(fa->dst_ip < fb->dst_ip ) return(-1); else { if(fa->dst_ip > fb->dst_ip ) return(1); } @@ -376,10 +376,10 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow flow.src_ip = iph->saddr, flow.dst_ip = iph->daddr; flow.src_port = htons(*sport), flow.dst_port = htons(*dport); flow.hashval = hashval = flow.protocol + flow.vlan_id + flow.src_ip + flow.dst_ip + flow.src_port + flow.dst_port; + /* printf("hashval=%u [%u][%u][%u:%u][%u:%u]\n", hashval, flow.protocol, flow.vlan_id, flow.src_ip, flow.src_port, flow.dst_ip, flow.dst_port); */ idx = hashval % workflow->prefs.num_roots; ret = ndpi_tfind(&flow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp); - /* to avoid two nodes in one binary tree for a flow */ int is_changed = 0; if(ret == NULL) { diff --git a/src/include/ndpi_protocol_ids.h b/src/include/ndpi_protocol_ids.h index 7e2f55711..b8b77ada4 100644 --- a/src/include/ndpi_protocol_ids.h +++ b/src/include/ndpi_protocol_ids.h @@ -79,8 +79,8 @@ typedef enum { NDPI_PROTOCOL_MINING = 42, /* Bitcoin, Ethereum, ZCash, Monero */ NDPI_PROTOCOL_NEST_LOG_SINK = 43, /* Nest Log Sink (Nest Protect) - Darryl Sokoloski <darryl@egloo.ca> */ NDPI_PROTOCOL_MODBUS = 44, /* Modbus */ + NDPI_PROTOCOL_WHATSAPP_VIDEO = 45, - NDPI_PROTOCOL_FREE_45 = 45, /* Free */ NDPI_PROTOCOL_FREE_46 = 46, /* Free */ NDPI_PROTOCOL_XBOX = 47, diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc index 730050a2e..a58d80e25 100644 --- a/src/lib/ndpi_content_match.c.inc +++ b/src/lib/ndpi_content_match.c.inc @@ -8485,6 +8485,7 @@ ndpi_protocol_match host_match[] = { { "audio-fa.scdn.co", NULL, "audio-fa\\.scdn" TLD, "Spotify", NDPI_PROTOCOL_SPOTIFY, NDPI_PROTOCOL_CATEGORY_MUSIC, NDPI_PROTOCOL_FUN }, { "edge-mqtt.facebook.com", NULL, "edge-mqtt\\.facebook" TLD, "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_FUN }, + { "mqtt-mini.facebook.com", NULL, "mqtt-mini\\.facebook" TLD, "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_FUN }, /* Messenger Lite */ { "messenger.com", NULL, "messenger\\.com" TLD, "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_FUN }, { ".pandora.com", NULL, "\\.pandora" TLD, "Pandora", NDPI_PROTOCOL_PANDORA, NDPI_PROTOCOL_CATEGORY_STREAMING, NDPI_PROTOCOL_FUN }, diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 85fed4d0c..bf9c4069e 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -983,9 +983,9 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp 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_mod, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_FREE_45, + ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP_VIDEO, 0 /* can_have_a_subprotocol */, no_master, - no_master, "Free", NDPI_PROTOCOL_CATEGORY_CUSTOM_1 /* dummy */, + no_master, "WhatsAppVideo", 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_mod, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_FREE_46, diff --git a/src/lib/protocols/btlib.c b/src/lib/protocols/btlib.c index ea06a6348..309a10717 100644 --- a/src/lib/protocols/btlib.c +++ b/src/lib/protocols/btlib.c @@ -64,7 +64,8 @@ static char *print20b(char *s,const u_int8_t *b) { } static char *print_id_ip_p(char *s, const struct bt_nodes_data *b) { - u_int8_t *p = (void*)b; + u_int8_t *p = (u_int8_t*)b; + print20b(s,b->id); snprintf(s+40,39," %d.%d.%d.%d:%u", p[20], p[21], p[22], p[23], htons(b->port)); @@ -72,14 +73,16 @@ static char *print_id_ip_p(char *s, const struct bt_nodes_data *b) { } static char *print_ip_p(char *s, const struct bt_ipv4p *b,int np) { - const u_int8_t *p = (const void*)b; + const u_int8_t *p = (const u_int8_t*)b; + snprintf(s,39,!np ? "%d.%d.%d.%d:%u":"%d.%d.%d.%d", p[0], p[1], p[2], p[3], htons(b->port)); return s; } static char *print_ip6_p(char *s, const struct bt_ipv6p *b,int np) { - u_int16_t *p = (void*)b; + u_int16_t *p = (u_int16_t*)b; + snprintf(s,79,!np ? "%x:%x:%x:%x:%x:%x:%x:%x.%u":"%x:%x:%x:%x:%x:%x:%x:%x", htons(p[0]), htons(p[1]), htons(p[2]), htons(p[3]), htons(p[4]), htons(p[5]), htons(p[6]), htons(p[7]), @@ -507,6 +510,7 @@ const u_int8_t *bt_decode(const u_int8_t *b, size_t *l, int *ret, bt_parse_data_ cbd->level--; return b; } + bad_data: *ret=-1; return b; diff --git a/src/lib/protocols/memcached.c b/src/lib/protocols/memcached.c index 44a8b0858..e527688ba 100644 --- a/src/lib/protocols/memcached.c +++ b/src/lib/protocols/memcached.c @@ -92,99 +92,99 @@ #define MEMCACHED_MATCH(cr) (cr ## _LEN > length || memcmp(offset, cr, cr ## _LEN)) static void ndpi_int_memcached_add_connection(struct ndpi_detection_module_struct - *ndpi_struct, struct ndpi_flow_struct *flow) + *ndpi_struct, struct ndpi_flow_struct *flow) { - NDPI_LOG_INFO(ndpi_struct, "found memcached\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, - NDPI_PROTOCOL_MEMCACHED, NDPI_PROTOCOL_UNKNOWN); + NDPI_LOG_INFO(ndpi_struct, "found memcached\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, + NDPI_PROTOCOL_MEMCACHED, NDPI_PROTOCOL_UNKNOWN); } void ndpi_search_memcached( - struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow) + struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { - struct ndpi_packet_struct *packet = &flow->packet; - const u_int8_t *offset = packet->payload; - const u_int16_t length = packet->payload_packet_len; - u_int8_t *matches; + struct ndpi_packet_struct *packet = &flow->packet; + const u_int8_t *offset = packet->payload; + const u_int16_t length = packet->payload_packet_len; + u_int8_t *matches; - NDPI_LOG_DBG(ndpi_struct, "search memcached\n"); + NDPI_LOG_DBG(ndpi_struct, "search memcached\n"); - if (packet->tcp != NULL) { - if (packet->payload_packet_len < MEMCACHED_MIN_LEN) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; - } - - matches = &flow->l4.tcp.memcached_matches; + if (packet->tcp != NULL) { + if (packet->payload_packet_len < MEMCACHED_MIN_LEN) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; } - else if (packet->udp != NULL) { - if (packet->payload_packet_len < MEMCACHED_MIN_UDP_LEN) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; - } - - if ((offset[4] == 0x00 && offset[5] == 0x00) || - offset[6] != 0x00 || offset[7] != 0x00) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; - } - - offset += MEMCACHED_UDP_HDR_LEN; - matches = &flow->l4.udp.memcached_matches; + + matches = &flow->l4.tcp.memcached_matches; + } + else if (packet->udp != NULL) { + if (packet->payload_packet_len < MEMCACHED_MIN_UDP_LEN) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; } - else { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; + + if ((offset[4] == 0x00 && offset[5] == 0x00) || + offset[6] != 0x00 || offset[7] != 0x00) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; } - /* grep MCD memcached.c |\ - * egrep -v '(LEN|MATCH)' |\ - * sed -e 's/^#define //g' |\ - * awk '{ printf "else if (! MEMCACHED_MATCH(%s)) *matches += 1;\n",$1 }' */ - - if (! MEMCACHED_MATCH(MCDC_SET)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_ADD)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_REPLACE)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_APPEND)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_PREPEND)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_CAS)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_GET)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_GETS)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_DELETE)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_INCR)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_DECR)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_TOUCH)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_GAT)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_GATS)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDC_STATS)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_ERROR)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_CLIENT_ERROR)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_SERVER_ERROR)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_STORED)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_NOT_STORED)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_EXISTS)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_NOT_FOUND)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_END)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_DELETED)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_TOUCHED)) *matches += 1; - else if (! MEMCACHED_MATCH(MCDR_STAT)) *matches += 1; - - if (*matches >= MEMCACHED_MIN_MATCH) - ndpi_int_memcached_add_connection(ndpi_struct, flow); + offset += MEMCACHED_UDP_HDR_LEN; + matches = &flow->l4.udp.memcached_matches; + } + else { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; + } + + /* grep MCD memcached.c |\ + * egrep -v '(LEN|MATCH)' |\ + * sed -e 's/^#define //g' |\ + * awk '{ printf "else if (! MEMCACHED_MATCH(%s)) *matches += 1;\n",$1 }' */ + + if (! MEMCACHED_MATCH(MCDC_SET)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_ADD)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_REPLACE)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_APPEND)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_PREPEND)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_CAS)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_GET)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_GETS)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_DELETE)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_INCR)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_DECR)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_TOUCH)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_GAT)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_GATS)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDC_STATS)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_ERROR)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_CLIENT_ERROR)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_SERVER_ERROR)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_STORED)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_NOT_STORED)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_EXISTS)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_NOT_FOUND)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_END)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_DELETED)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_TOUCHED)) *matches += 1; + else if (! MEMCACHED_MATCH(MCDR_STAT)) *matches += 1; + + if (*matches >= MEMCACHED_MIN_MATCH) + ndpi_int_memcached_add_connection(ndpi_struct, flow); } void init_memcached_dissector( - struct ndpi_detection_module_struct *ndpi_struct, - u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) + struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { - ndpi_set_bitmask_protocol_detection("MEMCACHED", - ndpi_struct, detection_bitmask, *id, - NDPI_PROTOCOL_MEMCACHED, - ndpi_search_memcached, - NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD, - SAVE_DETECTION_BITMASK_AS_UNKNOWN, - ADD_TO_DETECTION_BITMASK); - - *id += 1; + ndpi_set_bitmask_protocol_detection("MEMCACHED", + ndpi_struct, detection_bitmask, *id, + NDPI_PROTOCOL_MEMCACHED, + ndpi_search_memcached, + NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD, + SAVE_DETECTION_BITMASK_AS_UNKNOWN, + ADD_TO_DETECTION_BITMASK); + + *id += 1; } diff --git a/src/lib/protocols/openvpn.c b/src/lib/protocols/openvpn.c index 6bd480ea1..b92eb5cf7 100644 --- a/src/lib/protocols/openvpn.c +++ b/src/lib/protocols/openvpn.c @@ -40,12 +40,19 @@ #define P_PACKET_ID_ARRAY_LEN_OFFSET(hmac_size) (P_HARD_RESET_PACKET_ID_OFFSET(hmac_size) + 8) #define P_HARD_RESET_CLIENT_MAX_COUNT 5 +static void ndpi_int_openvpn_add_connection(struct ndpi_detection_module_struct + *ndpi_struct, struct ndpi_flow_struct *flow) { + NDPI_LOG_INFO(ndpi_struct, "found memcached\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, + NDPI_PROTOCOL_MEMCACHED, NDPI_PROTOCOL_UNKNOWN); +} + static #ifndef WIN32 inline #endif u_int32_t get_packet_id(const u_int8_t * payload, u_int8_t hms) { - return ntohl(*(u_int32_t*)(payload + P_HARD_RESET_PACKET_ID_OFFSET(hms))); + return(ntohl(*(u_int32_t*)(payload + P_HARD_RESET_PACKET_ID_OFFSET(hms)))); } static @@ -54,11 +61,13 @@ inline #endif int8_t check_pkid_and_detect_hmac_size(const u_int8_t * payload) { // try to guess - if (get_packet_id(payload, P_HMAC_160) == 1) + if(get_packet_id(payload, P_HMAC_160) == 1) return P_HMAC_160; - if (get_packet_id(payload, P_HMAC_128) == 1) + + if(get_packet_id(payload, P_HMAC_128) == 1) return P_HMAC_128; - return -1; + + return(-1); } void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct, @@ -71,17 +80,39 @@ void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct, int8_t hmac_size; int8_t failed = 0; - if (packet->payload_packet_len >= 40) { + if(packet->payload_packet_len >= 40) { // skip openvpn TCP transport packet size - if (packet->tcp != NULL) + if(packet->tcp != NULL) ovpn_payload += 2; opcode = ovpn_payload[0] & P_OPCODE_MASK; - if (flow->ovpn_counter < P_HARD_RESET_CLIENT_MAX_COUNT && (opcode == P_CONTROL_HARD_RESET_CLIENT_V1 || + if(packet->udp) { +#ifdef DEBUG + printf("[packet_id: %u][opcode: %u][Packet ID: %d][%u <-> %u][len: %u]\n", + flow->num_processed_pkts, + opcode, check_pkid_and_detect_hmac_size(ovpn_payload), + htons(packet->udp->source), htons(packet->udp->dest), packet->payload_packet_len); +#endif + + if( + (flow->num_processed_pkts == 1) + && ( + ((packet->payload_packet_len == 112) + && ((opcode == 168) || (opcode == 192)) + ) + || ((packet->payload_packet_len == 80) + && ((opcode == 184) || (opcode == 88) || (opcode == 160) || (opcode == 168) || (opcode == 200))) + )) { + NDPI_LOG_INFO(ndpi_struct,"found openvpn\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OPENVPN, NDPI_PROTOCOL_UNKNOWN); + return; + } + } + + if(flow->ovpn_counter < P_HARD_RESET_CLIENT_MAX_COUNT && (opcode == P_CONTROL_HARD_RESET_CLIENT_V1 || opcode == P_CONTROL_HARD_RESET_CLIENT_V2)) { - - if (check_pkid_and_detect_hmac_size(ovpn_payload) > 0) { + if(check_pkid_and_detect_hmac_size(ovpn_payload) > 0) { memcpy(flow->ovpn_session_id, ovpn_payload+1, 8); NDPI_LOG_DBG2(ndpi_struct, @@ -89,20 +120,20 @@ void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct, flow->ovpn_session_id[0], flow->ovpn_session_id[1], flow->ovpn_session_id[2], flow->ovpn_session_id[3], flow->ovpn_session_id[4], flow->ovpn_session_id[5], flow->ovpn_session_id[6], flow->ovpn_session_id[7]); } - } else if (flow->ovpn_counter >= 1 && flow->ovpn_counter <= P_HARD_RESET_CLIENT_MAX_COUNT && + } else if(flow->ovpn_counter >= 1 && flow->ovpn_counter <= P_HARD_RESET_CLIENT_MAX_COUNT && (opcode == P_CONTROL_HARD_RESET_SERVER_V1 || opcode == P_CONTROL_HARD_RESET_SERVER_V2)) { hmac_size = check_pkid_and_detect_hmac_size(ovpn_payload); - if (hmac_size > 0) { + if(hmac_size > 0) { alen = ovpn_payload[P_PACKET_ID_ARRAY_LEN_OFFSET(hmac_size)]; session_remote = ovpn_payload + P_PACKET_ID_ARRAY_LEN_OFFSET(hmac_size) + 1 + alen * 4; - if (memcmp(flow->ovpn_session_id, session_remote, 8) == 0) { - NDPI_LOG_INFO(ndpi_struct,"found openvpn\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OPENVPN, NDPI_PROTOCOL_UNKNOWN); - } - else { + if(memcmp(flow->ovpn_session_id, session_remote, 8) == 0) { + NDPI_LOG_INFO(ndpi_struct,"found openvpn\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OPENVPN, NDPI_PROTOCOL_UNKNOWN); + return; + } else { NDPI_LOG_DBG2(ndpi_struct, "key mismatch: %02x%02x%02x%02x%02x%02x%02x%02x\n", session_remote[0], session_remote[1], session_remote[2], session_remote[3], @@ -116,14 +147,14 @@ void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct, flow->ovpn_counter++; - if (failed) { + if(failed) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); } } } -void init_openvpn_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) -{ +void init_openvpn_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { ndpi_set_bitmask_protocol_detection("OpenVPN", ndpi_struct, detection_bitmask, *id, NDPI_PROTOCOL_OPENVPN, ndpi_search_openvpn, diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index c169a47db..97cf091f0 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -28,7 +28,7 @@ #include "ndpi_api.h" -#define MAX_NUM_STUN_PKTS 10 +#define MAX_NUM_STUN_PKTS 8 struct stun_packet_header { u_int16_t msg_type, msg_len; @@ -53,10 +53,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * u_int8_t *is_whatsapp) { u_int16_t msg_type, msg_len; struct stun_packet_header *h = (struct stun_packet_header*)payload; - u_int8_t can_this_be_whatsapp_voice = 1; + u_int8_t can_this_be_whatsapp_voice = 1, wa = 0; flow->protos.stun_ssl.stun.num_processed_pkts++; - + if(payload_length < sizeof(struct stun_packet_header)) { if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) { *is_whatsapp = 1; @@ -75,86 +75,104 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * if(ntohs(h->msg_type) == 0x01 /* Binding Request */) flow->protos.stun_ssl.stun.num_binding_requests++; - - if((payload[0] != 0x80) && ((msg_len+20) > payload_length)) - return(NDPI_IS_NOT_STUN); - if((payload_length == (msg_len+20)) - && ((msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */)) { - u_int offset = 20; + /* printf("[%02X][%02X][msg_len: %u][payload_length: %u]\n", payload[0], payload[1], msg_len, payload_length); */ - /* - This can either be the standard RTCP or Ms Lync RTCP that - later will become Ms Lync RTP. In this case we need to - be careful before deciding about the protocol before dissecting the packet - - MS Lync = Skype - https://en.wikipedia.org/wiki/Skype_for_Business - */ + if(((payload[0] == 0x80) && ((msg_len+20) <= payload_length)) /* WhatsApp Voice */) { + *is_whatsapp = 1; + return NDPI_IS_STUN; /* This is WhatsApp Voice */ + } else if((payload[0] == 0x90) && ((msg_len+11) == payload_length) /* WhatsApp Video */) { + *is_whatsapp = 2; + return NDPI_IS_STUN; /* This is WhatsApp Video */ + } - while((offset+2) < payload_length) { - u_int16_t attribute = ntohs(*((u_int16_t*)&payload[offset])); - u_int16_t len = ntohs(*((u_int16_t*)&payload[offset+2])); - u_int16_t x = (len + 4) % 4; - - if(x != 0) - len += 4-x; - - switch(attribute) { - case 0x0008: /* Message Integrity */ - case 0x0020: /* XOR-MAPPED-ADDRESSES */ - case 0x4002: - /* These are the only messages apparently whatsapp voice can use */ - break; - - case 0x8054: /* Candidate Identifier */ - if((len == 4) - && ((offset+7) < payload_length) - && (payload[offset+5] == 0x00) - && (payload[offset+6] == 0x00) - && (payload[offset+7] == 0x00)) { - /* Either skype for business or "normal" skype with multiparty call */ - flow->protos.stun_ssl.stun.is_skype = 1; - return(NDPI_IS_STUN); - } - break; - - case 0x8055: /* MS Service Quality (skype?) */ - break; - - /* Proprietary fields found on skype calls */ - case 0x24DF: - case 0x3802: - case 0x8036: - case 0x8095: - case 0x0800: - /* printf("====>>>> %04X\n", attribute); */ - flow->protos.stun_ssl.stun.is_skype = 1; - return(NDPI_IS_STUN); - break; - - case 0x8070: /* Implementation Version */ - if((len == 4) - && ((offset+7) < payload_length) - && (payload[offset+4] == 0x00) - && (payload[offset+5] == 0x00) - && (payload[offset+6] == 0x00) - && ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03)) - ) { + if((payload[0] != 0x80) && ((msg_len+20) > payload_length)) + return(NDPI_IS_NOT_STUN); + + if(payload_length == (msg_len+20)) { + if(msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ { + u_int offset = 20; + + // printf("[%02X][%02X][%02X][%02X][payload_length: %u]\n", payload[offset], payload[offset+1], payload[offset+2], payload[offset+3],payload_length); + + /* + This can either be the standard RTCP or Ms Lync RTCP that + later will become Ms Lync RTP. In this case we need to + be careful before deciding about the protocol before dissecting the packet + + MS Lync = Skype + https://en.wikipedia.org/wiki/Skype_for_Business + */ + + while((offset+2) < payload_length) { + u_int16_t attribute = ntohs(*((u_int16_t*)&payload[offset])); + u_int16_t len = ntohs(*((u_int16_t*)&payload[offset+2])); + u_int16_t x = (len + 4) % 4; + + if(x != 0) + len += 4-x; + + switch(attribute) { + case 0x0008: /* Message Integrity */ + case 0x0020: /* XOR-MAPPED-ADDRESSES */ + case 0x4000: + case 0x4002: + /* These are the only messages apparently whatsapp voice can use */ + break; + + case 0x8054: /* Candidate Identifier */ + if((len == 4) + && ((offset+7) < payload_length) + && (payload[offset+5] == 0x00) + && (payload[offset+6] == 0x00) + && (payload[offset+7] == 0x00)) { + /* Either skype for business or "normal" skype with multiparty call */ + flow->protos.stun_ssl.stun.is_skype = 1; + return(NDPI_IS_STUN); + } + break; + + case 0x8055: /* MS Service Quality (skype?) */ + break; + + /* Proprietary fields found on skype calls */ + case 0x24DF: + case 0x3802: + case 0x8036: + case 0x8095: + case 0x0800: + /* printf("====>>>> %04X\n", attribute); */ flow->protos.stun_ssl.stun.is_skype = 1; return(NDPI_IS_STUN); + break; + + case 0x8070: /* Implementation Version */ + if((len == 4) + && ((offset+7) < payload_length) + && (payload[offset+4] == 0x00) + && (payload[offset+5] == 0x00) + && (payload[offset+6] == 0x00) + && ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03)) + ) { + flow->protos.stun_ssl.stun.is_skype = 1; + return(NDPI_IS_STUN); + } + break; + + default: + /* This means this STUN packet cannot be confused with whatsapp voice */ + /* printf("==> %04X\n", attribute); */ + can_this_be_whatsapp_voice = 0; + break; } - break; - default: - /* This means this STUN packet cannot be confused with whatsapp voice */ - can_this_be_whatsapp_voice = 0; - break; + offset += len + 4; } - - offset += len + 4; + goto udp_stun_found; + } else if(msg_type == 0x0800) { + *is_whatsapp = 1; + return NDPI_IS_STUN; /* This is WhatsApp */ } - goto udp_stun_found; } if((flow->protos.stun_ssl.stun.num_udp_pkts > 0) && (msg_type <= 0x00FF)) { @@ -163,7 +181,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * } else return NDPI_IS_NOT_STUN; - udp_stun_found: + udp_stun_found: if(can_this_be_whatsapp_voice) { flow->protos.stun_ssl.stun.num_udp_pkts++; @@ -172,11 +190,11 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * /* We cannot immediately say that this is STUN as there are other protocols like GoogleHangout that might be candidates, thus we set the - guessed protocol to STUN + guessed protocol to STUN */ flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; return(NDPI_IS_NOT_STUN); - } + } } void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) @@ -187,11 +205,11 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n NDPI_LOG_DBG(ndpi_struct, "search stun\n"); if(packet->payload == NULL) return; - + if(packet->tcp) { /* STUN may be encapsulated in TCP packets */ if((packet->payload_packet_len >= 22) - && ((ntohs(get_u_int16_t(packet->payload, 0)) + 2) == packet->payload_packet_len)) { + && ((ntohs(get_u_int16_t(packet->payload, 0)) + 2) == packet->payload_packet_len)) { /* TODO there could be several STUN packets in a single TCP packet so maybe the detection could be * improved by checking only the STUN packet of given length */ @@ -207,9 +225,9 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n } else { NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n"); /* Ummmmm we're in the TCP branch. This code looks bad */ ndpi_int_stun_add_connection(ndpi_struct, - is_whatsapp ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_STUN, flow); + is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, flow); } - + return; } } @@ -218,24 +236,25 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload, packet->payload_packet_len, &is_whatsapp) == NDPI_IS_STUN) { if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - + if(flow->protos.stun_ssl.stun.is_skype) { NDPI_LOG_INFO(ndpi_struct, "Found Skype\n"); - /* flow->protos.stun_ssl.stun.num_binding_requests < 4) ? NDPI_PROTOCOL_SKYPE_CALL_IN : NDPI_PROTOCOL_SKYPE_CALL_OUT */ + /* flow->protos.stun_ssl.stun.num_binding_requests < 4) ? NDPI_PROTOCOL_SKYPE_CALL_IN : NDPI_PROTOCOL_SKYPE_CALL_OUT */ if((flow->protos.stun_ssl.stun.num_processed_pkts >= 8) || (flow->protos.stun_ssl.stun.num_binding_requests >= 4)) ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); } else { NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n"); ndpi_int_stun_add_connection(ndpi_struct, - is_whatsapp ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_STUN, flow); + is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, + flow); } - + return; } if(flow->protos.stun_ssl.stun.num_udp_pkts >= MAX_NUM_STUN_PKTS) - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); if(flow->packet_counter > 0) { /* This might be a RTP stream: let's make sure we check it */ diff --git a/src/lib/protocols/viber.c b/src/lib/protocols/viber.c index 65e227234..9aaa0e243 100644 --- a/src/lib/protocols/viber.c +++ b/src/lib/protocols/viber.c @@ -36,7 +36,7 @@ void ndpi_search_viber(struct ndpi_detection_module_struct *ndpi_struct, struct if((packet->payload_packet_len == 12 && packet->payload[2] == 0x03 && packet->payload[3] == 0x00) || (packet->payload_packet_len == 20 && packet->payload[2] == 0x09 && packet->payload[3] == 0x00) - || ((packet->payload_packet_len < 135) && (packet->payload[0] == 0x11))) { + ) { NDPI_LOG_DBG(ndpi_struct, "found VIBER\n"); ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_VIBER, NDPI_PROTOCOL_UNKNOWN); return; |