aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2024-04-08 10:24:51 +0200
committerGitHub <noreply@github.com>2024-04-08 10:24:51 +0200
commit1b3ef7d7b2dde9d58cb217d3d7fb6b14d6281153 (patch)
tree868ce2beb4ba9dbfbe40dd05c9a1b200e367439c /src
parentf5905a62c7fc1922d0b49e9399d56e8cfee69516 (diff)
STUN: improve extraction of Mapped-Address metadata (#2370)
Enable parsing of Mapped-Address attribute for all STUN flows: that means that STUN classification might require more packets. Add a configuration knob to enable/disable this feature. Note that we can have (any) STUN metadata also for flows *not* classified as STUN (because of DTLS). Add support for ipv6. Restore the correct extra dissection logic for Telegram flows.
Diffstat (limited to 'src')
-rw-r--r--src/include/ndpi_private.h1
-rw-r--r--src/include/ndpi_typedefs.h10
-rw-r--r--src/lib/ndpi_main.c1
-rw-r--r--src/lib/protocols/stun.c67
4 files changed, 55 insertions, 24 deletions
diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h
index b26803a3c..92afa1d24 100644
--- a/src/include/ndpi_private.h
+++ b/src/include/ndpi_private.h
@@ -249,6 +249,7 @@ struct ndpi_detection_module_config_struct {
int stun_opportunistic_tls_enabled;
int stun_max_packets_extra_dissection;
+ int stun_mapped_address_enabled;
int dns_subclassification_enabled;
int dns_parse_response_enabled;
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 58c9d7df5..4f1935776 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1287,8 +1287,12 @@ struct ndpi_flow_struct {
struct {
u_int8_t maybe_dtls : 1, is_turn : 1, pad : 6;
struct {
- u_int32_t ipv4;
+ union {
+ u_int32_t v4;
+ u_int8_t v6[16];
+ } address; /* Network-order */
u_int16_t port;
+ u_int16_t is_ipv6: 1, _pad: 15;
} mapped_address;
} stun;
@@ -1513,8 +1517,8 @@ struct ndpi_flow_struct {
_Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 256,
"Size of the struct member protocols increased to more than 256 bytes, "
"please check if this change is necessary.");
-_Static_assert(sizeof(struct ndpi_flow_struct) <= 1024,
- "Size of the flow struct increased to more than 1024 bytes, "
+_Static_assert(sizeof(struct ndpi_flow_struct) <= 1032,
+ "Size of the flow struct increased to more than 1032 bytes, "
"please check if this change is necessary.");
#endif
#endif
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index e0150fe6c..c2583accc 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -11216,6 +11216,7 @@ static const struct cfg_param {
{ "stun", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(stun_opportunistic_tls_enabled), NULL },
{ "stun", "max_packets_extra_dissection", "4", "0", "255", CFG_PARAM_INT, __OFF(stun_max_packets_extra_dissection), NULL },
+ { "stun", "metadata.attribute.mapped_address", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(stun_mapped_address_enabled), NULL },
{ "dns", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(dns_subclassification_enabled), NULL },
{ "dns", "process_response", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(dns_parse_response_enabled), NULL },
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c
index 4e77cc532..cb0b3f001 100644
--- a/src/lib/protocols/stun.c
+++ b/src/lib/protocols/stun.c
@@ -402,9 +402,7 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct,
case 0x4007:
/* These are the only messages apparently whatsapp voice can use */
*app_proto = NDPI_PROTOCOL_WHATSAPP_CALL;
- flow->max_extra_packets_to_check = ndpi_struct->cfg.stun_max_packets_extra_dissection;
- flow->extra_packets_func = stun_search_again;
- return 1;
+ break;
case 0x0014: /* Realm */
if(flow->host_server_name[0] == '\0') {
@@ -442,7 +440,7 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct,
case 0x8070: /* MS Implementation Version */
case 0x8055: /* MS Service Quality */
*app_proto = NDPI_PROTOCOL_SKYPE_TEAMS_CALL;
- return 1;
+ break;
case 0xFF03:
*app_proto = NDPI_PROTOCOL_GOOGLE_CALL;
@@ -466,7 +464,8 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct,
break;
case 0x0020: /* XOR-MAPPED-ADDRESS */
- if(real_len <= payload_length - off - 12) {
+ if(ndpi_struct->cfg.stun_mapped_address_enabled &&
+ real_len <= payload_length - off - 12) {
u_int8_t protocol_family = payload[off+5];
if(protocol_family == 0x01 /* IPv4 */) {
@@ -475,8 +474,22 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t port_xor = (magic_cookie >> 16) & 0xFFFF;
flow->stun.mapped_address.port = xored_port ^ port_xor;
- flow->stun.mapped_address.ipv4 = xored_ip ^ magic_cookie;
- flow->extra_packets_func = NULL; /* We're good now */
+ flow->stun.mapped_address.address.v4 = htonl(xored_ip ^ magic_cookie);
+ flow->stun.mapped_address.is_ipv6 = 0;
+ } else if(protocol_family == 0x02 /* IPv6 */ &&
+ real_len <= payload_length - off - 24) {
+ u_int32_t ip[4];
+ u_int16_t port;
+
+ port = ntohs(*((u_int16_t *)&payload[off + 6])) ^ (magic_cookie >> 16);
+ ip[0] = *((u_int32_t *)&payload[off + 8]) ^ htonl(magic_cookie);
+ ip[1] = *((u_int32_t *)&payload[off + 12]) ^ htonl(transaction_id[0]);
+ ip[2] = *((u_int32_t *)&payload[off + 16]) ^ htonl(transaction_id[1]);
+ ip[3] = *((u_int32_t *)&payload[off + 20]) ^ htonl(transaction_id[2]);
+
+ flow->stun.mapped_address.port = port;
+ memcpy(&flow->stun.mapped_address.address, &ip, 16);
+ flow->stun.mapped_address.is_ipv6 = 1;
}
}
break;
@@ -492,16 +505,25 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct,
return 1;
}
-static int keep_extra_dissection(struct ndpi_flow_struct *flow)
+static int keep_extra_dissection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
{
if(!is_subclassification_real(flow))
return 1;
- /* Looking for XOR-PEER-ADDRESS metadata; TODO: other protocols? */
- if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TELEGRAM_VOIP)
- || (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_WHATSAPP_CALL))
+ /* See the comment at the end of ndpi_int_stun_add_connection()
+ where we set the extra dissection */
+
+ if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TELEGRAM_VOIP)
return 1;
- return 0;
+
+ if(ndpi_struct->cfg.stun_mapped_address_enabled &&
+ flow->stun.mapped_address.port)
+ return 0;
+ if(!ndpi_struct->cfg.stun_mapped_address_enabled)
+ return 0;
+
+ return 1;
}
static u_int32_t __get_master(struct ndpi_flow_struct *flow) {
@@ -694,7 +716,7 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct,
} else {
NDPI_LOG_DBG(ndpi_struct, "QUIC range. Unexpected\n");
}
- return keep_extra_dissection(flow);
+ return keep_extra_dissection(ndpi_struct, flow);
}
/* ************************************************************ */
@@ -822,16 +844,19 @@ static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *nd
/* We want extra dissection for:
* sub-classification
- * metadata extraction or looking for RTP
- The latter is enabled only without sub-classification or for Telegram
- (to find all XOR-PEER-ADDRESS attributes)
+ * metadata extraction (XOR-PEER-ADDRESS/XOR-MAPPED-ADDRESS) or looking for RTP
+ At the moment:
+ * it seems ZOOM doens't have any meaningful attributes
+ * we want XOR-MAPPED-ADDRESS only for Telegram -> we can stop after (the first)
+ XOR-MAPPED-ADDRESS for all the other sub-protocols
*/
if(!flow->extra_packets_func) {
- if(!is_subclassification_real(flow) ||
- flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TELEGRAM_VOIP /* Metadata. TODO: other protocols? */) {
- NDPI_LOG_DBG(ndpi_struct, "Enabling extra dissection\n");
- flow->max_extra_packets_to_check = ndpi_struct->cfg.stun_max_packets_extra_dissection;
- flow->extra_packets_func = stun_search_again;
+ if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_ZOOM) {
+ if(keep_extra_dissection(ndpi_struct, flow)) {
+ NDPI_LOG_DBG(ndpi_struct, "Enabling extra dissection\n");
+ flow->max_extra_packets_to_check = ndpi_struct->cfg.stun_max_packets_extra_dissection;
+ flow->extra_packets_func = stun_search_again;
+ }
}
}
}