aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/dns.c101
-rw-r--r--src/lib/protocols/dnscrypt.c69
-rw-r--r--src/lib/protocols/http.c174
-rw-r--r--src/lib/protocols/kerberos.c4
-rw-r--r--src/lib/protocols/mdns_proto.c153
-rw-r--r--src/lib/protocols/netbios.c2
-rw-r--r--src/lib/protocols/quic.c74
-rw-r--r--src/lib/protocols/teamspeak.c68
-rw-r--r--src/lib/protocols/tls.c69
-rw-r--r--src/lib/protocols/tor.c2
10 files changed, 400 insertions, 316 deletions
diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c
index 5e6d01d69..12c6d0338 100644
--- a/src/lib/protocols/dns.c
+++ b/src/lib/protocols/dns.c
@@ -27,15 +27,47 @@
#include "ndpi_api.h"
-
#define FLAGS_MASK 0x8000
-// #define DNS_DEBUG 1
+/* #define DNS_DEBUG 1 */
+
+#define DNS_PORT 53
+#define LLMNR_PORT 5355
+#define MDNS_PORT 5353
static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow);
/* *********************************************** */
+static u_int16_t checkPort(u_int16_t port) {
+ switch(port) {
+ case DNS_PORT:
+ return(NDPI_PROTOCOL_DNS);
+ break;
+ case LLMNR_PORT:
+ return(NDPI_PROTOCOL_LLMNR);
+ break;
+ case MDNS_PORT:
+ return(NDPI_PROTOCOL_MDNS);
+ break;
+ }
+
+ return(0);
+}
+
+/* *********************************************** */
+
+static u_int16_t checkDNSSubprotocol(u_int16_t sport, u_int16_t dport) {
+ u_int16_t rc = checkPort(sport);
+
+ if(rc == 0)
+ return(checkPort(dport));
+ else
+ return(rc);
+}
+
+/* *********************************************** */
+
static u_int16_t get16(int *i, const u_int8_t *payload) {
u_int16_t v = *(u_int16_t*)&payload[*i];
@@ -108,7 +140,7 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
NDPI_SET_BIT(flow->risk, NDPI_MALFORMED_PACKET);
return(1 /* invalid */);
}
-
+
if(*is_query) {
/* DNS Request */
if((dns_header->num_queries > 0) && (dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS)
@@ -182,7 +214,7 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
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) {
// printf("[rsp_type: %u][data_len: %u]\n", rsp_type, data_len);
@@ -190,7 +222,7 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
x += data_len;
continue; /* Skip CNAME */
}
-
+
if((((rsp_type == 0x1) && (data_len == 4)) /* A */
#ifdef NDPI_DETECTION_SUPPORT_IPV6
|| ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */
@@ -200,11 +232,11 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
}
}
}
-
+
break;
}
}
-
+
if((flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_DNS)
|| (flow->packet.detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) {
/* Request already set the protocol */
@@ -212,10 +244,8 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
} else {
/* We missed the request */
u_int16_t s_port = flow->packet.udp ? ntohs(flow->packet.udp->source) : ntohs(flow->packet.tcp->source);
-
- ndpi_set_detected_protocol(ndpi_struct, flow,
- (s_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS,
- NDPI_PROTOCOL_UNKNOWN);
+
+ ndpi_set_detected_protocol(ndpi_struct, flow, checkPort(s_port), NDPI_PROTOCOL_UNKNOWN);
}
}
}
@@ -256,15 +286,18 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
return;
}
- if((s_port == 53 || d_port == 53 || d_port == 5355)
+ if(((s_port == DNS_PORT) || (d_port == DNS_PORT)
+ || (s_port == MDNS_PORT) || (d_port == MDNS_PORT)
+ || (d_port == LLMNR_PORT))
&& (flow->packet.payload_packet_len > sizeof(struct ndpi_dns_packet_header)+payload_offset)) {
struct ndpi_dns_packet_header dns_header;
int j = 0, max_len, off;
int invalid = search_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query);
ndpi_protocol ret;
+ u_int num_queries, idx;
- ret.master_protocol = NDPI_PROTOCOL_UNKNOWN;
- ret.app_protocol = (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS;
+ ret.master_protocol = NDPI_PROTOCOL_UNKNOWN;
+ ret.app_protocol = (d_port == LLMNR_PORT) ? NDPI_PROTOCOL_LLMNR : ((d_port == MDNS_PORT) ? NDPI_PROTOCOL_MDNS : NDPI_PROTOCOL_DNS);
if(invalid) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
@@ -274,7 +307,35 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
/* extract host name server */
max_len = sizeof(flow->host_server_name)-1;
off = sizeof(struct ndpi_dns_packet_header) + payload_offset;
-
+
+ /* Before continuing let's dissect the following queries to see if they are valid */
+ for(idx=off, num_queries=0; (num_queries < dns_header.num_queries) && (idx < flow->packet.payload_packet_len);) {
+ u_int8_t name_len = flow->packet.payload[idx];
+
+#ifdef DNS_DEBUG
+ printf("[DNS] [name_len: %u]\n", name_len);
+#endif
+
+ if(name_len == 0) {
+ /* End of query */
+ num_queries++;
+ idx += 5;
+ continue;
+ }
+
+ if((name_len+idx) >= flow->packet.payload_packet_len) {
+ /* Invalid */
+#ifdef DNS_DEBUG
+ printf("[DNS] Invalid query len [%u >= %u]\n",
+ (name_len+idx),
+ flow->packet.payload_packet_len);
+#endif
+ NDPI_SET_BIT(flow->risk, NDPI_MALFORMED_PACKET);
+ break;
+ } else
+ idx += name_len+1;
+ }
+
while(j < max_len && off < flow->packet.payload_packet_len && flow->packet.payload[off] != '\0') {
uint8_t c, cl = flow->packet.payload[off++];
@@ -288,7 +349,7 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
while(j < max_len && cl != 0) {
u_int32_t shift;
-
+
c = flow->packet.payload[off++];
shift = ((u_int32_t) 1) << (c & 0x1f);
flow->host_server_name[j++] = tolower((dns_validchar[c >> 5] & shift) ? c : '_');
@@ -297,12 +358,12 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
}
flow->host_server_name[j] = '\0';
-
+
if(j > 0) {
ndpi_protocol_match_result ret_match;
- ndpi_check_dga_name(ndpi_struct, flow, (char*)flow->host_server_name);
-
+ ndpi_check_dga_name(ndpi_struct, flow, (char*)flow->host_server_name, 1);
+
ret.app_protocol = ndpi_match_host_subprotocol(ndpi_struct, flow,
(char *)flow->host_server_name,
strlen((const char*)flow->host_server_name),
@@ -313,7 +374,7 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
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;
+ ret.master_protocol = checkDNSSubprotocol(s_port, d_port);
else
ret.master_protocol = NDPI_PROTOCOL_DNS;
}
diff --git a/src/lib/protocols/dnscrypt.c b/src/lib/protocols/dnscrypt.c
new file mode 100644
index 000000000..6c89466f1
--- /dev/null
+++ b/src/lib/protocols/dnscrypt.c
@@ -0,0 +1,69 @@
+/*
+ * dnscrypt.c
+ *
+ * Copyright (C) 2020 - ntop.org
+ *
+ * nDPI is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nDPI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with nDPI. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "ndpi_protocol_ids.h"
+
+#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_DNSCRYPT
+
+#include "ndpi_api.h"
+
+static void ndpi_int_dnscrypt_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_DNSCRYPT, NDPI_PROTOCOL_UNKNOWN);
+}
+
+void ndpi_search_dnscrypt(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct *packet = &flow->packet;
+ static char const * const dnscrypt_initial = "2\rdnscrypt";
+
+ NDPI_LOG_DBG(ndpi_struct, "search dnscrypt\n");
+
+ if (flow->packet_counter > 2)
+ {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ }
+
+ /* dnscrypt protocol version 1: check magic */
+ if (packet->payload_packet_len >= 64 &&
+ strncmp((char*)packet->payload, "r6fnvWj8", strlen("r6fnvWj8")) == 0)
+ {
+ ndpi_int_dnscrypt_add_connection(ndpi_struct, flow);
+ }
+ /* dnscrypt protocol version 1 and 2: resolver ping */
+ if (packet->payload_packet_len > 13 + strlen(dnscrypt_initial) &&
+ strncasecmp((char*)packet->payload + 13, dnscrypt_initial, strlen(dnscrypt_initial)) == 0)
+ {
+ ndpi_int_dnscrypt_add_connection(ndpi_struct, flow);
+ }
+}
+
+void init_dnscrypt_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id,
+ NDPI_PROTOCOL_BITMASK *detection_bitmask)
+{
+ ndpi_set_bitmask_protocol_detection(
+ "DNScrypt", ndpi_struct, detection_bitmask, *id,
+ NDPI_PROTOCOL_DNSCRYPT, ndpi_search_dnscrypt, 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/http.c b/src/lib/protocols/http.c
index 0e3e0d413..983a53b1c 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -263,21 +263,102 @@ static void ndpi_check_user_agent(struct ndpi_detection_module_struct *ndpi_stru
char *ua) {
if((!ua) || (ua[0] == '\0')) return;
- // printf("***** [%s:%d] ==> '%s'\n", __FILE__, __LINE__, ua);
- // printf("***** %u\n", ndpi_check_dga_name(ndpi_struct, NULL, "uclient-fetch]"));
-
if((strlen(ua) < 4)
|| (!strncmp(ua, "test", 4))
|| (!strncmp(ua, "<?", 2))
|| strchr(ua, '{')
|| strchr(ua, '}')
- || ndpi_check_dga_name(ndpi_struct, NULL, ua)
+ || ndpi_check_dga_name(ndpi_struct, NULL, ua, 0)
// || ndpi_match_bigram(ndpi_struct, &ndpi_struct->impossible_bigrams_automa, ua)
) {
NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_USER_AGENT);
}
}
+int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ const u_int8_t *ua_ptr, u_int16_t ua_ptr_len)
+{
+ /**
+ Format examples:
+ Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) ....
+ Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0
+ */
+ if(ua_ptr_len > 7) {
+ char ua[256];
+ u_int mlen = ndpi_min(ua_ptr_len, sizeof(ua)-1);
+
+ strncpy(ua, (const char *)ua_ptr, mlen);
+ ua[mlen] = '\0';
+
+ if(strncmp(ua, "Mozilla", 7) == 0) {
+ char *parent = strchr(ua, '(');
+
+ if(parent) {
+ char *token, *end;
+
+ parent++;
+ end = strchr(parent, ')');
+ if(end) end[0] = '\0';
+
+ token = strsep(&parent, ";");
+ if(token) {
+ if((strcmp(token, "X11") == 0)
+ || (strcmp(token, "compatible") == 0)
+ || (strcmp(token, "Linux") == 0)
+ || (strcmp(token, "Macintosh") == 0)
+ ) {
+ token = strsep(&parent, ";");
+ if(token && (token[0] == ' ')) token++; /* Skip space */
+
+ if(token
+ && ((strcmp(token, "U") == 0)
+ || (strncmp(token, "MSIE", 4) == 0))) {
+ token = strsep(&parent, ";");
+ if(token && (token[0] == ' ')) token++; /* Skip space */
+
+ if(token && (strncmp(token, "Update", 6) == 0)) {
+ token = strsep(&parent, ";");
+
+ if(token && (token[0] == ' ')) token++; /* Skip space */
+
+ if(token && (strncmp(token, "AOL", 3) == 0)) {
+
+ token = strsep(&parent, ";");
+ if(token && (token[0] == ' ')) token++; /* Skip space */
+ }
+ }
+ }
+ }
+
+ if(token)
+ setHttpUserAgent(ndpi_struct, flow, token);
+ }
+ }
+ } else if((ua_ptr_len > 14) && (memcmp(ua, "netflix-ios-app", 15) == 0)) {
+ NDPI_LOG_INFO(ndpi_struct, "found netflix\n");
+ ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_NETFLIX, NDPI_PROTOCOL_CATEGORY_STREAMING);
+ return -1;
+ }
+ }
+
+ if(flow->http.user_agent == NULL) {
+ int len = ua_ptr_len + 1;
+
+ flow->http.user_agent = ndpi_malloc(len);
+ if(flow->http.user_agent) {
+ strncpy(flow->http.user_agent, (char*)ua_ptr, ua_ptr_len);
+ flow->http.user_agent[ua_ptr_len] = '\0';
+
+ ndpi_check_user_agent(ndpi_struct, flow, flow->http.user_agent);
+ }
+ }
+
+ NDPI_LOG_DBG2(ndpi_struct, "User Agent Type line found %.*s\n",
+ ua_ptr_len, ua_ptr);
+ return 0;
+}
+
/* ************************************************************* */
static void ndpi_check_numeric_ip(struct ndpi_detection_module_struct *ndpi_struct,
@@ -311,6 +392,7 @@ static void ndpi_check_http_url(struct ndpi_detection_module_struct *ndpi_struct
static void check_content_type_and_change_protocol(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
+ int ret;
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HTTP, NDPI_PROTOCOL_UNKNOWN);
@@ -345,84 +427,10 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
}
if(packet->user_agent_line.ptr != NULL && packet->user_agent_line.len != 0) {
- /**
- Format examples:
- Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) ....
- Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0
- */
- if(packet->user_agent_line.len > 7) {
- char ua[256];
- u_int mlen = ndpi_min(packet->user_agent_line.len, sizeof(ua)-1);
-
- strncpy(ua, (const char *)packet->user_agent_line.ptr, mlen);
- ua[mlen] = '\0';
-
- if(strncmp(ua, "Mozilla", 7) == 0) {
- char *parent = strchr(ua, '(');
-
- if(parent) {
- char *token, *end;
-
- parent++;
- end = strchr(parent, ')');
- if(end) end[0] = '\0';
-
- token = strsep(&parent, ";");
- if(token) {
- if((strcmp(token, "X11") == 0)
- || (strcmp(token, "compatible") == 0)
- || (strcmp(token, "Linux") == 0)
- || (strcmp(token, "Macintosh") == 0)
- ) {
- token = strsep(&parent, ";");
- if(token && (token[0] == ' ')) token++; /* Skip space */
-
- if(token
- && ((strcmp(token, "U") == 0)
- || (strncmp(token, "MSIE", 4) == 0))) {
- token = strsep(&parent, ";");
- if(token && (token[0] == ' ')) token++; /* Skip space */
-
- if(token && (strncmp(token, "Update", 6) == 0)) {
- token = strsep(&parent, ";");
-
- if(token && (token[0] == ' ')) token++; /* Skip space */
-
- if(token && (strncmp(token, "AOL", 3) == 0)) {
-
- token = strsep(&parent, ";");
- if(token && (token[0] == ' ')) token++; /* Skip space */
- }
- }
- }
- }
-
- if(token)
- setHttpUserAgent(ndpi_struct, flow, token);
- }
- }
- } else if((packet->user_agent_line.len > 14) && (memcmp(ua, "netflix-ios-app", 15) == 0)) {
- NDPI_LOG_INFO(ndpi_struct, "found netflix\n");
- ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_NETFLIX, NDPI_PROTOCOL_CATEGORY_STREAMING);
- return;
- }
- }
-
- if(flow->http.user_agent == NULL) {
- int len = packet->user_agent_line.len + 1;
-
- flow->http.user_agent = ndpi_malloc(len);
- if(flow->http.user_agent) {
- strncpy(flow->http.user_agent, (char*)packet->user_agent_line.ptr,
- packet->user_agent_line.len);
- flow->http.user_agent[packet->user_agent_line.len] = '\0';
-
- ndpi_check_user_agent(ndpi_struct, flow, flow->http.user_agent);
- }
- }
-
- NDPI_LOG_DBG2(ndpi_struct, "User Agent Type line found %.*s\n",
- packet->user_agent_line.len, packet->user_agent_line.ptr);
+ ret = http_process_user_agent(ndpi_struct, flow, packet->user_agent_line.ptr, packet->user_agent_line.len);
+ /* TODO: Is it correct to avoid setting ua, host_name,... if we have a (Netflix) subclassification? */
+ if(ret != 0)
+ return;
}
/* check for host line */
@@ -438,7 +446,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
flow->host_server_name[len] = '\0';
flow->extra_packets_func = NULL; /* We're good now */
- if(len > 0) ndpi_check_dga_name(ndpi_struct, flow, (char*)flow->host_server_name);
+ if(len > 0) ndpi_check_dga_name(ndpi_struct, flow, (char*)flow->host_server_name, 1);
flow->server_id = flow->dst;
if(packet->forwarded_line.ptr) {
diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c
index 10c2b5a65..fa0ab6cb6 100644
--- a/src/lib/protocols/kerberos.c
+++ b/src/lib/protocols/kerberos.c
@@ -252,7 +252,9 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct,
realm_offset = cname_len + name_offset + 3;
/* if cname does not end with a $ then it's a username */
- if(cname_len && cname_str[cname_len-1] == '$') {
+ if(cname_len
+ && (cname_len < sizeof(cname_str))
+ && (cname_str[cname_len-1] == '$')) {
cname_str[cname_len-1] = '\0';
snprintf(flow->protos.kerberos.hostname, sizeof(flow->protos.kerberos.hostname), "%s", cname_str);
} else
diff --git a/src/lib/protocols/mdns_proto.c b/src/lib/protocols/mdns_proto.c
deleted file mode 100644
index 2b75f19ec..000000000
--- a/src/lib/protocols/mdns_proto.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * mdns.c
- *
- * Copyright (C) 2016-20 - ntop.org
- *
- * This file is part of nDPI, an open source deep packet inspection
- * library based on the OpenDPI and PACE technology by ipoque GmbH
- *
- * nDPI is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * nDPI is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with nDPI. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-#include "ndpi_protocol_ids.h"
-
-#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_MDNS
-
-#include "ndpi_api.h"
-
-#define NDPI_MAX_MDNS_REQUESTS 128
-
-PACK_ON
-struct mdns_header {
- u_int16_t transaction_id, flags, questions, answers, authority_rr, additional_rr;
-} PACK_OFF;
-
-/**
- MDNS header is similar to dns header
-
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | ID = 0x0000 |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | FLAGS |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | QDCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | ANCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | NSCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- | ARCOUNT |
- +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-*/
-
-
-static void ndpi_int_mdns_add_connection(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MDNS, NDPI_PROTOCOL_UNKNOWN);
-}
-
-static int ndpi_int_check_mdns_payload(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow) {
- struct ndpi_packet_struct *packet = &flow->packet;
- struct mdns_header *h = (struct mdns_header*)packet->payload;
- u_int16_t questions = ntohs(h->questions), answers = ntohs(h->answers);
-
- if((questions > NDPI_MAX_MDNS_REQUESTS)
- || (answers > NDPI_MAX_MDNS_REQUESTS))
- return(0);
-
- if((packet->payload[2] & 0x80) == 0) {
- NDPI_LOG_INFO(ndpi_struct, "found MDNS with question query\n");
- return 1;
- } else if((packet->payload[2] & 0x80) != 0) {
- char answer[256];
- int i, j, len;
-
- for(i=13, j=0; (i < packet->payload_packet_len) && (i < (sizeof(answer)-1)) && (packet->payload[i] != 0); i++)
- answer[j++] = (packet->payload[i] < 13) ? '.' : packet->payload[i];
-
- answer[j] = '\0';
-
- /* printf("==> [%d] %s\n", j, answer); */
-
- len = ndpi_min(sizeof(flow->protos.mdns.answer)-1, j);
- strncpy(flow->protos.mdns.answer, (const char *)answer, len);
- flow->protos.mdns.answer[len] = '\0';
-
- NDPI_LOG_INFO(ndpi_struct, "found MDNS with answer query\n");
- return 1;
- }
-
- return 0;
-}
-
-void ndpi_search_mdns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
-{
- struct ndpi_packet_struct *packet = &flow->packet;
- NDPI_LOG_DBG(ndpi_struct, "search MDNS\n");
-
- /**
- information from http://www.it-administrator.de/lexikon/multicast-dns.html
- */
-
- /* check if UDP packet */
- if(packet->udp != NULL) {
- /* read destination port */
- u_int16_t sport = ntohs(packet->udp->source);
- u_int16_t dport = ntohs(packet->udp->dest);
-
- /* check standard MDNS ON port 5353 */
- if(((dport == 5353) || (sport == 5353))
- && (packet->payload_packet_len >= 12)) {
- if(packet->iph != NULL) {
- if(ndpi_int_check_mdns_payload(ndpi_struct, flow) == 1) {
- ndpi_int_mdns_add_connection(ndpi_struct, flow);
- return;
- }
- }
-#ifdef NDPI_DETECTION_SUPPORT_IPV6
- if(packet->iphv6 != NULL) {
- u_int32_t daddr_0 = packet->iphv6->ip6_dst.u6_addr.u6_addr32[0];
-
- if(daddr_0 == htonl(0xff020000) /* && daddr[1] == 0 && daddr[2] == 0 && daddr[3] == htonl(0xfb) */) {
-
- NDPI_LOG_INFO(ndpi_struct, "found MDNS with destination address ff02::fb\n");
-
- if(ndpi_int_check_mdns_payload(ndpi_struct, flow) == 1) {
- ndpi_int_mdns_add_connection(ndpi_struct, flow);
- return;
- }
- }
- }
-#endif
- }
- }
-
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
-}
-
-
-void init_mdns_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
-{
- ndpi_set_bitmask_protocol_detection("MDNS", ndpi_struct, detection_bitmask, *id,
- NDPI_PROTOCOL_MDNS,
- ndpi_search_mdns,
- NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD,
- SAVE_DETECTION_BITMASK_AS_UNKNOWN,
- ADD_TO_DETECTION_BITMASK);
-
- *id += 1;
-}
-
diff --git a/src/lib/protocols/netbios.c b/src/lib/protocols/netbios.c
index 6ca691c7e..1f3850cbd 100644
--- a/src/lib/protocols/netbios.c
+++ b/src/lib/protocols/netbios.c
@@ -85,7 +85,7 @@ static void ndpi_int_netbios_add_connection(struct ndpi_detection_module_struct
flow->packet.payload_packet_len - off, name, sizeof(name)) > 0) {
snprintf((char*)flow->host_server_name, sizeof(flow->host_server_name)-1, "%s", name);
- ndpi_check_dga_name(ndpi_struct, flow, (char*)flow->host_server_name);
+ ndpi_check_dga_name(ndpi_struct, flow, (char*)flow->host_server_name, 1);
}
if(sub_protocol == NDPI_PROTOCOL_UNKNOWN)
diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c
index 84ad23799..2a4c7294b 100644
--- a/src/lib/protocols/quic.c
+++ b/src/lib/protocols/quic.c
@@ -43,7 +43,10 @@
*/
extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow, int is_quic);
+ struct ndpi_flow_struct *flow, uint32_t quic_version);
+extern int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ const u_int8_t *ua_ptr, u_int16_t ua_ptr_len);
/* Versions */
#define V_Q024 0x51303234
@@ -141,9 +144,13 @@ static int is_version_with_tls(uint32_t version)
return is_version_quic(version) ||
((version & 0xFFFFFF00) == 0x54303500) /* T05X */;
}
+int is_version_with_var_int_transport_params(uint32_t version)
+{
+ return (is_version_quic(version) && is_quic_ver_greater_than(version, 27)) ||
+ (version == V_T051);
+}
-
-static int quic_len(const uint8_t *buf, uint64_t *value)
+int quic_len(const uint8_t *buf, uint64_t *value)
{
*value = buf[0];
switch((*value) >> 6) {
@@ -163,6 +170,22 @@ static int quic_len(const uint8_t *buf, uint64_t *value)
return 0;
}
}
+int quic_len_buffer_still_required(uint8_t value)
+{
+ switch(value >> 6) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 3;
+ case 3:
+ return 7;
+ default: /* No Possible */
+ return 0;
+ }
+}
+
static uint16_t gquic_get_u16(const uint8_t *buf, uint32_t version)
{
@@ -903,7 +926,9 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_
if(counter + 2 + offset_len + 2 /*gquic_get_u16 reads 2 bytes */ > clear_payload_len)
return NULL;
if(clear_payload[counter + 1] != 0x01) {
+#ifdef QUIC_DEBUG
NDPI_LOG_ERR(ndpi_struct, "Unexpected stream ID version 0x%x\n", version);
+#endif
return NULL;
}
counter += 2 + offset_len;
@@ -936,7 +961,9 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_
if(first_nonzero_payload_byte != 0x06) {
if(first_nonzero_payload_byte != 0x02 &&
first_nonzero_payload_byte != 0x1C) {
+#ifdef QUIC_DEBUG
NDPI_LOG_ERR(ndpi_struct, "Unexpected frame 0x%x\n", first_nonzero_payload_byte);
+#endif
} else {
NDPI_LOG_DBG(ndpi_struct, "Unexpected ACK/CC frame\n");
}
@@ -945,8 +972,10 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_
if(counter + 2 + 8 >= clear_payload_len) /* quic_len reads 8 bytes, at most */
return NULL;
if(clear_payload[counter + 1] != 0x00) {
+#ifdef QUIC_DEBUG
NDPI_LOG_ERR(ndpi_struct, "Unexpected crypto stream offset 0x%x\n",
clear_payload[counter + 1]);
+#endif
return NULL;
}
counter += 2;
@@ -955,8 +984,10 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_
}
if(*crypto_data_len + counter > clear_payload_len) {
+#ifdef QUIC_DEBUG
NDPI_LOG_ERR(ndpi_struct, "Invalid length %lu + %d > %d version 0x%x\n",
(unsigned long)*crypto_data_len, counter, clear_payload_len, version);
+#endif
return NULL;
}
return crypto_data;
@@ -1015,7 +1046,8 @@ static uint8_t *get_clear_payload(struct ndpi_detection_module_struct *ndpi_stru
}
static void process_tls(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
- const u_int8_t *crypto_data, uint32_t crypto_data_len)
+ const u_int8_t *crypto_data, uint32_t crypto_data_len,
+ uint32_t version)
{
struct ndpi_packet_struct *packet = &flow->packet;
@@ -1027,7 +1059,7 @@ static void process_tls(struct ndpi_detection_module_struct *ndpi_struct,
packet->payload = crypto_data;
packet->payload_packet_len = crypto_data_len;
- processClientServerHello(ndpi_struct, flow, 1);
+ processClientServerHello(ndpi_struct, flow, version);
/* Restore */
packet->payload = p;
@@ -1049,11 +1081,14 @@ static void process_chlo(struct ndpi_detection_module_struct *ndpi_struct,
uint32_t prev_offset;
uint32_t tag_offset_start, offset, len, sni_len;
ndpi_protocol_match_result ret_match;
+ int sni_found = 0, ua_found = 0;
if(crypto_data_len < 6)
return;
if(memcmp(crypto_data, "CHLO", 4) != 0) {
+#ifdef QUIC_DEBUG
NDPI_LOG_ERR(ndpi_struct, "Unexpected handshake message");
+#endif
return;
}
num_tags = (*(uint16_t *)&crypto_data[4]);
@@ -1086,7 +1121,19 @@ static void process_chlo(struct ndpi_detection_module_struct *ndpi_struct,
(char *)flow->host_server_name,
strlen((const char*)flow->host_server_name),
&ret_match, NDPI_PROTOCOL_QUIC);
- return;
+ sni_found = 1;
+ if (ua_found)
+ return;
+ }
+ if((memcmp(tag, "UAID", 4) == 0) &&
+ (tag_offset_start + prev_offset + len < crypto_data_len)) {
+ NDPI_LOG_DBG2(ndpi_struct, "UA: [%.*s]\n", len, &crypto_data[tag_offset_start + prev_offset]);
+
+ http_process_user_agent(ndpi_struct, flow,
+ &crypto_data[tag_offset_start + prev_offset], len);
+ ua_found = 1;
+ if (sni_found)
+ return;
}
prev_offset = offset;
@@ -1137,13 +1184,16 @@ static int may_be_initial_pkt(struct ndpi_detection_module_struct *ndpi_struct,
if(is_gquic_ver_less_than(*version, 43) &&
(!pub_bit5 || pub_bit3 != 0 || pub_bit4 != 0)) {
- NDPI_LOG_ERR(ndpi_struct, "Version 0x%x invalid flags 0x%x\n",
- *version, first_byte);
+#ifdef QUIC_DEBUG
+ NDPI_LOG_ERR(ndpi_struct, "Version 0x%x invalid flags 0x%x\n", *version, first_byte);
+#endif
return 0;
}
if((*version == V_Q046) &&
(pub_bit7 != 1 || pub_bit8 != 1)) {
+#ifdef QUIC_DEBUG
NDPI_LOG_ERR(ndpi_struct, "Q46 invalid flag 0x%x\n", first_byte);
+#endif
return 0;
}
if((is_version_quic(*version) || (*version == V_Q046) || (*version == V_Q050)) &&
@@ -1201,8 +1251,10 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
*/
if(!is_version_supported(version)) {
- NDPI_LOG_ERR(ndpi_struct, "Unsupported version 0x%x\n", version)
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+#ifdef QUIC_DEBUG
+ NDPI_LOG_ERR(ndpi_struct, "Unsupported version 0x%x\n", version);
+#endif
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}
@@ -1235,7 +1287,7 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
if(!is_version_with_tls(version)) {
process_chlo(ndpi_struct, flow, crypto_data, crypto_data_len);
} else {
- process_tls(ndpi_struct, flow, crypto_data, crypto_data_len);
+ process_tls(ndpi_struct, flow, crypto_data, crypto_data_len, version);
}
if(is_version_with_encrypted_header(version)) {
ndpi_free(clear_payload);
diff --git a/src/lib/protocols/teamspeak.c b/src/lib/protocols/teamspeak.c
index 0fb538e36..a2a1002ff 100644
--- a/src/lib/protocols/teamspeak.c
+++ b/src/lib/protocols/teamspeak.c
@@ -24,7 +24,7 @@
#include "ndpi_api.h"
static void ndpi_int_teamspeak_add_connection(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow)
+ *ndpi_struct, struct ndpi_flow_struct *flow)
{
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TEAMSPEAK, NDPI_PROTOCOL_UNKNOWN);
}
@@ -36,56 +36,38 @@ void ndpi_search_teamspeak(struct ndpi_detection_module_struct *ndpi_struct, str
NDPI_LOG_DBG(ndpi_struct, "search teamspeak\n");
-
-#ifdef WEAK_DETECTION_CODE_DISABLED
- if(packet->udp != NULL) {
- u_int16_t udport, usport;
-
- usport = ntohs(packet->udp->source), udport = ntohs(packet->udp->dest);
-
- /* http://www.imfirewall.com/en/protocols/teamSpeak.htm */
- if(((usport == 9987 || udport == 9987) || (usport == 8767 || udport == 8767)) && packet->payload_packet_len >= 20) {
- NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK udp\n");
- ndpi_int_teamspeak_add_connection(ndpi_struct, flow);
- }
- }
- else
-#endif
-
- if(packet->tcp != NULL) {
-#if WEAK_DETECTION_CODE_DISABLED
- u_int16_t tdport, tsport;
- tsport = ntohs(packet->tcp->source), tdport = ntohs(packet->tcp->dest);
-#endif
- /* https://github.com/Youx/soliloque-server/wiki/Connection-packet */
- if(packet->payload_packet_len >= 20) {
- if(((memcmp(packet->payload, "\xf4\xbe\x03\x00", 4) == 0)) ||
- ((memcmp(packet->payload, "\xf4\xbe\x02\x00", 4) == 0)) ||
- ((memcmp(packet->payload, "\xf4\xbe\x01\x00", 4) == 0))) {
- NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK tcp\n");
- ndpi_int_teamspeak_add_connection(ndpi_struct, flow);
- } /* http://www.imfirewall.com/en/protocols/teamSpeak.htm */
+ if (packet->payload_packet_len >= 20) {
+ if (packet->udp != NULL) {
+ if (memcmp(packet->payload, "TS3INIT1", strlen("TS3INIT1")) == 0)
+ {
+ NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK udp\n");
+ ndpi_int_teamspeak_add_connection(ndpi_struct, flow);
}
-#if WEAK_DETECTION_CODE_DISABLED
- else if((tsport == 14534 || tdport == 14534) || (tsport == 51234 || tdport == 51234)) {
- NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK\n");
- ndpi_int_teamspeak_add_connection(ndpi_struct, flow);
- }
-#endif
+ } else if(packet->tcp != NULL) {
+ /* https://github.com/Youx/soliloque-server/wiki/Connection-packet */
+ if(((memcmp(packet->payload, "\xf4\xbe\x03\x00", 4) == 0)) ||
+ ((memcmp(packet->payload, "\xf4\xbe\x02\x00", 4) == 0)) ||
+ ((memcmp(packet->payload, "\xf4\xbe\x01\x00", 4) == 0)))
+ {
+ NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK tcp\n");
+ ndpi_int_teamspeak_add_connection(ndpi_struct, flow);
+ } /* http://www.imfirewall.com/en/protocols/teamSpeak.htm */
}
-
+ }
+
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}
-void init_teamspeak_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
+void init_teamspeak_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id,
+ NDPI_PROTOCOL_BITMASK *detection_bitmask)
{
ndpi_set_bitmask_protocol_detection("TeamSpeak", ndpi_struct, detection_bitmask, *id,
- NDPI_PROTOCOL_TEAMSPEAK,
- ndpi_search_teamspeak,
- NDPI_SELECTION_BITMASK_PROTOCOL_TCP_OR_UDP_WITH_PAYLOAD,
- SAVE_DETECTION_BITMASK_AS_UNKNOWN,
- ADD_TO_DETECTION_BITMASK);
+ NDPI_PROTOCOL_TEAMSPEAK,
+ ndpi_search_teamspeak,
+ NDPI_SELECTION_BITMASK_PROTOCOL_TCP_OR_UDP_WITH_PAYLOAD,
+ SAVE_DETECTION_BITMASK_AS_UNKNOWN,
+ ADD_TO_DETECTION_BITMASK);
*id += 1;
}
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index aa3836442..134dfe614 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -31,7 +31,14 @@
extern char *strptime(const char *s, const char *format, struct tm *tm);
extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow, int is_quic);
+ struct ndpi_flow_struct *flow, uint32_t quic_version);
+extern int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ const u_int8_t *ua_ptr, u_int16_t ua_ptr_len);
+/* QUIC/GQUIC stuff */
+extern int quic_len(const uint8_t *buf, uint64_t *value);
+extern int quic_len_buffer_still_required(uint8_t value);
+extern int is_version_with_var_int_transport_params(uint32_t version);
// #define DEBUG_TLS_MEMORY 1
// #define DEBUG_TLS 1
@@ -864,7 +871,7 @@ struct ja3_info {
/* **************************************** */
int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow, int is_quic) {
+ struct ndpi_flow_struct *flow, uint32_t quic_version) {
struct ndpi_packet_struct *packet = &flow->packet;
struct ja3_info ja3;
u_int8_t invalid_ja3 = 0;
@@ -876,6 +883,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t total_len;
u_int8_t handshake_type;
char buffer[64] = { '\0' };
+ int is_quic = (quic_version != 0);
int is_dtls = packet->udp && (!is_quic);
#ifdef DEBUG_TLS
@@ -1161,7 +1169,8 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
flow->l4.tcp.tls.subprotocol_detected = 1;
}
- ndpi_check_dga_name(ndpi_struct, flow, flow->protos.stun_ssl.ssl.client_requested_server_name);
+ ndpi_check_dga_name(ndpi_struct, flow,
+ flow->protos.stun_ssl.ssl.client_requested_server_name, 1);
} else {
#ifdef DEBUG_TLS
printf("[TLS] Extensions server len too short: %u vs %u\n",
@@ -1365,6 +1374,60 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
}
}
}
+ } else if(extension_id == 65445 /* QUIC transport parameters */) {
+ u_int16_t s_offset = offset+extension_offset;
+ uint16_t final_offset;
+ int using_var_int = is_version_with_var_int_transport_params(quic_version);
+
+ if(!using_var_int) {
+ if(s_offset+1 >= total_len) {
+ final_offset = 0; /* Force skipping extension */
+ } else {
+ u_int16_t seq_len = ntohs(*((u_int16_t*)&packet->payload[s_offset]));
+ s_offset += 2;
+ final_offset = MIN(total_len, s_offset + seq_len);
+ }
+ } else {
+ final_offset = MIN(total_len, s_offset + extension_len);
+ }
+
+ while(s_offset < final_offset) {
+ u_int64_t param_type, param_len;
+
+ if(!using_var_int) {
+ if(s_offset+3 >= final_offset)
+ break;
+ param_type = ntohs(*((u_int16_t*)&packet->payload[s_offset]));
+ param_len = ntohs(*((u_int16_t*)&packet->payload[s_offset + 2]));
+ s_offset += 4;
+ } else {
+ if(s_offset >= final_offset ||
+ (s_offset + quic_len_buffer_still_required(packet->payload[s_offset])) >= final_offset)
+ break;
+ s_offset += quic_len(&packet->payload[s_offset], &param_type);
+
+ if(s_offset >= final_offset ||
+ (s_offset + quic_len_buffer_still_required(packet->payload[s_offset])) >= final_offset)
+ break;
+ s_offset += quic_len(&packet->payload[s_offset], &param_len);
+ }
+
+#ifdef DEBUG_TLS
+ printf("Client SSL [QUIC TP: Param 0x%x Len %d]\n", (int)param_type, (int)param_len);
+#endif
+ if(s_offset+param_len >= final_offset)
+ break;
+
+ if(param_type==0x3129) {
+#ifdef DEBUG_TLS
+ printf("UA [%.*s]\n", (int)param_len, &packet->payload[s_offset]);
+#endif
+ http_process_user_agent(ndpi_struct, flow,
+ &packet->payload[s_offset], param_len);
+ break;
+ }
+ s_offset += param_len;
+ }
}
extension_offset += extension_len; /* Move to the next extension */
diff --git a/src/lib/protocols/tor.c b/src/lib/protocols/tor.c
index 7318685e7..71172e211 100644
--- a/src/lib/protocols/tor.c
+++ b/src/lib/protocols/tor.c
@@ -48,7 +48,7 @@ int ndpi_is_tls_tor(struct ndpi_detection_module_struct *ndpi_struct,
if((dot = strrchr(dummy, '.')) == NULL) return(0);
name = &dot[1];
- if(ndpi_check_dga_name(ndpi_struct, flow, name)) {
+ if(ndpi_check_dga_name(ndpi_struct, flow, name, 1)) {
ndpi_int_tor_add_connection(ndpi_struct, flow);
return(1);
} else {