diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_api.h | 6 | ||||
-rw-r--r-- | src/include/ndpi_protocol_ids.h | 4 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 1 | ||||
-rw-r--r-- | src/lib/ndpi_content_match.c.inc | 92 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 197 | ||||
-rw-r--r-- | src/lib/ndpi_serializer.c | 63 | ||||
-rw-r--r-- | src/lib/protocols/ciscovpn.c | 28 | ||||
-rw-r--r-- | src/lib/protocols/dns.c | 373 | ||||
-rw-r--r-- | src/lib/protocols/skype.c | 15 | ||||
-rw-r--r-- | src/lib/protocols/steam.c | 76 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 396 |
11 files changed, 744 insertions, 507 deletions
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h index 285629035..34b1fed67 100644 --- a/src/include/ndpi_api.h +++ b/src/include/ndpi_api.h @@ -807,7 +807,8 @@ extern "C" { 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); - + u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); u_int8_t ndpi_is_safe_ssl_cipher(u_int32_t cipher); const char* ndpi_cipher2str(u_int32_t cipher); u_int16_t ndpi_guess_host_protocol_id(struct ndpi_detection_module_struct *ndpi_struct, @@ -858,6 +859,9 @@ extern "C" { const char *key, float value, const char *format /* e.f. "%.2f" */); int ndpi_serialize_end_of_record(ndpi_serializer *serializer); + int ndpi_serialize_start_of_block(ndpi_serializer *_serializer, + const char *key); + int ndpi_serialize_end_of_block(ndpi_serializer *_serializer); char* ndpi_serializer_get_buffer(ndpi_serializer *_serializer, u_int32_t *buffer_len); u_int32_t ndpi_serializer_get_buffer_len(ndpi_serializer *_serializer); int ndpi_serializer_set_buffer_len(ndpi_serializer *_serializer, u_int32_t l); diff --git a/src/include/ndpi_protocol_ids.h b/src/include/ndpi_protocol_ids.h index c22c6f815..77b244bca 100644 --- a/src/include/ndpi_protocol_ids.h +++ b/src/include/ndpi_protocol_ids.h @@ -98,7 +98,7 @@ typedef enum { NDPI_PROTOCOL_QQLIVE = 61, NDPI_PROTOCOL_THUNDER = 62, NDPI_PROTOCOL_SOULSEEK = 63, - NDPI_PROTOCOL_FREE_64 = 64, + NDPI_PROTOCOL_PS_VUE = 64, NDPI_PROTOCOL_IRC = 65, NDPI_PROTOCOL_AYIYA = 66, NDPI_PROTOCOL_UNENCRYPTED_JABBER = 67, @@ -223,7 +223,7 @@ typedef enum { NDPI_PROTOCOL_VEVO = 186, NDPI_PROTOCOL_PANDORA = 187, NDPI_PROTOCOL_QUIC = 188, /* Andrea Buscarinu <andrea.buscarinu@gmail.com> - Michele Campus <michelecampus5@gmail.com> */ - NDPI_PROTOCOL_FREE_189 = 189, + NDPI_PROTOCOL_ZOOM = 189, /* Zoom video conference. */ NDPI_PROTOCOL_EAQ = 190, NDPI_PROTOCOL_OOKLA = 191, NDPI_PROTOCOL_AMQP = 192, diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 3cf7c07b3..ccc4faec7 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1379,6 +1379,7 @@ typedef enum { #define NDPI_SERIALIZER_STATUS_COMMA (1 << 0) #define NDPI_SERIALIZER_STATUS_ARRAY (1 << 1) #define NDPI_SERIALIZER_STATUS_EOR (1 << 2) +#define NDPI_SERIALIZER_STATUS_SOB (1 << 3) typedef struct { u_int32_t flags; diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc index 1693db9fd..c6e753de6 100644 --- a/src/lib/ndpi_content_match.c.inc +++ b/src/lib/ndpi_content_match.c.inc @@ -8220,6 +8220,92 @@ static ndpi_network host_protocol_list[] = { /* Line */ { 0x7DD1FC00 /* 125.209.252.0/24 */, 24, NDPI_PROTOCOL_LINE }, + /* Zoom video conference app. */ + { 0x03501480 /* 3.80.20.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x03787900 /* 3.120.121.0/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x03682280 /* 3.104.34.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x03D04800 /* 3.208.72.0/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x03D3F100 /* 3.211.241.0/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x04227D80 /* 4.34.125.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x04234080 /* 4.35.64.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x08058000 /* 8.5.128.0/23 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x0D340680 /* 13.52.6.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x0D349200 /* 13.52.146.0/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x0D726AA6 /* 13.114.106.166/32 */, 32, NDPI_PROTOCOL_ZOOM }, + { 0x12CD5D80 /* 18.205.93.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x32EFCA00 /* 50.239.202.0/23 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x32EFCC00 /* 50.239.204.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x343D6480 /* 52.61.100.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x34519780 /* 52.81.151.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x34C56115 /* 52.197.97.21/32 */, 32, NDPI_PROTOCOL_ZOOM }, + { 0x34CA3EC0 /* 52.202.62.192/26 */, 26, NDPI_PROTOCOL_ZOOM }, + { 0x34D7A800 /* 52.215.168.0/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x40454A00 /* 64.69.74.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x407D3E00 /* 64.125.62.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x40D39000 /* 64.211.144.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x41279800 /* 65.39.152.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x45AE3900 /* 69.174.57.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x45AE6C00 /* 69.174.108.0/22 */, 22, NDPI_PROTOCOL_ZOOM }, + { 0x634F1400 /* 99.79.20.0/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0x677AA600 /* 103.122.166.0/23 */, 23, NDPI_PROTOCOL_ZOOM }, + { 0x6D5EA000 /* 109.94.160.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0x736E9AC0 /* 115.110.154.192/26 */, 26, NDPI_PROTOCOL_ZOOM }, + { 0x737238C0 /* 115.114.56.192/26 */, 26, NDPI_PROTOCOL_ZOOM }, + { 0x73727300 /* 115.114.115.0/26 */, 26, NDPI_PROTOCOL_ZOOM }, + { 0x73728300 /* 115.114.131.0/26 */, 26, NDPI_PROTOCOL_ZOOM }, + { 0x781D9400 /* 120.29.148.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xA0013880 /* 160.1.56.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0xA1C78800 /* 161.199.136.0/22 */, 22, NDPI_PROTOCOL_ZOOM }, + { 0xA20CE800 /* 162.12.232.0/22 */, 22, NDPI_PROTOCOL_ZOOM }, + { 0xA2FF2400 /* 162.255.36.0/22 */, 22, NDPI_PROTOCOL_ZOOM }, + { 0xA5FE5800 /* 165.254.88.0/23 */, 23, NDPI_PROTOCOL_ZOOM }, + { 0xC0CC0C00 /* 192.204.12.0/22 */, 22, NDPI_PROTOCOL_ZOOM }, + { 0xCAB1CF80 /* 202.177.207.128/27 */, 27, NDPI_PROTOCOL_ZOOM }, + { 0xCAB1D560 /* 202.177.213.96/27 */, 27, NDPI_PROTOCOL_ZOOM }, + { 0xCC506800 /* 204.80.104.0/21 */, 21, NDPI_PROTOCOL_ZOOM }, + { 0xCC8D1C00 /* 204.141.28.0/22 */, 22, NDPI_PROTOCOL_ZOOM }, + { 0xCFE28400 /* 207.226.132.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xD109D300 /* 209.9.211.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xD109D700 /* 209.9.215.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xD2393700 /* 210.57.55.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xD5139000 /* 213.19.144.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xD5139900 /* 213.19.153.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xD5F48C00 /* 213.244.140.0/24 */, 24, NDPI_PROTOCOL_ZOOM }, + { 0xDD7A5840 /* 221.122.88.64/27 */, 27, NDPI_PROTOCOL_ZOOM }, + { 0xDD7A5880 /* 221.122.88.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + { 0xDD7A5980 /* 221.122.89.128/25 */, 25, NDPI_PROTOCOL_ZOOM }, + /* 2620:123:2000::/44 IPV6 */ + + { 0x08F8DA14 /* 8.248.218.20/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FA6E14 /* 8.250.110.20/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FC028B /* 8.252.2.139/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FD6803 /* 8.253.104.3/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FE6813 /* 8.253.104.19/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FE8C0F /* 8.253.140.15/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FE8C10 /* 8.253.140.16/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FE8C77 /* 8.253.140.119/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FC8CA8 /* 8.253.140.168/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x08FC8CA9 /* 8.253.140.169/32 */, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x4318881E /* 67.24.136.30/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x431889FE /* 67.24.137.254/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x43188DFE /* 67.24.141.254/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x43188E1E /* 67.24.142.30/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x4318901E /* 67.24.144.30/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x4318921E /* 67.24.146.30/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x43189630 /* 67.24.150.30/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA2D83A20 /* 162.216.58.32/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA2D83A2B /* 162.216.58.43/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA2D83A39 /* 162.216.58.57/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA2D83A40 /* 162.216.58.64/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA2D83A48 /* 162.216.58.72/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA2D83A51 /* 162.216.58.81/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA7CE74AA /* 167.206.116.170/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA7CEDA60 /* 167.206.218.96/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA7CEDA72 /* 167.206.218.114/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA7CEDA7B /* 167.206.218.123/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA7CEDA82 /* 167.206.218.130/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0xA7CEDA8A /* 167.206.218.138/32*/, 32, NDPI_PROTOCOL_PS_VUE }, + { 0x0, 0, 0 } }; @@ -8593,7 +8679,9 @@ ndpi_protocol_match host_match[] = { { "hotspotshield.com", NULL, "hotspotshield" TLD, "HotspotShield", NDPI_PROTOCOL_HOTSPOT_SHIELD, NDPI_PROTOCOL_CATEGORY_VPN, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS }, { ".northghost.com", NULL, "\\.northghost" TLD, "HotspotShield", NDPI_PROTOCOL_HOTSPOT_SHIELD, NDPI_PROTOCOL_CATEGORY_VPN, NDPI_PROTOCOL_POTENTIALLY_DANGEROUS }, - { ".webex.com", NULL, "\\.webex" TLD, "Webex", NDPI_PROTOCOL_WEBEX, NDPI_PROTOCOL_CATEGORY_VOIP, NDPI_PROTOCOL_ACCEPTABLE }, + { ".webex.com", NULL, "\\.webex" TLD, "Webex", NDPI_PROTOCOL_WEBEX, NDPI_PROTOCOL_CATEGORY_VOIP, NDPI_PROTOCOL_ACCEPTABLE }, + { ".zoom.us", NULL, "\\.zoom" TLD, "Zoom", NDPI_PROTOCOL_ZOOM, NDPI_PROTOCOL_CATEGORY_VIDEO, NDPI_PROTOCOL_ACCEPTABLE }, + { ".cloudfront.net", NULL, "\\.cloudfront" TLD, "Zoom", NDPI_PROTOCOL_ZOOM, NDPI_PROTOCOL_CATEGORY_VIDEO, NDPI_PROTOCOL_ACCEPTABLE }, { ".ocsdomain.com", NULL, "\\.ocsdomain" TLD, "OCS", NDPI_PROTOCOL_OCS, NDPI_PROTOCOL_CATEGORY_MEDIA, NDPI_PROTOCOL_FUN }, { "ocs.fr", NULL, "ocs" TLD, "OCS", NDPI_PROTOCOL_OCS, NDPI_PROTOCOL_CATEGORY_MEDIA, NDPI_PROTOCOL_FUN }, @@ -8639,8 +8727,6 @@ ndpi_protocol_match host_match[] = { /* Detected "slack-assets2.s3-us-west-2.amazonaws.com.". Omitted "*amazonaws.com" CDN, but no generic pattern to use on first part */ { "slack-assets2.s3-", NULL, "slack-assets2\\.s3-", "Slack", NDPI_PROTOCOL_SLACK, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, - { "wechat.com", NULL, "wechat\\.com" TLD, "WeChat", NDPI_PROTOCOL_WECHAT, NDPI_PROTOCOL_CATEGORY_SOCIAL_NETWORK, NDPI_PROTOCOL_FUN }, - { "github.com", NULL, "github" TLD, "Github", NDPI_PROTOCOL_GITHUB, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, { ".github.com", NULL, "\\.github" TLD, "Github", NDPI_PROTOCOL_GITHUB, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, { "github.io", NULL, NULL, "Github", NDPI_PROTOCOL_GITHUB, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index df40c5769..44963d183 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -455,7 +455,7 @@ static int ndpi_string_to_automa(struct ndpi_detection_module_struct *ndpi_struc /* TODO This function should free the memory during program termination - + */ static void ndpi_free_memory_at_termination(struct ndpi_detection_module_struct *ndpi_struct, char *buf) { @@ -471,7 +471,7 @@ static int ndpi_add_host_url_subprotocol(struct ndpi_detection_module_struct *nd char *value = ndpi_strdup(_value); if(!value) return(-1); else ndpi_free_memory_at_termination(ndpi_struct, value); - + #ifdef DEBUG NDPI_LOG_DEBUG2(ndpi_struct, "[NDPI] Adding [%s][%d]\n", value, protocol_id); #endif @@ -978,7 +978,7 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_b, 3544, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_WECHAT, 0 /* can_have_a_subprotocol */, no_master, /* wechat.com */ - no_master, "WeChat", NDPI_PROTOCOL_CATEGORY_SOCIAL_NETWORK, + 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_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_MEMCACHED, @@ -1122,9 +1122,9 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp 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_64, + ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_PS_VUE, 0 /* can_have_a_subprotocol */, no_master, - no_master, "Free64", NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, + 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_mod, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_IRC, @@ -1249,9 +1249,9 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp 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_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_FREE_189, + ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_ZOOM, 0 /* can_have_a_subprotocol */, no_master, - no_master, "Free189", NDPI_PROTOCOL_CATEGORY_VOIP, + 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_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP_FILES, @@ -1555,7 +1555,7 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_set_proto_defaults(ndpi_mod, 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, 0, 0, 0, 0) /* TCP */, + 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_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TEAMSPEAK, 0 /* can_have_a_subprotocol */, no_master, @@ -1794,10 +1794,14 @@ static int ac_match_handler(AC_MATCH_t *m, AC_TEXT_t *txt, AC_REP_t *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) */ - && (whatfound[-1] != '.') - ) - return(0); + && 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 */ + } + } } /* @@ -2215,6 +2219,13 @@ int ndpi_match_string(void *_automa, char *string_to_match) { rc = ac_automata_search(automa, &ac_input_text, &match); ac_automata_reset(automa); + /* + 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); } @@ -2236,6 +2247,13 @@ int ndpi_match_string_id(void *_automa, char *string_to_match, unsigned long *id rc = ac_automata_search(automa, &ac_input_text, &match); ac_automata_reset(automa); + /* + 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); @@ -3543,7 +3561,7 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str u_int8_t l4_result; if (!flow) - return 1; + return 1; /* reset payload_packet_len, will be set if ipv4 tcp or udp */ flow->packet.payload_packet_len = 0; @@ -3606,7 +3624,7 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str 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 */ @@ -3860,7 +3878,7 @@ void check_ndpi_udp_flow_func(struct ndpi_detection_module_struct *ndpi_struct, && NDPI_BITMASK_COMPARE(ndpi_struct->callback_buffer_udp[a].detection_bitmask, detection_bitmask) != 0) { ndpi_struct->callback_buffer_udp[a].func(ndpi_struct, flow); - + // NDPI_LOG_DBG(ndpi_struct, "[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 */ @@ -4044,8 +4062,14 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st if(flow == NULL) return(ret); - else - ret.category = flow->category; + + /* 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) { @@ -4460,6 +4484,44 @@ void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_struc /* ********************************************************************************* */ +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_struct, struct ndpi_flow_struct *flow, const unsigned char *packet, @@ -4484,7 +4546,7 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct /* 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) { /* @@ -4497,7 +4559,7 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct */ ) { ndpi_process_extra_packet(ndpi_struct, flow, packet, packetlen, current_tick_l, src, dst); - + return(ret); } else goto ret_protocols; @@ -4676,8 +4738,12 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct } else ret.app_protocol = flow->detected_protocol_stack[0]; - ndpi_fill_protocol_category(ndpi_struct, flow, &ret); - + /* Don;t overwrite the category if already set */ + if(flow->category == NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) + ndpi_fill_protocol_category(ndpi_struct, 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) @@ -4701,7 +4767,8 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct 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.iph = NULL, flow->packet.tcp = NULL, flow->packet.udp = NULL, flow->packet.payload = NULL; + ndpi_reset_packet_line_info(&flow->packet); return(ret); } @@ -4864,39 +4931,7 @@ void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_struc return; packet->packet_lines_parsed_complete = 1; - 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_reset_packet_line_info(packet); if((packet->payload_packet_len < 3) || (packet->payload == NULL)) @@ -5862,7 +5897,7 @@ int ndpi_get_category_id(struct ndpi_detection_module_struct *ndpi_mod, char *ca void ndpi_dump_protocols(struct ndpi_detection_module_struct *ndpi_mod) { int i; - + for(i=0; i<(int)ndpi_mod->ndpi_num_supported_protocols; i++) printf("%3d %-22s %-12s %s\n", i, ndpi_mod->proto_defaults[i].protoName, @@ -6102,6 +6137,13 @@ int ndpi_match_bigram(struct ndpi_detection_module_struct *ndpi_struct, rc = ac_automata_search(((AC_AUTOMATA_t*)automa->ac_automa), &ac_input_text, &match); ac_automata_reset(((AC_AUTOMATA_t*)automa->ac_automa)); + /* + 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); } @@ -6116,7 +6158,7 @@ void ndpi_free_flow(struct ndpi_flow_struct *flow) { if(flow->l4.tcp.tls_srv_cert_fingerprint_ctx) ndpi_free(flow->l4.tcp.tls_srv_cert_fingerprint_ctx); } - + ndpi_free(flow); } } @@ -6275,4 +6317,43 @@ int ndpi_flowv6_flow_hash(u_int8_t l4_proto, struct ndpi_in6_addr *src_ip, struc 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_struct, + struct ndpi_flow_struct *flow) { + +#if 0 + printf("[DEBUG] %s(%u.%u)\n", __FUNCTION__, + flow->detected_protocol_stack[0], + flow->detected_protocol_stack[1]); +#endif + + if(flow->check_extra_packets) return(1); + + switch(flow->detected_protocol_stack[0]) { + 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') + return(1); + break; + + case NDPI_PROTOCOL_DNS: + if((ndpi_struct->dns_dont_dissect_response == 0) + && (flow->host_server_name[0] == '\0')) + return(1); + break; + } + + return(0); +} + +/* ******************************************************************** */ diff --git a/src/lib/ndpi_serializer.c b/src/lib/ndpi_serializer.c index 87ce5e364..49f29a4e8 100644 --- a/src/lib/ndpi_serializer.c +++ b/src/lib/ndpi_serializer.c @@ -454,7 +454,10 @@ static inline void ndpi_serialize_json_pre(ndpi_serializer *_serializer) { if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) serializer->status.size_used--; /* Remove ']'*/ serializer->status.size_used--; /* Remove '}'*/ - if(serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA) + + if (serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB) + serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB; + else if(serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA) serializer->buffer[serializer->status.size_used++] = ','; } } @@ -1206,6 +1209,64 @@ int ndpi_serialize_string_string(ndpi_serializer *_serializer, /* ********************************** */ +/* Serialize start of nested block (JSON only)*/ +int ndpi_serialize_start_of_block(ndpi_serializer *_serializer, + const char *key) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t needed, klen = strlen(key); + + if (serializer->fmt != ndpi_serialization_format_json) + return -1; + + needed = 16 + klen; + + if (buff_diff < needed) { + if (ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->status.size_used; + } + + ndpi_serialize_json_pre(_serializer); + serializer->status.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->status.size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->status.size_used; + serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ": {"); + buff_diff = serializer->buffer_size - serializer->status.size_used; + ndpi_serialize_json_post(_serializer); + + serializer->status.flags |= NDPI_SERIALIZER_STATUS_SOB; + + return(0); +} + +/* ********************************** */ + +/* Serialize start of nested block (JSON only)*/ +int ndpi_serialize_end_of_block(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t needed; + + if (serializer->fmt != ndpi_serialization_format_json) + return -1; + + needed = 4; + + if (buff_diff < needed) { + if (ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->status.size_used; + } + + buff_diff = serializer->buffer_size - serializer->status.size_used; + ndpi_serialize_json_post(_serializer); + + return(0); +} + +/* ********************************** */ + void ndpi_serializer_create_snapshot(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; diff --git a/src/lib/protocols/ciscovpn.c b/src/lib/protocols/ciscovpn.c index d98f91e02..4a73e5728 100644 --- a/src/lib/protocols/ciscovpn.c +++ b/src/lib/protocols/ciscovpn.c @@ -48,7 +48,33 @@ void ndpi_search_ciscovpn(struct ndpi_detection_module_struct *ndpi_struct, stru NDPI_LOG_INFO(ndpi_struct, "found CISCOVPN\n"); ndpi_int_ciscovpn_add_connection(ndpi_struct, flow); return; - } + } + else if(((tsport == 443 || tdport == 443) || + (tsport == 80 || tdport == 80)) && + ((packet->payload[0] == 0x17 && + packet->payload[1] == 0x03 && + packet->payload[2] == 0x03 && + packet->payload[3] == 0x00 && + packet->payload[4] == 0x3A))) + { + /* TLS signature of Cisco AnyConnect 0X170303003A */ + NDPI_LOG_INFO(ndpi_struct, "found CISCO Anyconnect VPN\n"); + ndpi_int_ciscovpn_add_connection(ndpi_struct, flow); + return; + } + else if(((tsport == 8009 || tdport == 8009) || + (tsport == 8008 || tdport == 8008)) && + ((packet->payload[0] == 0x17 && + packet->payload[1] == 0x03 && + packet->payload[2] == 0x03 && + packet->payload[3] == 0x00 && + packet->payload[4] == 0x69))) + { + /* TCP signature of Cisco AnyConnect 0X1703030069 */ + NDPI_LOG_INFO(ndpi_struct, "found CISCO Anyconnect VPN\n"); + ndpi_int_ciscovpn_add_connection(ndpi_struct, flow); + return; + } else if( ( (usport == 10000 && udport == 10000) diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index b9cd1a9cb..86575f23e 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -30,7 +30,7 @@ #define FLAGS_MASK 0x8000 -/* #define DNS_DEBUG 1 */ +// #define DNS_DEBUG 1 /* *********************************************** */ @@ -59,23 +59,144 @@ static u_int getNameLength(u_int i, const u_int8_t *payload, u_int payloadLen) { return(off + getNameLength(i+off, payload, payloadLen)); } } -/* - allowed chars for dns names A-Z 0-9 _ - - Perl script for generation map: +/* + allowed chars for dns names A-Z 0-9 _ - + Perl script for generation map: my @M; for(my $ch=0; $ch < 256; $ch++) { - $M[$ch >> 5] |= 1 << ($ch & 0x1f) if chr($ch) =~ /[a-z0-9_-]/i; + $M[$ch >> 5] |= 1 << ($ch & 0x1f) if chr($ch) =~ /[a-z0-9_-]/i; } print join(',', map { sprintf "0x%08x",$_ } @M),"\n"; - */ +*/ static uint32_t dns_validchar[8] = { - 0x00000000,0x03ff2000,0x87fffffe,0x07fffffe,0,0,0,0 + 0x00000000,0x03ff2000,0x87fffffe,0x07fffffe,0,0,0,0 }; + +/* *********************************************** */ + +static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + struct ndpi_dns_packet_header *dns_header, + int payload_offset, u_int8_t *is_query) { + int x = payload_offset; + + memcpy(dns_header, (struct ndpi_dns_packet_header*)&flow->packet.payload[x], + sizeof(struct ndpi_dns_packet_header)); + dns_header->tr_id = ntohs(dns_header->tr_id); + dns_header->flags = ntohs(dns_header->flags); + dns_header->num_queries = ntohs(dns_header->num_queries); + dns_header->num_answers = ntohs(dns_header->num_answers); + dns_header->authority_rrs = ntohs(dns_header->authority_rrs); + dns_header->additional_rrs = ntohs(dns_header->additional_rrs); + + x += sizeof(struct ndpi_dns_packet_header); + + /* 0x0000 QUERY */ + if((dns_header->flags & FLAGS_MASK) == 0x0000) + *is_query = 1; + /* 0x8000 RESPONSE */ + else if((dns_header->flags & FLAGS_MASK) == 0x8000) + *is_query = 0; + else + return(1 /* invalid */); + + if(*is_query) { + /* DNS Request */ + if((dns_header->num_queries > 0) && (dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) + && (((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */) + || ((dns_header->num_answers == 0) && (dns_header->authority_rrs == 0)))) { + /* This is a good query */ + while(x < flow->packet.payload_packet_len) { + if(flow->packet.payload[x] == '\0') { + x++; + flow->protos.dns.query_type = get16(&x, flow->packet.payload); +#ifdef DNS_DEBUG + NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type); + printf("[DNS] query_type=%d\n", flow->protos.dns.query_type); +#endif + break; + } else + x++; + } + } else + return(1 /* invalid */); + } else { + /* DNS Reply */ + flow->protos.dns.reply_code = dns_header->flags & 0x0F; + + if((dns_header->num_queries > 0) && (dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) /* Don't assume that num_queries must be zero */ + && (((dns_header->num_answers > 0) && (dns_header->num_answers <= NDPI_MAX_DNS_REQUESTS)) + || ((dns_header->authority_rrs > 0) && (dns_header->authority_rrs <= NDPI_MAX_DNS_REQUESTS)) + || ((dns_header->additional_rrs > 0) && (dns_header->additional_rrs <= NDPI_MAX_DNS_REQUESTS))) + ) { + /* This is a good reply: we dissect it both for request and response */ + + /* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */ + /* if(ndpi_struct->dns_dont_dissect_response == 0) */ { + x++; + + if(flow->packet.payload[x] != '\0') { + while((x < flow->packet.payload_packet_len) + && (flow->packet.payload[x] != '\0')) { + x++; + } + + x++; + } + + x += 4; + + if(dns_header->num_answers > 0) { + u_int16_t rsp_type; + u_int16_t num; + + for(num = 0; num < dns_header->num_answers; num++) { + u_int16_t data_len; + + if((x+6) >= flow->packet.payload_packet_len) { + break; + } + + if((data_len = getNameLength(x, flow->packet.payload, flow->packet.payload_packet_len)) == 0) { + break; + } else + x += data_len; + + rsp_type = get16(&x, flow->packet.payload); + flow->protos.dns.rsp_type = rsp_type; + + /* here x points to the response "class" field */ + if((x+12) <= flow->packet.payload_packet_len) { + x += 6; + data_len = get16(&x, flow->packet.payload); + + if(((x + data_len) <= flow->packet.payload_packet_len) + && (((rsp_type == 0x1) && (data_len == 4)) /* A */ +#ifdef NDPI_DETECTION_SUPPORT_IPV6 + || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */ +#endif + )) { + memcpy(&flow->protos.dns.rsp_addr, flow->packet.payload + x, data_len); + } + } + + break; + } + } + } + } else + return(1 /* invalid */); + } + + /* Valid */ + return(0); +} + /* *********************************************** */ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { - int x, payload_offset; + int payload_offset; u_int8_t is_query; u_int16_t s_port = 0, d_port = 0; @@ -94,191 +215,97 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd return; } - x = payload_offset; - if((s_port == 53 || d_port == 53 || d_port == 5355) - && (flow->packet.payload_packet_len > sizeof(struct ndpi_dns_packet_header)+x)) { + && (flow->packet.payload_packet_len > sizeof(struct ndpi_dns_packet_header)+payload_offset)) { struct ndpi_dns_packet_header dns_header; - int invalid = 0; - - memcpy(&dns_header, (struct ndpi_dns_packet_header*) &flow->packet.payload[x], sizeof(struct ndpi_dns_packet_header)); - dns_header.tr_id = ntohs(dns_header.tr_id); - dns_header.flags = ntohs(dns_header.flags); - dns_header.num_queries = ntohs(dns_header.num_queries); - dns_header.num_answers = ntohs(dns_header.num_answers); - dns_header.authority_rrs = ntohs(dns_header.authority_rrs); - dns_header.additional_rrs = ntohs(dns_header.additional_rrs); - x += sizeof(struct ndpi_dns_packet_header); - - /* 0x0000 QUERY */ - if((dns_header.flags & FLAGS_MASK) == 0x0000) - is_query = 1; - /* 0x8000 RESPONSE */ - else if((dns_header.flags & FLAGS_MASK) == 0x8000) - is_query = 0; - else - invalid = 1; - - if(!invalid) { - int j = 0, max_len, off; - if(is_query) { - /* DNS Request */ - if((dns_header.num_queries > 0) && (dns_header.num_queries <= NDPI_MAX_DNS_REQUESTS) - && (((dns_header.flags & 0x2800) == 0x2800 /* Dynamic DNS Update */) - || ((dns_header.num_answers == 0) && (dns_header.authority_rrs == 0)))) { - /* This is a good query */ - - while(x < flow->packet.payload_packet_len) { - if(flow->packet.payload[x] == '\0') { - x++; - flow->protos.dns.query_type = get16(&x, flow->packet.payload); -#ifdef DNS_DEBUG - NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type); -#endif - break; - } else - x++; - } - } else - invalid = 1; - } else { - /* DNS Reply */ - - flow->protos.dns.reply_code = dns_header.flags & 0x0F; - - if((dns_header.num_queries > 0) && (dns_header.num_queries <= NDPI_MAX_DNS_REQUESTS) /* Don't assume that num_queries must be zero */ - && (((dns_header.num_answers > 0) && (dns_header.num_answers <= NDPI_MAX_DNS_REQUESTS)) - || ((dns_header.authority_rrs > 0) && (dns_header.authority_rrs <= NDPI_MAX_DNS_REQUESTS)) - || ((dns_header.additional_rrs > 0) && (dns_header.additional_rrs <= NDPI_MAX_DNS_REQUESTS))) - ) { - /* This is a good reply: we dissect it both for request and response */ - - /* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */ - /* if(ndpi_struct->dns_dont_dissect_response == 0) */ { - x++; - - if(flow->packet.payload[x] != '\0') { - while((x < flow->packet.payload_packet_len) - && (flow->packet.payload[x] != '\0')) { - x++; - } - - x++; - } - - x += 4; - - if(dns_header.num_answers > 0) { - u_int16_t rsp_type; - u_int16_t num; - - for(num = 0; num < dns_header.num_answers; num++) { - u_int16_t data_len; - - if((x+6) >= flow->packet.payload_packet_len) { - break; - } - - if((data_len = getNameLength(x, flow->packet.payload, flow->packet.payload_packet_len)) == 0) { - break; - } else - x += data_len; + int j = 0, max_len, off; + int invalid = search_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query); + ndpi_protocol ret; + + ret.master_protocol = NDPI_PROTOCOL_UNKNOWN; + ret.app_protocol = (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS; + + if(invalid) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; + } - rsp_type = get16(&x, flow->packet.payload); - flow->protos.dns.rsp_type = rsp_type; + /* extract host name server */ + max_len = sizeof(flow->host_server_name)-1; + off = sizeof(struct ndpi_dns_packet_header) + payload_offset; - /* here x points to the response "class" field */ - if((x+12) <= flow->packet.payload_packet_len) { - x += 6; - data_len = get16(&x, flow->packet.payload); + while(j < max_len && off < flow->packet.payload_packet_len && flow->packet.payload[off] != '\0') { + uint8_t c, cl = flow->packet.payload[off++]; - if(((x + data_len) <= flow->packet.payload_packet_len) - && (((rsp_type == 0x1) && (data_len == 4)) /* A */ -#ifdef NDPI_DETECTION_SUPPORT_IPV6 - || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */ -#endif - )) { - memcpy(&flow->protos.dns.rsp_addr, flow->packet.payload + x, data_len); - } - } - - break; - } - } - } - } else - invalid = 1; + if( (cl & 0xc0) != 0 || // we not support compressed names in query + off + cl >= flow->packet.payload_packet_len) { + j = 0; + break; } - if(invalid) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; - } - - /* extract host name server */ - max_len = sizeof(flow->host_server_name)-1; - off = sizeof(struct ndpi_dns_packet_header) + payload_offset; - - while(j < max_len && off < flow->packet.payload_packet_len && flow->packet.payload[off] != '\0') { - uint8_t c, cl = flow->packet.payload[off++]; - - if( (cl & 0xc0) != 0 || // we not support compressed names in query - off + cl >= flow->packet.payload_packet_len) { - j = 0; - break; - } - - if(j && j < max_len) flow->host_server_name[j++] = '.'; - - while(j < max_len && cl != 0) { - c = flow->packet.payload[off++]; - flow->host_server_name[j++] = (dns_validchar[c >> 5] & (1 << (c & 0x1f))) ? c : '_'; - cl--; - } - } - flow->host_server_name[j] = '\0'; + if(j && j < max_len) flow->host_server_name[j++] = '.'; - if(is_query && (ndpi_struct->dns_dont_dissect_response == 0)) { - // dpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); - return; /* The response will set the verdict */ + while(j < max_len && cl != 0) { + c = flow->packet.payload[off++]; + flow->host_server_name[j++] = (dns_validchar[c >> 5] & (1 << (c & 0x1f))) ? c : '_'; + cl--; } + } + flow->host_server_name[j] = '\0'; + + if(j > 0) { + ndpi_protocol_match_result ret_match; + + ret.app_protocol = ndpi_match_host_subprotocol(ndpi_struct, flow, + (char *)flow->host_server_name, + strlen((const char*)flow->host_server_name), + &ret_match, + NDPI_PROTOCOL_DNS); + + if(ret_match.protocol_category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) + flow->category = ret_match.protocol_category; + + if(ret.app_protocol == NDPI_PROTOCOL_UNKNOWN) + ret.master_protocol = (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS; + else + ret.master_protocol = NDPI_PROTOCOL_DNS; + } + + if(is_query && (ndpi_struct->dns_dont_dissect_response == 0)) { + /* In this case we say that the protocol has been detected just to let apps carry on with their activities */ + ndpi_set_detected_protocol(ndpi_struct, flow, ret.app_protocol, ret.master_protocol); + return; /* The response will set the verdict */ + } - flow->protos.dns.num_queries = (u_int8_t)dns_header.num_queries, + flow->protos.dns.num_queries = (u_int8_t)dns_header.num_queries, flow->protos.dns.num_answers = (u_int8_t) (dns_header.num_answers + dns_header.authority_rrs + dns_header.additional_rrs); - if(j > 0) { - ndpi_protocol_match_result ret_match; - - ndpi_match_host_subprotocol(ndpi_struct, flow, - (char *)flow->host_server_name, - strlen((const char*)flow->host_server_name), - &ret_match, - NDPI_PROTOCOL_DNS); - } - #ifdef DNS_DEBUG - NDPI_LOG_DBG2(ndpi_struct, "[num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n", - flow->protos.dns.num_queries, flow->protos.dns.num_answers, - flow->protos.dns.reply_code, flow->protos.dns.rsp_type, flow->host_server_name - ); + NDPI_LOG_DBG2(ndpi_struct, "[num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n", + flow->protos.dns.num_queries, flow->protos.dns.num_answers, + flow->protos.dns.reply_code, flow->protos.dns.rsp_type, flow->host_server_name + ); #endif - if(flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { - /** - Do not set the protocol with DNS if ndpi_match_host_subprotocol() has - matched a subprotocol - **/ - NDPI_LOG_INFO(ndpi_struct, "found DNS\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); - } else { + if(flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { + /** + Do not set the protocol with DNS if ndpi_match_host_subprotocol() has + matched a subprotocol + **/ + NDPI_LOG_INFO(ndpi_struct, "found DNS\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, ret.app_protocol, ret.master_protocol); + } else { + if((flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_DNS) + || (flow->packet.detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) + ; + else NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - } } } } -void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) -{ +void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { ndpi_set_bitmask_protocol_detection("DNS", ndpi_struct, detection_bitmask, *id, NDPI_PROTOCOL_DNS, ndpi_search_dns, diff --git a/src/lib/protocols/skype.c b/src/lib/protocols/skype.c index 2f3aac2f6..8ada5d997 100644 --- a/src/lib/protocols/skype.c +++ b/src/lib/protocols/skype.c @@ -23,13 +23,6 @@ #include "ndpi_api.h" -static void ndpi_skype_report_protocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { - /* printf("-> payload_len=%u\n", flow->packet.payload_packet_len); */ - - NDPI_LOG_INFO(ndpi_struct, "found skype\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); -} - static int is_port(u_int16_t a, u_int16_t b, u_int16_t c) { return(((a == c) || (b == c)) ? 1 : 0); } @@ -60,7 +53,11 @@ static void ndpi_check_skype(struct ndpi_detection_module_struct *ndpi_struct, s ((payload_len >= 16) && (packet->payload[0] != 0x30) /* Avoid invalid SNMP detection */ && (packet->payload[2] == 0x02))) { - ndpi_skype_report_protocol(ndpi_struct, flow); + + if(is_port(sport, dport, 8801)) + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_ZOOM, NDPI_PROTOCOL_UNKNOWN); + else + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); } } @@ -90,7 +87,7 @@ static void ndpi_check_skype(struct ndpi_detection_module_struct *ndpi_struct, s /* printf("[SKYPE] %u/%u\n", ntohs(packet->tcp->source), ntohs(packet->tcp->dest)); */ NDPI_LOG_INFO(ndpi_struct, "found skype\n"); - ndpi_skype_report_protocol(ndpi_struct, flow); + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); } else { // printf("NO [SKYPE] payload_len=%u\n", payload_len); } diff --git a/src/lib/protocols/steam.c b/src/lib/protocols/steam.c index 0a737baf9..6e1034aee 100644 --- a/src/lib/protocols/steam.c +++ b/src/lib/protocols/steam.c @@ -1,6 +1,7 @@ /* * steam.c * + * Copyright (C) 2011-19 - ntop.org * Copyright (C) 2014 Tomasz Bujlow <tomasz@skatnet.dk> * * The signature is mostly based on the Libprotoident library @@ -242,52 +243,55 @@ static void ndpi_check_steam_udp3(struct ndpi_detection_module_struct *ndpi_stru void ndpi_search_steam(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; - /* Break after 20 packets. */ - if (flow->packet_counter > 20) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; - } - - /* skip marked or retransmitted packets */ - if (packet->tcp_retransmission != 0) { - return; - } - - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) { - return; - } - - NDPI_LOG_DBG(ndpi_struct, "search STEAM\n"); - ndpi_check_steam_http(ndpi_struct, flow); + if(flow->packet.udp != NULL) { + if(flow->packet_counter > 5) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; + } + + ndpi_check_steam_udp1(ndpi_struct, flow); - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) { - return; - } - - ndpi_check_steam_tcp(ndpi_struct, flow); + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) + return; - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) { - return; - } + ndpi_check_steam_udp2(ndpi_struct, flow); - ndpi_check_steam_udp1(ndpi_struct, flow); + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) + return; - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) { - return; - } + ndpi_check_steam_udp3(ndpi_struct, flow); + } else { + /* Break after 10 packets. */ + if(flow->packet_counter > 10) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; + } + + + /* skip marked or retransmitted packets */ + if(packet->tcp_retransmission != 0) { + return; + } + + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) + return; + + NDPI_LOG_DBG(ndpi_struct, "search STEAM\n"); + ndpi_check_steam_http(ndpi_struct, flow); - ndpi_check_steam_udp2(ndpi_struct, flow); + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) + return; + + ndpi_check_steam_tcp(ndpi_struct, flow); - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) { - return; + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STEAM) + return; } - - ndpi_check_steam_udp3(ndpi_struct, flow); } -void init_steam_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) -{ +void init_steam_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { ndpi_set_bitmask_protocol_detection("Steam", ndpi_struct, detection_bitmask, *id, NDPI_PROTOCOL_STEAM, ndpi_search_steam, diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index bf2eb0b86..448062f47 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -38,22 +38,6 @@ struct stun_packet_header { u_int8_t transaction_id[8]; }; -/* ************************************************************ */ - -static u_int8_t is_stun_based_proto(u_int16_t proto) { - - switch(proto) { - case NDPI_PROTOCOL_WHATSAPP_CALL: - case NDPI_PROTOCOL_MESSENGER: - case NDPI_PROTOCOL_HANGOUT_DUO: - case NDPI_PROTOCOL_SKYPE_CALL: - case NDPI_PROTOCOL_SIGNAL: - case NDPI_PROTOCOL_STUN: - return(1); - } - - return(0); -} /* ************************************************************ */ @@ -160,10 +144,11 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * const u_int16_t payload_length) { 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; - + int rc; + /* STUN over TCP does not look good */ - if(flow->packet.tcp) return(NDPI_IS_NOT_STUN); + if (flow->packet.tcp) + return(NDPI_IS_NOT_STUN); if(payload_length >= 512) { return(NDPI_IS_NOT_STUN); @@ -172,7 +157,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) { flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; - return(NDPI_IS_STUN); /* This is WhatsApp Voice */ + return(NDPI_IS_STUN); } else return(NDPI_IS_NOT_STUN); } @@ -183,52 +168,40 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * goto udp_stun_found; } - msg_type = ntohs(h->msg_type) /* & 0x3EEF */, msg_len = ntohs(h->msg_len); + msg_type = ntohs(h->msg_type), msg_len = ntohs(h->msg_len); + if(msg_type == 0) + return(NDPI_IS_NOT_STUN); + /* https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml */ - if(msg_type > 0x000C) { + if ((msg_type & 0x3EEF) > 0x000B && msg_type != 0x0800) { #ifdef DEBUG_STUN printf("[STUN] msg_type = %04X\n", msg_type); #endif - if(is_stun_based_proto(flow->guessed_host_protocol_id)) { - /* - In this case we have the detected the typical STUN pattern - of modern protocols where the flow starts as STUN and becomes - something else that has nothing to do with STUN anymore - */ - ndpi_int_stun_add_connection(ndpi_struct, flow, - flow->guessed_protocol_id, - flow->guessed_host_protocol_id); - return(NDPI_IS_STUN); - } - /* - If we're here it's because this does not look like STUN anymore - as this was a flow that started as STUN and turned into something - else. Let's investigate what is that about - */ - if(payload[0] == 0x16) { + If we're here it's because this does not look like STUN anymore + as this was a flow that started as STUN and turned into something + else. Let's investigate what is that about + */ + if (payload[0] == 0x16) { /* Let's check if this is DTLS used by some socials */ struct ndpi_packet_struct *packet = &flow->packet; - u_int16_t total_len, version = htons(*((u_int16_t*)&packet->payload[1])); - - switch(version) { - case 0xFEFF: /* DTLS 1.0 */ - case 0xFEFD: /* DTLS 1.2 */ - total_len = ntohs(*((u_int16_t*)&packet->payload[11]))+13; - - if(payload_length == total_len) { - /* This is DTLS and the only protocol we know behaves like this is signal */ - flow->guessed_host_protocol_id = NDPI_PROTOCOL_SIGNAL; - ndpi_int_stun_add_connection(ndpi_struct, flow, - flow->guessed_protocol_id, - flow->guessed_host_protocol_id); - return(NDPI_IS_STUN); - } + u_int16_t total_len, version = htons(*((u_int16_t*) &packet->payload[1])); + + switch (version) { + case 0xFEFF: /* DTLS 1.0 */ + case 0xFEFD: /* DTLS 1.2 */ + total_len = ntohs(*((u_int16_t*) &packet->payload[11])) + 13; + + if (payload_length == total_len) { + /* This is DTLS and the only protocol we know behaves like this is signal */ + flow->guessed_host_protocol_id = NDPI_PROTOCOL_SIGNAL; + return(NDPI_IS_STUN); + } } } - + return(NDPI_IS_NOT_STUN); } @@ -239,31 +212,32 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * printf("[STUN] Here we go\n");; #endif - if(ndpi_struct->stun_cache) { + if (ndpi_struct->stun_cache) { u_int16_t proto; u_int32_t key = get_stun_lru_key(flow, 0); - int rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto, 0 /* Don't remove it as it can be used for other connections */); + int rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto, + 0 /* Don't remove it as it can be used for other connections */); #ifdef DEBUG_LRU printf("[LRU] Searching %u\n", key); #endif - if(!rc) { + if (!rc) { key = get_stun_lru_key(flow, 1); - rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto, 0 /* Don't remove it as it can be used for other connections */); + rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto, + 0 /* Don't remove it as it can be used for other connections */); #ifdef DEBUG_LRU - printf("[LRU] Searching %u\n", key); + printf("[LRU] Searching %u\n", key); #endif } - if(rc) { + if (rc) { #ifdef DEBUG_LRU printf("[LRU] Cache FOUND %u / %u\n", key, proto); #endif - flow->guessed_host_protocol_id = proto, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - + flow->guessed_host_protocol_id = proto; return(NDPI_IS_STUN); } else { #ifdef DEBUG_LRU @@ -279,42 +253,34 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * if(msg_type == 0x01 /* Binding Request */) { flow->protos.stun_ssl.stun.num_binding_requests++; - if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE)) + if (!msg_len && flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE) flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; else flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - if(msg_len == 0) { + if (!msg_len) { /* flow->protos.stun_ssl.stun.num_udp_pkts++; */ return(NDPI_IS_NOT_STUN); /* This to keep analyzing STUN instead of giving up */ } } - if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN)) { + if (!msg_len && flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return(NDPI_IS_NOT_STUN); } flow->protos.stun_ssl.stun.num_udp_pkts++; - /* - printf("[msg_type: %04X][payload_length: %u][num_binding_request: %u]\n", - msg_type, payload_length, flow->protos.stun_ssl.stun.num_binding_requests); - */ - - if(((payload[0] == 0x80) - && (payload_length < 512) - && ((msg_len+20) <= payload_length)) /* WhatsApp Voice */) { + if((payload[0] == 0x80 && payload_length < 512 && ((msg_len+20) <= payload_length))) { flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; - return(NDPI_IS_STUN); /* This is WhatsApp Voice */ - } else if((payload[0] == 0x90) - && (((msg_len+11) == payload_length) /* WhatsApp Video */ - || (flow->protos.stun_ssl.stun.num_binding_requests >= 4))) { + return(NDPI_IS_STUN); /* This is WhatsApp Call */ + } else if((payload[0] == 0x90) && (((msg_len+11) == payload_length) || + (flow->protos.stun_ssl.stun.num_binding_requests >= 4))) { flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; - return(NDPI_IS_STUN); /* This is WhatsApp Video */ + return(NDPI_IS_STUN); /* This is WhatsApp Call */ } - if((payload[0] != 0x80) && ((msg_len+20) > payload_length)) + if (payload[0] != 0x80 && (msg_len + 20) > payload_length) return(NDPI_IS_NOT_STUN); else { switch(flow->guessed_protocol_id) { @@ -330,202 +296,186 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * } } - if(payload_length == (msg_len+20)) { - if(msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ { + if (payload_length == (msg_len+20)) { + if ((msg_type & 0x3EEF) <= 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 + 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 - */ + 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; + 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; + if (x) + len += 4-x; #ifdef DEBUG_STUN - printf("==> Attribute: %04X\n", attribute); + printf("==> Attribute: %04X\n", attribute); #endif - switch(attribute) { - // case 0x0008: /* Message Integrity */ - // case 0x0020: /* XOR-MAPPED-ADDRESSES */ - case 0x4000: - case 0x4001: - case 0x4002: - /* These are the only messages apparently whatsapp voice can use */ + switch(attribute) { + case 0x0103: + flow->guessed_host_protocol_id = NDPI_PROTOCOL_ZOOM; + return(NDPI_IS_STUN); break; + + case 0x4000: + case 0x4001: + case 0x4002: + /* These are the only messages apparently whatsapp voice can use */ + flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; + return(NDPI_IS_STUN); + break; - case 0x0014: /* Realm */ - { - u_int16_t realm_len = ntohs(*((u_int16_t*)&payload[offset+2])); + case 0x0014: /* Realm */ + { + u_int16_t realm_len = ntohs(*((u_int16_t*)&payload[offset+2])); - if(flow->host_server_name[0] == '\0') { - u_int j, i = (realm_len > sizeof(flow->host_server_name)) ? sizeof(flow->host_server_name) : realm_len; - u_int k = offset+4; + if(flow->host_server_name[0] == '\0') { + u_int j, i = (realm_len > sizeof(flow->host_server_name)) ? sizeof(flow->host_server_name) : realm_len; + u_int k = offset+4; - memset(flow->host_server_name, 0, sizeof(flow->host_server_name)); + memset(flow->host_server_name, 0, sizeof(flow->host_server_name)); - for(j=0; j<i; j++) - flow->host_server_name[j] = payload[k++]; + for(j=0; j<i; j++) + flow->host_server_name[j] = payload[k++]; #ifdef DEBUG_STUN - printf("==> [%s]\n", flow->host_server_name); + printf("==> [%s]\n", flow->host_server_name); #endif - if(strstr((char*)flow->host_server_name, "google.com") != NULL) { - flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - return(NDPI_IS_STUN); - } else if(strstr((char*)flow->host_server_name, "whispersystems.org") != NULL) { - flow->guessed_host_protocol_id = NDPI_PROTOCOL_SIGNAL, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - return(NDPI_IS_STUN); - } - } - } - break; - - case 0xC057: /* Messeger */ - if(msg_type == 0x0001) { - if((msg_len == 100) || (msg_len == 104)) { - flow->guessed_host_protocol_id = NDPI_PROTOCOL_MESSENGER, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - return(NDPI_IS_STUN); - } else if(msg_len == 76) { + if (strstr((char*) flow->host_server_name, "google.com") != NULL) { + flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; + return(NDPI_IS_STUN); + } else if (strstr((char*) flow->host_server_name, "whispersystems.org") != NULL) { + flow->guessed_host_protocol_id = NDPI_PROTOCOL_SIGNAL; + return(NDPI_IS_STUN); + } + } + } + break; + + case 0xC057: /* Messeger */ + if (msg_type == 0x0001) { + if ((msg_len == 100) || (msg_len == 104)) { + flow->guessed_host_protocol_id = NDPI_PROTOCOL_MESSENGER; + return(NDPI_IS_STUN); + } else if(msg_len == 76) { #if 0 - if(1) { - flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - return(NDPI_IS_NOT_STUN); /* This case is found also with signal traffic */ - } else - return(NDPI_IS_STUN); + if(1) { + flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; + return(NDPI_IS_NOT_STUN); /* This case is found also with signal traffic */ + } else + return(NDPI_IS_STUN); #endif - } - } - 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 */ + } + } + 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 */ #ifdef DEBUG_STUN - printf("==> Skype found\n"); + printf("==> Skype found\n"); #endif - flow->guessed_protocol_id = NDPI_PROTOCOL_SKYPE_CALL; - 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: - case 0x8006: /* This is found on skype calls) */ - /* printf("====>>>> %04X\n", attribute); */ + flow->guessed_host_protocol_id = NDPI_PROTOCOL_SKYPE_CALL; + 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: + case 0x8006: /* This is found on skype calls) */ + /* printf("====>>>> %04X\n", attribute); */ #ifdef DEBUG_STUN - printf("==> Skype (2) found\n"); + printf("==> Skype (2) found\n"); #endif - flow->guessed_protocol_id = NDPI_PROTOCOL_SKYPE_CALL; - return(NDPI_IS_STUN); - break; + flow->guessed_host_protocol_id = NDPI_PROTOCOL_SKYPE_CALL; + 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->guessed_protocol_id = NDPI_PROTOCOL_SKYPE_CALL; + 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))) { #ifdef DEBUG_STUN - printf("==> Skype (3) found\n"); + printf("==> Skype (3) found\n"); #endif - return(NDPI_IS_STUN); - } - break; + flow->guessed_host_protocol_id = NDPI_PROTOCOL_SKYPE_CALL; + return(NDPI_IS_STUN); + } + break; - case 0xFF03: - can_this_be_whatsapp_voice = 0; - flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; - break; + case 0xFF03: + flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; + return(NDPI_IS_STUN); + break; - default: - /* This means this STUN packet cannot be confused with whatsapp voice */ + default: #ifdef DEBUG_STUN - printf("==> %04X\n", attribute); + printf("==> %04X\n", attribute); #endif - can_this_be_whatsapp_voice = 0; - break; - } + break; + } - offset += len + 4; + offset += len + 4; } + goto udp_stun_found; } else if(msg_type == 0x0800) { flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; - return(NDPI_IS_STUN); /* This is WhatsApp */ + return(NDPI_IS_STUN); } } - if((flow->protos.stun_ssl.stun.num_udp_pkts > 0) && (msg_type <= 0x00FF)) { + if ((flow->protos.stun_ssl.stun.num_udp_pkts > 0) && (msg_type <= 0x00FF)) { flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; - return(NDPI_IS_STUN); /* This is WhatsApp Voice */ + return(NDPI_IS_STUN); } else return(NDPI_IS_NOT_STUN); - udp_stun_found: - if(can_this_be_whatsapp_voice) { - struct ndpi_packet_struct *packet = &flow->packet; - int rc; +udp_stun_found: + flow->protos.stun_ssl.stun.num_processed_pkts++; + + struct ndpi_packet_struct *packet = &flow->packet; - flow->protos.stun_ssl.stun.num_processed_pkts++; #ifdef DEBUG_STUN - printf("==>> NDPI_PROTOCOL_WHATSAPP_CALL\n"); + printf("==>> NDPI_PROTOCOL_WHATSAPP_CALL\n"); #endif - if((ntohs(packet->udp->source) == 3478) || (ntohs(packet->udp->dest) == 3478)) { - flow->guessed_host_protocol_id = (is_messenger_ip_address(ntohl(packet->iph->saddr)) || is_messenger_ip_address(ntohl(packet->iph->daddr))) ? - NDPI_PROTOCOL_MESSENGER : NDPI_PROTOCOL_WHATSAPP_CALL; - } else - flow->guessed_host_protocol_id = (is_google_ip_address(ntohl(packet->iph->saddr)) || is_google_ip_address(ntohl(packet->iph->daddr))) - ? NDPI_PROTOCOL_HANGOUT_DUO : NDPI_PROTOCOL_WHATSAPP_CALL; - - rc = (flow->protos.stun_ssl.stun.num_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN; - - if(rc == NDPI_IS_STUN) - ndpi_int_stun_add_connection(ndpi_struct, flow, - NDPI_IS_STUN, - flow->guessed_host_protocol_id); + if(is_messenger_ip_address(ntohl(packet->iph->saddr)) || is_messenger_ip_address(ntohl(packet->iph->daddr))) + flow->guessed_host_protocol_id = NDPI_PROTOCOL_MESSENGER; + else if(is_google_ip_address(ntohl(packet->iph->saddr)) || is_google_ip_address(ntohl(packet->iph->daddr))) + flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; + + rc = (flow->protos.stun_ssl.stun.num_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN; - return(rc); - } else { - /* - 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 - */ - return(NDPI_IS_NOT_STUN); - } + return rc; } + void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; @@ -557,7 +507,7 @@ 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) == NDPI_IS_STUN) { udp_stun_match: - if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) + if (flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; if(flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) { |