aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/directconnect.c141
-rw-r--r--src/lib/protocols/dns.c32
-rw-r--r--src/lib/protocols/hangout.c28
-rw-r--r--src/lib/protocols/http.c22
-rw-r--r--src/lib/protocols/mail_imap.c2
-rw-r--r--src/lib/protocols/msn.c6
-rw-r--r--src/lib/protocols/ookla.c4
-rw-r--r--src/lib/protocols/quic.c16
-rw-r--r--src/lib/protocols/rtp.c107
-rw-r--r--src/lib/protocols/ssh.c240
-rw-r--r--src/lib/protocols/stun.c201
-rw-r--r--src/lib/protocols/teamspeak.c45
-rw-r--r--src/lib/protocols/tls.c (renamed from src/lib/protocols/ssl.c)632
-rw-r--r--src/lib/protocols/tor.c12
-rw-r--r--src/lib/protocols/yahoo.c2
15 files changed, 901 insertions, 589 deletions
diff --git a/src/lib/protocols/directconnect.c b/src/lib/protocols/directconnect.c
index 19582724d..563540fba 100644
--- a/src/lib/protocols/directconnect.c
+++ b/src/lib/protocols/directconnect.c
@@ -58,9 +58,9 @@ static u_int16_t parse_binf_message(struct ndpi_detection_module_struct
u_int16_t ssl_port = 0;
while (i < payload_len) {
i = skip_unknown_headers(payload, payload_len, i);
- if ((i + 30) < payload_len) {
- if (memcmp(&payload[i], "DCTM", 4) == 0) {
- if (memcmp(&payload[i + 15], "ADCS", 4) == 0) {
+ if((i + 30) < payload_len) {
+ if(memcmp(&payload[i], "DCTM", 4) == 0) {
+ if(memcmp(&payload[i + 15], "ADCS", 4) == 0) {
ssl_port = ntohs_ndpi_bytestream_to_number(&payload[i + 25], 5, &bytes_read);
NDPI_LOG_DBG2(ndpi_struct, "DC ssl port parsed %d\n", ssl_port);
}
@@ -84,15 +84,15 @@ static void ndpi_int_directconnect_add_connection(struct ndpi_detection_module_s
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_DIRECTCONNECT, NDPI_PROTOCOL_UNKNOWN);
- if (src != NULL) {
+ if(src != NULL) {
src->directconnect_last_safe_access_time = packet->tick_timestamp;
- if (connection_type == DIRECT_CONNECT_TYPE_PEER) {
- if (packet->tcp != NULL
+ if(connection_type == DIRECT_CONNECT_TYPE_PEER) {
+ if(packet->tcp != NULL
&& flow->setup_packet_direction != packet->packet_direction && src->detected_directconnect_port == 0) {
src->detected_directconnect_port = packet->tcp->source;
NDPI_LOG_DBG2(ndpi_struct, "DC tcp PORT %u for src\n", ntohs(src->detected_directconnect_port));
}
- if (packet->udp != NULL && src->detected_directconnect_udp_port == 0) {
+ if(packet->udp != NULL && src->detected_directconnect_udp_port == 0) {
src->detected_directconnect_udp_port = packet->udp->source;
NDPI_LOG_DBG2(ndpi_struct, "DC udp PORT %u for src\n", ntohs(src->detected_directconnect_port));
@@ -100,10 +100,10 @@ static void ndpi_int_directconnect_add_connection(struct ndpi_detection_module_s
}
}
- if (dst != NULL) {
+ if(dst != NULL) {
dst->directconnect_last_safe_access_time = packet->tick_timestamp;
- if (connection_type == DIRECT_CONNECT_TYPE_PEER) {
- if (packet->tcp != NULL
+ if(connection_type == DIRECT_CONNECT_TYPE_PEER) {
+ if(packet->tcp != NULL
&& flow->setup_packet_direction == packet->packet_direction && dst->detected_directconnect_port == 0) {
/* DST PORT MARKING CAN LEAD TO PORT MISSDETECTIONS
* seen at large customer http servers, where someone has send faked DC tcp packets
@@ -121,35 +121,34 @@ static void ndpi_int_directconnect_add_connection(struct ndpi_detection_module_s
}
}
-static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
-{
+static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
struct ndpi_id_struct *src = flow->src;
struct ndpi_id_struct *dst = flow->dst;
- if (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) {
- if (packet->payload_packet_len >= 40 && memcmp(&packet->payload[0], "BINF", 4) == 0) {
- u_int16_t ssl_port = 0;
- ssl_port = parse_binf_message(ndpi_struct, &packet->payload[4], packet->payload_packet_len - 4);
- if (dst != NULL && ssl_port) {
+ if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) {
+ if(packet->payload_packet_len >= 40 && memcmp(&packet->payload[0], "BINF", 4) == 0) {
+ u_int16_t ssl_port = parse_binf_message(ndpi_struct,
+ &packet->payload[4],
+ packet->payload_packet_len - 4);
+ if(dst != NULL && ssl_port)
dst->detected_directconnect_ssl_port = ssl_port;
- }
- if (src != NULL && ssl_port) {
+
+ if(src != NULL && ssl_port)
src->detected_directconnect_ssl_port = ssl_port;
- }
-
-
}
- if ((packet->payload_packet_len >= 38 && packet->payload_packet_len <= 42)
+
+ if((packet->payload_packet_len >= 38 && packet->payload_packet_len <= 42)
&& memcmp(&packet->payload[0], "DCTM", 4) == 0 && memcmp(&packet->payload[15], "ADCS", 4) == 0) {
u_int16_t bytes_read = 0;
- if (dst != NULL) {
+ if(dst != NULL) {
dst->detected_directconnect_ssl_port =
ntohs_ndpi_bytestream_to_number(&packet->payload[25], 5, &bytes_read);
NDPI_LOG_DBG2(ndpi_struct, "DC ssl port parsed %d\n", ntohs(dst->detected_directconnect_ssl_port));
}
- if (src != NULL) {
+ if(src != NULL) {
src->detected_directconnect_ssl_port =
ntohs_ndpi_bytestream_to_number(&packet->payload[25], 5, &bytes_read);
NDPI_LOG_DBG2(ndpi_struct, "DC ssl port parsed %d\n", ntohs(src->detected_directconnect_ssl_port));
@@ -160,9 +159,9 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
return;
}
- if (src != NULL) {
- if (src->detected_directconnect_port == packet->tcp->source) {
- if ((u_int32_t)
+ if(src != NULL) {
+ if(src->detected_directconnect_port == packet->tcp->source) {
+ if((u_int32_t)
(packet->tick_timestamp -
src->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) {
src->directconnect_last_safe_access_time = packet->tick_timestamp;
@@ -175,8 +174,8 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
return;
}
}
- if (src->detected_directconnect_ssl_port == packet->tcp->dest) {
- if ((u_int32_t)
+ if(src->detected_directconnect_ssl_port == packet->tcp->dest) {
+ if((u_int32_t)
(packet->tick_timestamp -
src->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) {
src->directconnect_last_safe_access_time = packet->tick_timestamp;
@@ -192,9 +191,9 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
}
- if (dst != NULL) {
- if (dst->detected_directconnect_port == packet->tcp->dest) {
- if ((u_int32_t)
+ if(dst != NULL) {
+ if(dst->detected_directconnect_port == packet->tcp->dest) {
+ if((u_int32_t)
(packet->tick_timestamp -
dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) {
dst->directconnect_last_safe_access_time = packet->tick_timestamp;
@@ -207,8 +206,8 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
return;
}
}
- if (dst->detected_directconnect_ssl_port == packet->tcp->dest) {
- if ((u_int32_t)
+ if(dst->detected_directconnect_ssl_port == packet->tcp->dest) {
+ if((u_int32_t)
(packet->tick_timestamp -
dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) {
dst->directconnect_last_safe_access_time = packet->tick_timestamp;
@@ -224,17 +223,17 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
}
- if (flow->directconnect_stage == 0) {
+ if(flow->directconnect_stage == 0) {
- if (packet->payload_packet_len > 6) {
- if (packet->payload[0] == '$'
+ if(packet->payload_packet_len > 6) {
+ if(packet->payload[0] == '$'
&& packet->payload[packet->payload_packet_len - 1] == '|'
&& (memcmp(&packet->payload[1], "Lock ", 5) == 0)) {
NDPI_LOG_DBG2(ndpi_struct, "maybe first dc connect to hub detected\n");
flow->directconnect_stage = 1;
return;
}
- if (packet->payload_packet_len > 7
+ if(packet->payload_packet_len > 7
&& packet->payload[0] == '$'
&& packet->payload[packet->payload_packet_len - 1] == '|'
&& (memcmp(&packet->payload[1], "MyNick ", 7) == 0)) {
@@ -244,15 +243,15 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
}
}
- if (packet->payload_packet_len >= 11) {
+ if(packet->payload_packet_len >= 11) {
/* did not see this pattern in any trace */
- if (memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0
+ if(memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0
|| memcmp(&packet->payload[0], "HSUP ADBASE", 11) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found DC HSUP ADBAS0 E\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_HUB);
return;
/* did not see this pattern in any trace */
- } else if (memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 ||
+ } else if(memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 ||
memcmp(&packet->payload[0], "CSUP ADBASE", 11) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found DC CSUP ADBAS0 E\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_ADC_PEER);
@@ -262,16 +261,16 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
}
- } else if (flow->directconnect_stage == 1) {
- if (packet->payload_packet_len >= 11) {
+ } else if(flow->directconnect_stage == 1) {
+ if(packet->payload_packet_len >= 11) {
/* did not see this pattern in any trace */
- if (memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0
+ if(memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0
|| memcmp(&packet->payload[0], "HSUP ADBASE", 11) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found DC HSUP ADBAS E in second packet\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_HUB);
return;
/* did not see this pattern in any trace */
- } else if (memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 ||
+ } else if(memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 ||
memcmp(&packet->payload[0], "CSUP ADBASE", 11) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found DC HSUP ADBAS0 E in second packet\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_ADC_PEER);
@@ -280,8 +279,8 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
}
}
/* get client hello answer or server message */
- if (packet->payload_packet_len > 6) {
- if ((packet->payload[0] == '$' || packet->payload[0] == '<')
+ if(packet->payload_packet_len > 6) {
+ if((packet->payload[0] == '$' || packet->payload[0] == '<')
&& packet->payload[packet->payload_packet_len - 1] == '|') {
NDPI_LOG_INFO(ndpi_struct, "found DC second\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_HUB);
@@ -291,10 +290,10 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n
}
}
- } else if (flow->directconnect_stage == 2) {
+ } else if(flow->directconnect_stage == 2) {
/* get client hello answer or server message */
- if (packet->payload_packet_len > 6) {
- if (packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|') {
+ if(packet->payload_packet_len > 6) {
+ if(packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|') {
NDPI_LOG_INFO(ndpi_struct, "found DC between peers\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_PEER);
return;
@@ -318,8 +317,8 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct
struct ndpi_id_struct *dst = flow->dst;
int pos, count = 0;
- if (dst != NULL && dst->detected_directconnect_udp_port == packet->udp->dest) {
- if ((u_int32_t)
+ if(dst != NULL && dst->detected_directconnect_udp_port == packet->udp->dest) {
+ if((u_int32_t)
(packet->tick_timestamp -
dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) {
@@ -334,21 +333,21 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct
}
}
- if (packet->payload_packet_len > 58) {
- if (src != NULL
+ if(packet->payload_packet_len > 58) {
+ if(src != NULL
&& NDPI_COMPARE_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, NDPI_PROTOCOL_DIRECTCONNECT)) {
- if (packet->payload[0] == '$'
+ if(packet->payload[0] == '$'
&& packet->payload[packet->payload_packet_len - 1] == '|'
&& memcmp(&packet->payload[1], "SR ", 3) == 0) {
pos = packet->payload_packet_len - 2;
- if (packet->payload[pos] == ')') {
+ if(packet->payload[pos] == ')') {
while (pos > 0 && packet->payload[pos] != '(' && count < 21) {
pos--;
count++;
}
- if (packet->payload[pos] == '(') {
+ if(packet->payload[pos] == '(') {
pos = pos - 44;
- if (pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) {
+ if(pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found DC udp\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_PEER);
return;
@@ -356,25 +355,25 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct
}
}
flow->directconnect_stage++;
- if (flow->directconnect_stage < 3)
+ if(flow->directconnect_stage < 3)
return;
}
}
- if (dst != NULL
+ if(dst != NULL
&& NDPI_COMPARE_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, NDPI_PROTOCOL_DIRECTCONNECT)) {
- if (packet->payload[0] == '$'
+ if(packet->payload[0] == '$'
&& packet->payload[packet->payload_packet_len - 1] == '|'
&& memcmp(&packet->payload[1], "SR ", 3) == 0) {
pos = packet->payload_packet_len - 2;
- if (packet->payload[pos] == ')') {
+ if(packet->payload[pos] == ')') {
while (pos > 0 && packet->payload[pos] != '(' && count < 21) {
pos--;
count++;
}
- if (packet->payload[pos] == '(') {
+ if(packet->payload[pos] == '(') {
pos = pos - 44;
- if (pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) {
+ if(pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) {
NDPI_LOG_INFO(ndpi_struct, "found DC udp\n");
ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_PEER);
return;
@@ -382,7 +381,7 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct
}
}
flow->directconnect_stage++;
- if (flow->directconnect_stage < 3)
+ if(flow->directconnect_stage < 3)
return;
}
}
@@ -404,14 +403,14 @@ void ndpi_search_directconnect(struct ndpi_detection_module_struct
NDPI_LOG_DBG(ndpi_struct, "search DC\n");
- if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) {
- if (src != NULL && ((u_int32_t)
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) {
+ if(src != NULL && ((u_int32_t)
(packet->tick_timestamp -
src->directconnect_last_safe_access_time) <
ndpi_struct->directconnect_connection_ip_tick_timeout)) {
src->directconnect_last_safe_access_time = packet->tick_timestamp;
- } else if (dst != NULL && ((u_int32_t)
+ } else if(dst != NULL && ((u_int32_t)
(packet->tick_timestamp -
dst->directconnect_last_safe_access_time) <
ndpi_struct->directconnect_connection_ip_tick_timeout)) {
@@ -423,9 +422,9 @@ void ndpi_search_directconnect(struct ndpi_detection_module_struct
return;
}
- if (packet->tcp != NULL) {
+ if(packet->tcp != NULL) {
ndpi_search_directconnect_tcp(ndpi_struct, flow);
- } else if (packet->udp != NULL) {
+ } else if(packet->udp != NULL) {
ndpi_search_directconnect_udp(ndpi_struct, flow);
}
}
diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c
index dc97f3fe7..6a4a02f60 100644
--- a/src/lib/protocols/dns.c
+++ b/src/lib/protocols/dns.c
@@ -128,19 +128,17 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd
|| ((dns_header.num_answers == 0) && (dns_header.authority_rrs == 0)))) {
/* This is a good query */
- if(dns_header.num_queries > 0) {
- while(x < flow->packet.payload_packet_len) {
- if(flow->packet.payload[x] == '\0') {
- x++;
- flow->protos.dns.query_type = get16(&x, flow->packet.payload);
+ 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);
+ NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type);
#endif
- break;
- } else
- x++;
- }
- }
+ break;
+ } else
+ x++;
+ }
} else
invalid = 1;
} else {
@@ -222,15 +220,19 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd
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++];
+ 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;
+ 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:'_';
+ flow->host_server_name[j++] = (dns_validchar[c >> 5] & (1 << (c & 0x1f))) ? c : '_';
cl--;
}
}
diff --git a/src/lib/protocols/hangout.c b/src/lib/protocols/hangout.c
index 99bf879cb..c96b36018 100644
--- a/src/lib/protocols/hangout.c
+++ b/src/lib/protocols/hangout.c
@@ -22,8 +22,12 @@
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_HANGOUT_DUO
+/* #define DEBUG_LRU 1 */
+
#include "ndpi_api.h"
+/* stun.c */
+extern u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow);
/* https://support.google.com/a/answer/1279090?hl=en */
#define HANGOUT_UDP_LOW_PORT 19302
@@ -85,11 +89,29 @@ void ndpi_search_hangout(struct ndpi_detection_module_struct *ndpi_struct,
if((packet->payload_packet_len > 24) && is_google_flow(ndpi_struct, flow)) {
if(
- ((packet->udp != NULL) && (isHangoutUDPPort(ntohs(packet->udp->source)) || isHangoutUDPPort(ntohs(packet->udp->dest))))
+ ((packet->udp != NULL) && (isHangoutUDPPort(ntohs(packet->udp->source))
+ || isHangoutUDPPort(ntohs(packet->udp->dest))))
||
- ((packet->tcp != NULL) && (isHangoutTCPPort(ntohs(packet->tcp->source)) || isHangoutTCPPort(ntohs(packet->tcp->dest))))) {
+ ((packet->tcp != NULL) && (isHangoutTCPPort(ntohs(packet->tcp->source))
+ || isHangoutTCPPort(ntohs(packet->tcp->dest))))) {
NDPI_LOG_INFO(ndpi_struct, "found Hangout\n");
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_UNKNOWN);
+
+ /* Hangout is over STUN hence the LRU cache is shared */
+ if(ndpi_struct->stun_cache == NULL)
+ ndpi_struct->stun_cache = ndpi_lru_cache_init(1024);
+
+ if(ndpi_struct->stun_cache && flow->packet.iph && flow->packet.udp) {
+ u_int32_t key = get_stun_lru_key(flow);
+
+#ifdef DEBUG_LRU
+ printf("[LRU] ADDING %u / %u.%u\n", key, NDPI_PROTOCOL_STUN, NDPI_PROTOCOL_HANGOUT_DUO);
+#endif
+
+ ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, NDPI_PROTOCOL_HANGOUT_DUO);
+ }
+
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO,
+ NDPI_PROTOCOL_STUN);
return;
}
}
diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c
index 1e066c3ac..cd5f193db 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -35,7 +35,7 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd
printf("[%s] [http_dont_dissect_response: %u]->> %s\n", __FUNCTION__,
ndpi_struct->http_dont_dissect_response, flow->http.response_status_code);
#endif
-
+
if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) {
/* This is HTTP and it is not a sub protocol (e.g. skype or dropbox) */
@@ -157,7 +157,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
#endif
/* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */
-
+
/* if(!ndpi_struct->http_dont_dissect_response) */ {
if((flow->http.url == NULL)
&& (packet->http_url_name.len > 0)
@@ -320,7 +320,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
/**
check result of host subprotocol detection
-
+
if "detected" in flow == 0 then "detected" = "guess"
else "guess" = "detected"
**/
@@ -338,7 +338,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
if(flow->detected_protocol_stack[0] != flow->guessed_host_protocol_id)
flow->guessed_host_protocol_id = flow->detected_protocol_stack[0];
}
-
+
if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN)
&& ((ndpi_struct->http_dont_dissect_response) || flow->http_detected)
&& (packet->http_origin.len > 0)) {
@@ -480,17 +480,17 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
if(packet->payload_packet_len >= 12) {
char buf[4];
-
+
/* Set server HTTP response code */
strncpy(buf, (char*)&packet->payload[9], 3);
buf[3] = '\0';
-
+
flow->http.response_status_code = atoi(buf);
/* https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */
if((flow->http.response_status_code < 100) || (flow->http.response_status_code > 509))
flow->http.response_status_code = 0; /* Out of range */
}
-
+
ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HTTP);
check_content_type_and_change_protocol(ndpi_struct, flow);
return;
@@ -533,14 +533,14 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
if(ndpi_struct->ookla_cache == NULL)
ndpi_struct->ookla_cache = ndpi_lru_cache_init(1024);
-
+
if(packet->iph != NULL && ndpi_struct->ookla_cache != NULL) {
if(packet->tcp->source == htons(8080))
- ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->saddr);
+ ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->saddr, 1 /* dummy */);
else
- ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->daddr);
+ ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->daddr, 1 /* dummy */);
}
-
+
return;
}
diff --git a/src/lib/protocols/mail_imap.c b/src/lib/protocols/mail_imap.c
index 65341cdc8..69d135943 100644
--- a/src/lib/protocols/mail_imap.c
+++ b/src/lib/protocols/mail_imap.c
@@ -48,7 +48,7 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct,
if (flow->l4.tcp.mail_imap_starttls == 2) {
NDPI_LOG_DBG2(ndpi_struct, "starttls detected\n");
NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_MAIL_IMAP);
- NDPI_DEL_PROTOCOL_FROM_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SSL);
+ NDPI_DEL_PROTOCOL_FROM_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_TLS);
return;
}
diff --git a/src/lib/protocols/msn.c b/src/lib/protocols/msn.c
index 8ab45ad32..8d52d690b 100644
--- a/src/lib/protocols/msn.c
+++ b/src/lib/protocols/msn.c
@@ -62,7 +62,7 @@ static void ndpi_search_msn_tcp(struct ndpi_detection_module_struct *ndpi_struct
u_int16_t plen;
u_int16_t status = 0;
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) {
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
NDPI_LOG_DBG2(ndpi_struct, "msn ssl ft test\n");
@@ -103,7 +103,7 @@ static void ndpi_search_msn_tcp(struct ndpi_detection_module_struct *ndpi_struct
*/
/* now we have a look at the first packet only. */
if(flow->packet_counter == 1
- || ((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL)
+ || ((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS)
&& flow->packet_counter <= 3)
) {
@@ -497,7 +497,7 @@ void ndpi_search_msn(struct ndpi_detection_module_struct *ndpi_struct, struct nd
// need to do the ceck when protocol == http too (POST /gateway ...)
if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN
|| packet->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP
- || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL
+ || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS
|| packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN
)
ndpi_search_msn_tcp(ndpi_struct, flow);
diff --git a/src/lib/protocols/ookla.c b/src/lib/protocols/ookla.c
index 44746fbd3..f3c2108bc 100644
--- a/src/lib/protocols/ookla.c
+++ b/src/lib/protocols/ookla.c
@@ -38,7 +38,9 @@ void ndpi_search_ookla(struct ndpi_detection_module_struct* ndpi_struct, struct
goto ookla_exclude;
if(ndpi_struct->ookla_cache != NULL) {
- if(ndpi_lru_find_cache(ndpi_struct->ookla_cache, addr, 0 /* Don't remove it as it can be used for other connections */)) {
+ u_int16_t dummy;
+
+ if(ndpi_lru_find_cache(ndpi_struct->ookla_cache, addr, &dummy, 0 /* Don't remove it as it can be used for other connections */)) {
NDPI_LOG_INFO(ndpi_struct, "found ookla tcp connection\n");
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN);
return;
diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c
index 6d4d45044..87378ea61 100644
--- a/src/lib/protocols/quic.c
+++ b/src/lib/protocols/quic.c
@@ -83,15 +83,27 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
) {
int i;
-
if((packet->payload[1] == 'Q')
&& (packet->payload[2] == '0')
&& (packet->payload[3] == '4')
- && (packet->payload[4] == '6'))
+ && (packet->payload[4] == '6')
+ && (version_len == 1)
+ )
quic_hlen = 18; /* TODO: Better handle Q046 */
else {
+ u_int16_t potential_stun_len = ntohs((*((u_int16_t*)&packet->payload[2])));
+
if((version_len > 0) && (packet->payload[1+cid_len] != 'Q'))
goto no_quic;
+
+ if((version_len == 0) && ((packet->payload[0] & 0xC3 /* ignore CID len/packet number */) != 0))
+ goto no_quic;
+
+
+ /* Heuristic to see if this packet could be a STUN packet */
+ if((potential_stun_len /* STUN message len */ < udp_len)
+ && ((potential_stun_len+25 /* Attribute header overhead we assume is max */) /* STUN message len */ > udp_len))
+ return; /* This could be STUN, let's skip this packet */
NDPI_LOG_INFO(ndpi_struct, "found QUIC\n");
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_QUIC, NDPI_PROTOCOL_UNKNOWN);
diff --git a/src/lib/protocols/rtp.c b/src/lib/protocols/rtp.c
index bd0179287..90b73ab1e 100644
--- a/src/lib/protocols/rtp.c
+++ b/src/lib/protocols/rtp.c
@@ -58,14 +58,14 @@ static u_int8_t isValidMSRTPType(u_int8_t payloadType) {
case 127: /* x-data */
return(1 /* RTP */);
break;
-
+
case 200: /* RTCP PACKET SENDER */
case 201: /* RTCP PACKET RECEIVER */
case 202: /* RTCP Source Description */
case 203: /* RTCP Bye */
return(2 /* RTCP */);
break;
-
+
default:
return(0);
}
@@ -78,8 +78,10 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
const u_int8_t * payload, const u_int16_t payload_len) {
NDPI_LOG_DBG(ndpi_struct, "search RTP\n");
- if (payload_len < 2)
+ if((payload_len < 2) || flow->protos.stun_ssl.stun.num_binding_requests) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
+ }
//struct ndpi_packet_struct *packet = &flow->packet;
u_int8_t payloadType, payload_type = payload[1] & 0x7F;
@@ -91,17 +93,17 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
&& ((payload_type <= 34)
|| ((payload_type >= 96) && (payload_type <= 127))
/* http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
- )
- ) {
+ )
+ ) {
struct ndpi_packet_struct *packet = &flow->packet;
-
+
if(packet->iph) {
/* 125.209.252.xxx */
if(((ntohl(packet->iph->saddr) & 0xFFFFFF00 /* 255.255.255.0 */) == 0x7DD1FC00)
|| ((ntohl(packet->iph->daddr) & 0xFFFFFF00 /* 255.255.255.0 */) == 0x7DD1FC00)) {
if((flow->packet.payload[0] == 0x80)
&& ((flow->packet.payload[1] == 0x78) || (flow->packet.payload[1] == 0xE8))
- ) {
+ ) {
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_LINE, NDPI_PROTOCOL_LINE);
return;
}
@@ -112,7 +114,7 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_RTP, NDPI_PROTOCOL_UNKNOWN);
return;
} else if((payload_len >= 12)
- && (((payload[0] & 0xFF) == 0x80) || ((payload[0] & 0xFF) == 0xA0)) /* RTP magic byte[1] */
+ && (((payload[0] & 0xFF) == 0x80) || ((payload[0] & 0xFF) == 0xA0)) /* RTP magic byte[1] */
&& (payloadType = isValidMSRTPType(payload[1] & 0xFF))) {
if(payloadType == 1 /* RTP */) {
NDPI_LOG_INFO(ndpi_struct, "Found Skype for Business (former MS Lync)\n");
@@ -126,7 +128,7 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
return;
#endif
}
- }
+ }
/* No luck this time */
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
@@ -139,7 +141,7 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd
struct ndpi_packet_struct *packet = &flow->packet;
/* printf("*** %s(pkt=%d)\n", __FUNCTION__, flow->packet_counter); */
-
+
if((packet->udp != NULL)
/* && (ntohs(packet->udp->source) > 1023) */
&& (ntohs(packet->udp->dest) > 1023))
@@ -204,14 +206,14 @@ u_int16_t update_seq(struct ndpi_detection_module_struct *ndpi_struct, struct nd
u_int16_t delta = seq - flow->rtp_seqnum[direction];
- if (delta < RTP_MAX_OUT_OF_ORDER) { /* in order, with permissible gap */
+ if(delta < RTP_MAX_OUT_OF_ORDER) { /* in order, with permissible gap */
flow->rtp_seqnum[direction] = seq;
NDPI_LOG_DBG(ndpi_struct, "rtp_seqnum[%u] = %u (increased by %u)\n",
- direction, seq, delta);
+ direction, seq, delta);
return delta;
} else {
NDPI_LOG_DBG(ndpi_struct, "retransmission (dir %u, seqnum %u)\n",
- direction, seq);
+ direction, seq);
return 0;
}
}
@@ -227,51 +229,51 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
NDPI_LOG_DBG(ndpi_struct, "search rtp\n");
- if (payload_len == 4 && get_u_int32_t(packet->payload, 0) == 0 && flow->packet_counter < 8) {
+ if(payload_len == 4 && get_u_int32_t(packet->payload, 0) == 0 && flow->packet_counter < 8) {
NDPI_LOG_DBG(ndpi_struct, "need next packet, maybe ClearSea out calls\n");
return;
}
- if (payload_len == 5 && memcmp(payload, "hello", 5) == 0) {
+ if(payload_len == 5 && memcmp(payload, "hello", 5) == 0) {
NDPI_LOG_DBG(ndpi_struct,
- "need next packet, initial hello packet of SIP out calls.\n");
+ "need next packet, initial hello packet of SIP out calls.\n");
return;
}
- if (payload_len == 1 && payload[0] == 0) {
+ if(payload_len == 1 && payload[0] == 0) {
NDPI_LOG_DBG(ndpi_struct,
- "need next packet, payload_packet_len == 1 && payload[0] == 0.\n");
+ "need next packet, payload_packet_len == 1 && payload[0] == 0.\n");
return;
}
- if (payload_len == 3 && memcmp(payload, "png", 3) == 0) {
+ if(payload_len == 3 && memcmp(payload, "png", 3) == 0) {
/* weird packet found in Ninja GlobalIP trace */
NDPI_LOG_DBG(ndpi_struct, "skipping packet with len = 3 and png payload\n");
return;
}
- if (payload_len < 12) {
+ if(payload_len < 12) {
NDPI_LOG_DBG(ndpi_struct, "minimal packet size for rtp packets: 12\n");
goto exclude_rtp;
}
- if (payload_len == 12 && get_u_int32_t(payload, 0) == 0 && get_u_int32_t(payload, 4) == 0 && get_u_int32_t(payload, 8) == 0) {
+ if(payload_len == 12 && get_u_int32_t(payload, 0) == 0 && get_u_int32_t(payload, 4) == 0 && get_u_int32_t(payload, 8) == 0) {
NDPI_LOG_DBG(ndpi_struct, "skipping packet with len = 12 and only 0-bytes\n");
return;
}
- if ((payload[0] & 0xc0) == 0xc0 || (payload[0] & 0xc0) == 0x40 || (payload[0] & 0xc0) == 0x00) {
+ if((payload[0] & 0xc0) == 0xc0 || (payload[0] & 0xc0) == 0x40 || (payload[0] & 0xc0) == 0x00) {
NDPI_LOG_DBG(ndpi_struct, "version = 3 || 1 || 0, maybe first rtp packet\n");
return;
}
- if ((payload[0] & 0xc0) != 0x80) {
+ if((payload[0] & 0xc0) != 0x80) {
NDPI_LOG_DBG(ndpi_struct, "rtp version must be 2, first two bits of a packets must be 10\n");
goto exclude_rtp;
}
/* rtp_payload_type are the last seven bits of the second byte */
- if (flow->rtp_payload_type[packet->packet_direction] != (payload[1] & 0x7F)) {
+ if(flow->rtp_payload_type[packet->packet_direction] != (payload[1] & 0x7F)) {
NDPI_LOG_DBG(ndpi_struct, "payload_type has changed, reset stages\n");
packet->packet_direction == 0 ? (flow->rtp_stage1 = 0) : (flow->rtp_stage2 = 0);
}
@@ -280,56 +282,56 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
stage = (packet->packet_direction == 0 ? flow->rtp_stage1 : flow->rtp_stage2);
- if (stage > 0) {
+ if(stage > 0) {
NDPI_LOG_DBG(ndpi_struct, "stage = %u\n", packet->packet_direction == 0 ? flow->rtp_stage1 : flow->rtp_stage2);
- if (flow->rtp_ssid[packet->packet_direction] != get_u_int32_t(payload, 8)) {
+ if(flow->rtp_ssid[packet->packet_direction] != get_u_int32_t(payload, 8)) {
NDPI_LOG_DBG(ndpi_struct, "ssid has changed, goto exclude rtp\n");
goto exclude_rtp;
}
- if (seqnum == flow->rtp_seqnum[packet->packet_direction]) {
+ if(seqnum == flow->rtp_seqnum[packet->packet_direction]) {
NDPI_LOG_DBG(ndpi_struct, "maybe \"retransmission\", need next packet\n");
return;
- } else if ((u_int16_t) (seqnum - flow->rtp_seqnum[packet->packet_direction]) < RTP_MAX_OUT_OF_ORDER) {
+ } else if((u_int16_t) (seqnum - flow->rtp_seqnum[packet->packet_direction]) < RTP_MAX_OUT_OF_ORDER) {
NDPI_LOG_DBG(ndpi_struct,
- "new packet has larger sequence number (within valid range)\n");
+ "new packet has larger sequence number (within valid range)\n");
update_seq(ndpi_struct, flow, packet->packet_direction, seqnum);
- } else if ((u_int16_t) (flow->rtp_seqnum[packet->packet_direction] - seqnum) < RTP_MAX_OUT_OF_ORDER) {
+ } else if((u_int16_t) (flow->rtp_seqnum[packet->packet_direction] - seqnum) < RTP_MAX_OUT_OF_ORDER) {
NDPI_LOG_DBG(ndpi_struct,
- "new packet has smaller sequence number (within valid range)\n");
+ "new packet has smaller sequence number (within valid range)\n");
init_seq(ndpi_struct, flow, packet->packet_direction, seqnum, 1);
} else {
NDPI_LOG_DBG(ndpi_struct,
- "sequence number diff is too big, goto exclude rtp.\n");
+ "sequence number diff is too big, goto exclude rtp.\n");
goto exclude_rtp;
}
} else {
NDPI_LOG_DBG(ndpi_struct, "rtp_ssid[%u] = %u\n", packet->packet_direction,
- flow->rtp_ssid[packet->packet_direction]);
+ flow->rtp_ssid[packet->packet_direction]);
flow->rtp_ssid[packet->packet_direction] = get_u_int32_t(payload, 8);
- if (flow->packet_counter < 3) {
+ if(flow->packet_counter < 3) {
NDPI_LOG_DBG(ndpi_struct, "packet_counter < 3, need next packet\n");
}
init_seq(ndpi_struct, flow, packet->packet_direction, seqnum, 1);
}
- if (seqnum <= 3) {
+ if(seqnum <= 3) {
NDPI_LOG_DBG(ndpi_struct, "sequence_number = %u, too small, need next packet, return\n", seqnum);
return;
}
- if (stage == 3) {
+ if(stage == 3) {
NDPI_LOG_DBG(ndpi_struct, "add connection I\n");
ndpi_int_rtp_add_connection(ndpi_struct, flow);
} else {
packet->packet_direction == 0 ? flow->rtp_stage1++ : flow->rtp_stage2++;
NDPI_LOG_DBG(ndpi_struct, "stage[%u]++; need next packet\n",
- packet->packet_direction);
+ packet->packet_direction);
}
return;
- exclude_rtp:
- if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN
- || /* packet->real_protocol_read_only == NDPI_PROTOCOL_STUN */) {
+exclude_rtp:
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN
+ || /* packet->real_protocol_read_only == NDPI_PROTOCOL_STUN */) {
NDPI_LOG_DBG(ndpi_struct, "STUN: is detected, need next packet\n");
return;
}
@@ -344,17 +346,17 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd
struct ndpi_packet_struct *packet = &flow->packet;
- if (packet->udp) {
+ if(packet->udp) {
ndpi_rtp_search(ndpi_struct, flow, packet->payload, packet->payload_packet_len);
- } else if (packet->tcp) {
+ } else if(packet->tcp) {
/* skip special packets seen at yahoo traces */
- if (packet->payload_packet_len >= 20 && ntohs(get_u_int16_t(packet->payload, 2)) + 20 == packet->payload_packet_len &&
- packet->payload[0] == 0x90 && packet->payload[1] >= 0x01 && packet->payload[1] <= 0x07) {
- if (flow->packet_counter == 2)
+ if(packet->payload_packet_len >= 20 && ntohs(get_u_int16_t(packet->payload, 2)) + 20 == packet->payload_packet_len &&
+ packet->payload[0] == 0x90 && packet->payload[1] >= 0x01 && packet->payload[1] <= 0x07) {
+ if(flow->packet_counter == 2)
flow->l4.tcp.rtp_special_packets_seen = 1;
NDPI_LOG_DBG(ndpi_struct,
- "skipping STUN-like, special yahoo packets with payload[0] == 0x90.\n");
+ "skipping STUN-like, special yahoo packets with payload[0] == 0x90.\n");
return;
}
@@ -365,12 +367,12 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd
* we can remove this restriction
*/
- if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN
- || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_RTP) {
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN
+ || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_RTP) {
/* RTP may be encapsulated in TCP packets */
- if (packet->payload_packet_len >= 2 && ntohs(get_u_int16_t(packet->payload, 0)) + 2 == packet->payload_packet_len) {
+ if(packet->payload_packet_len >= 2 && ntohs(get_u_int16_t(packet->payload, 0)) + 2 == packet->payload_packet_len) {
/* TODO there could be several RTP packets in a single TCP packet so maybe the detection could be
* improved by checking only the RTP packet of given length */
@@ -381,9 +383,9 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd
}
}
- if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN && flow->l4.tcp.rtp_special_packets_seen == 1) {
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN && flow->l4.tcp.rtp_special_packets_seen == 1) {
- if (packet->payload_packet_len >= 4 && ntohl(get_u_int32_t(packet->payload, 0)) + 4 == packet->payload_packet_len) {
+ if(packet->payload_packet_len >= 4 && ntohl(get_u_int32_t(packet->payload, 0)) + 4 == packet->payload_packet_len) {
/* TODO there could be several RTP packets in a single TCP packet so maybe the detection could be
* improved by checking only the RTP packet of given length */
@@ -394,7 +396,7 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd
}
}
- if (NDPI_FLOW_PROTOCOL_EXCLUDED(ndpi_struct, flow, NDPI_PROTOCOL_STUN)) {
+ if(NDPI_FLOW_PROTOCOL_EXCLUDED(ndpi_struct, flow, NDPI_PROTOCOL_STUN)) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
} else {
NDPI_LOG_DBG(ndpi_struct, "STUN not yet excluded, need next packet\n");
@@ -416,4 +418,3 @@ void init_rtp_dissector(struct ndpi_detection_module_struct *ndpi_struct,
*id += 1;
}
-
diff --git a/src/lib/protocols/ssh.c b/src/lib/protocols/ssh.c
index 1a20078c3..7e5ca5e62 100644
--- a/src/lib/protocols/ssh.c
+++ b/src/lib/protocols/ssh.c
@@ -2,7 +2,7 @@
* ssh.c
*
* Copyright (C) 2009-2011 by ipoque GmbH
- * Copyright (C) 2011-18 - ntop.org
+ * Copyright (C) 2011-19 - ntop.org
*
* This file is part of nDPI, an open source deep packet inspection
* library based on the OpenDPI and PACE technology by ipoque GmbH
@@ -19,7 +19,7 @@
*
* 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"
@@ -27,12 +27,134 @@
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SSH
#include "ndpi_api.h"
+#include "ndpi_md5.h"
+
+/*
+ HASSH - https://github.com/salesforce/hassh
+
+ https://github.com/salesforce/hassh/blob/master/python/hassh.py
+
+ [server]
+ skex = packet.ssh.kex_algorithms
+ seastc = packet.ssh.encryption_algorithms_server_to_client
+ smastc = packet.ssh.mac_algorithms_server_to_client
+ scastc = packet.ssh.compression_algorithms_server_to_client
+ hasshs_str = ';'.join([skex, seastc, smastc, scastc])
+
+ [client]
+ ckex = packet.ssh.kex_algorithms
+ ceacts = packet.ssh.encryption_algorithms_client_to_server
+ cmacts = packet.ssh.mac_algorithms_client_to_server
+ ccacts = packet.ssh.compression_algorithms_client_to_server
+ hassh_str = ';'.join([ckex, ceacts, cmacts, ccacts])
+*/
+
+/* #define SSH_DEBUG 1 */
+
+/* ************************************************************************ */
static void ndpi_int_ssh_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_SSH, NDPI_PROTOCOL_UNKNOWN);
}
+/* ************************************************************************ */
+
+static u_int16_t concat_hash_string(struct ndpi_packet_struct *packet,
+ char *buf, u_int8_t client_hash) {
+ u_int16_t offset = 22, buf_out_len = 0;
+ u_int32_t len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+
+ if(len < (packet->payload_packet_len-offset)) {
+ /* ssh.kex_algorithms [C/S] */
+ offset += 4;
+ strncpy(buf, (const char *)&packet->payload[offset], buf_out_len = len);
+ buf[buf_out_len++] = ';';
+ offset += len;
+
+ /* ssh.server_host_key_algorithms [None] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ offset += 4 + len;
+
+ /* ssh.encryption_algorithms_client_to_server [C] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+
+ if(client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.encryption_algorithms_server_to_client [S] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(!client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.mac_algorithms_client_to_server [C] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.mac_algorithms_server_to_client [S] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(!client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.compression_algorithms_client_to_server [C] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.compression_algorithms_server_to_client [S] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(!client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.languages_client_to_server [None] */
+
+ /* ssh.languages_server_to_client [None] */
+ }
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] %s\n", buf);
+#endif
+
+ return(buf_out_len);
+}
+
+/* ************************************************************************ */
+
static void ndpi_ssh_zap_cr(char *str, int len) {
len--;
@@ -45,46 +167,132 @@ static void ndpi_ssh_zap_cr(char *str, int len) {
}
}
-void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
-{
- struct ndpi_packet_struct *packet = &flow->packet;
+/* ************************************************************************ */
+
+void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [stage: %u]\n", flow->l4.tcp.ssh_stage);
+#endif
- if (flow->l4.tcp.ssh_stage == 0) {
- if (packet->payload_packet_len > 7 && packet->payload_packet_len < 100
+ if(flow->l4.tcp.ssh_stage == 0) {
+ if(packet->payload_packet_len > 7 && packet->payload_packet_len < 100
&& memcmp(packet->payload, "SSH-", 4) == 0) {
if(!ndpi_struct->disable_metadata_export) {
- int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len);
+ int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len);
+
strncpy(flow->protos.ssh.client_signature, (const char *)packet->payload, len);
flow->protos.ssh.client_signature[len] = '\0';
ndpi_ssh_zap_cr(flow->protos.ssh.client_signature, len);
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [client_signature: %s]\n", flow->protos.ssh.client_signature);
+#endif
}
-
+
NDPI_LOG_DBG2(ndpi_struct, "ssh stage 0 passed\n");
flow->l4.tcp.ssh_stage = 1 + packet->packet_direction;
+ flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH;
return;
}
- } else if (flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) {
- if (packet->payload_packet_len > 7 && packet->payload_packet_len < 500
+ } else if(flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) {
+ if(packet->payload_packet_len > 7 && packet->payload_packet_len < 500
&& memcmp(packet->payload, "SSH-", 4) == 0) {
if(!ndpi_struct->disable_metadata_export) {
int len = ndpi_min(sizeof(flow->protos.ssh.server_signature)-1, packet->payload_packet_len);
+
strncpy(flow->protos.ssh.server_signature, (const char *)packet->payload, len);
flow->protos.ssh.server_signature[len] = '\0';
ndpi_ssh_zap_cr(flow->protos.ssh.server_signature, len);
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [server_signature: %s]\n", flow->protos.ssh.server_signature);
+#endif
+
+ NDPI_LOG_DBG2(ndpi_struct, "ssh stage 1 passed\n");
+ flow->l4.tcp.ssh_stage++;;
+ flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH;
+ } else {
+ NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
+ ndpi_int_ssh_add_connection(ndpi_struct, flow);
}
-
- NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
-
- ndpi_int_ssh_add_connection(ndpi_struct, flow);
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [completed stage: %u]\n", flow->l4.tcp.ssh_stage);
+#endif
+
return;
+ }
+ } else {
+ u_int8_t msgcode = *(packet->payload + 5);
+ ndpi_MD5_CTX ctx;
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [stage: %u][msg: %u]\n", flow->l4.tcp.ssh_stage, msgcode);
+#endif
+ if(msgcode == 20 /* key exchange init */) {
+ char *hassh_buf = calloc(packet->payload_packet_len, sizeof(char));
+ u_int i, len;
+
+ if(hassh_buf) {
+ if(flow->l4.tcp.ssh_stage == 3) {
+ u_char fingerprint_client[16];
+
+ len = concat_hash_string(packet, hassh_buf, 1 /* client */);
+
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len);
+ ndpi_MD5Final(fingerprint_client, &ctx);
+
+#ifdef SSH_DEBUG
+ {
+ printf("\n[SSH] [client][%s][", hassh_buf);
+ for(i=0; i<16; i++) printf("%02X", fingerprint_client[i]);
+ printf("]\n");
+ }
+#endif
+ for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_client[i*2], "%02X", fingerprint_client[i] & 0xFF);
+ flow->protos.ssh.hassh_client[32] = '\0';
+ } else {
+ u_char fingerprint_server[16];
+
+ len = concat_hash_string(packet, hassh_buf, 0 /* server */);
+
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len);
+ ndpi_MD5Final(fingerprint_server, &ctx);
+
+#ifdef SSH_DEBUG
+ {
+ printf("\n[SSH] [server][%s][", hassh_buf);
+ for(i=0; i<16; i++) printf("%02X", fingerprint_server[i]);
+ printf("]\n");
+ }
+#endif
+
+ for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_server[i*2], "%02X", fingerprint_server[i] & 0xFF);
+ flow->protos.ssh.hassh_server[32] = '\0';
+ }
+
+ free(hassh_buf);
+ }
}
+
+ if(flow->l4.tcp.ssh_stage++ == 4) {
+ NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
+ ndpi_int_ssh_add_connection(ndpi_struct, flow);
+ }
+
+ return;
}
NDPI_LOG_DBG(ndpi_struct, "excluding ssh at stage %d\n", flow->l4.tcp.ssh_stage);
NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SSH);
}
+/* ************************************************************************ */
void init_ssh_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
{
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c
index 202b3d939..8334c667a 100644
--- a/src/lib/protocols/stun.c
+++ b/src/lib/protocols/stun.c
@@ -30,7 +30,9 @@
#define MAX_NUM_STUN_PKTS 8
-// #define DEBUG_STUN 1
+/* #define DEBUG_STUN 1 */
+
+/* #define DEBUG_LRU 1 */
struct stun_packet_header {
u_int16_t msg_type, msg_len;
@@ -38,9 +40,43 @@ struct stun_packet_header {
u_int8_t transaction_id[8];
};
+/* ************************************************************ */
+
+u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow) {
+ return(flow->packet.iph->saddr + flow->packet.udp->source);
+}
+
+/* ************************************************************ */
+
static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
- u_int proto, struct ndpi_flow_struct *flow) {
- ndpi_set_detected_protocol(ndpi_struct, flow, proto, NDPI_PROTOCOL_UNKNOWN);
+ struct ndpi_flow_struct *flow,
+ u_int app_proto, u_int proto) {
+ if(ndpi_struct->stun_cache == NULL)
+ ndpi_struct->stun_cache = ndpi_lru_cache_init(1024);
+
+ if(ndpi_struct->stun_cache
+ && flow->packet.iph
+ && flow->packet.udp
+ && (app_proto != NDPI_PROTOCOL_UNKNOWN)
+ ) /* Cache flow sender info */ {
+ u_int32_t key = get_stun_lru_key(flow);
+ u_int16_t cached_proto;
+
+ if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &cached_proto, 0 /* Don't remove it as it can be used for other connections */)) {
+#ifdef DEBUG_LRU
+ printf("[LRU] FOUND %u / %u: no need to cache %u.%u\n", key, cached_proto, proto, app_proto);
+#endif
+ app_proto = cached_proto, proto = NDPI_PROTOCOL_STUN;
+ } else {
+#ifdef DEBUG_LRU
+ printf("[LRU] ADDING %u / %u.%u\n", key, proto, app_proto);
+#endif
+
+ ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, app_proto);
+ }
+ }
+
+ ndpi_set_detected_protocol(ndpi_struct, flow, app_proto, proto);
}
typedef enum {
@@ -48,6 +84,7 @@ typedef enum {
NDPI_IS_NOT_STUN
} ndpi_int_stun_t;
+/* ************************************************************ */
static int is_google_ip_address(u_int32_t host) {
if(
@@ -59,6 +96,29 @@ static int is_google_ip_address(u_int32_t host) {
return(0);
}
+/* ************************************************************ */
+
+/*
+ WhatsApp
+ 31.13.86.48
+ 31.13.92.50
+ 157.240.20.51
+ 157.240.21.51
+ 185.60.216.51
+
+ Messenger
+ 31.13.86.5
+*/
+
+static int is_messenger_ip_address(u_int32_t host) {
+ if(host == 0x1F0D5605 /* 31.13.86.5 */)
+ return(1);
+ else
+ return(0);
+}
+
+/* ************************************************************ */
+
static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
const u_int8_t * payload,
@@ -77,7 +137,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
*is_whatsapp = 0, *is_messenger = 0, *is_duo = 0;
if(payload_length < sizeof(struct stun_packet_header)) {
- /* This looks like an invlid packet */
+ /* This looks like an invalid packet */
if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) {
*is_whatsapp = 1;
@@ -98,18 +158,47 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if(msg_type > 0x000C)
return(NDPI_IS_NOT_STUN);
+ if(ndpi_struct->stun_cache) {
+ u_int16_t proto;
+ u_int32_t key = get_stun_lru_key(flow);
+
+ if(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] FOUND %u / %u\n", key, proto);
+#endif
+
+ flow->guessed_host_protocol_id = proto, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ return(NDPI_IS_STUN);
+ } else {
+#ifdef DEBUG_LRU
+ printf("[LRU] NOT FOUND %u\n", key);
+#endif
+ }
+ } else {
+#ifdef DEBUG_LRU
+ printf("[LRU] NO/EMPTY CACHE\n");
+#endif
+ }
+
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 == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE))
flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO;
- }
+ else
+ flow->guessed_host_protocol_id = NDPI_PROTOCOL_STUN;
+
+ flow->protos.stun_ssl.stun.num_udp_pkts++;
+
+ if(msg_len == 0)
+ 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)) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return(NDPI_IS_NOT_STUN);
}
-
+
flow->protos.stun_ssl.stun.num_udp_pkts++;
/*
@@ -131,9 +220,20 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if((payload[0] != 0x80) && ((msg_len+20) > payload_length))
return(NDPI_IS_NOT_STUN);
- else
- flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
-
+ else {
+ switch(flow->guessed_protocol_id) {
+ case NDPI_PROTOCOL_HANGOUT_DUO:
+ case NDPI_PROTOCOL_MESSENGER:
+ case NDPI_PROTOCOL_WHATSAPP_VOICE:
+ /* Don't overwrite the protocol with sub-STUN protocols */
+ break;
+
+ default:
+ flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ break;
+ }
+ }
+
if(payload_length == (msg_len+20)) {
if(msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ {
u_int offset = 20;
@@ -157,6 +257,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if(x != 0)
len += 4-x;
+#ifdef DEBUG_STUN
+ printf("==> Attribute: %04X\n", attribute);
+#endif
+
switch(attribute) {
case 0x0008: /* Message Integrity */
case 0x0020: /* XOR-MAPPED-ADDRESSES */
@@ -166,6 +270,28 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
/* These are the only messages apparently whatsapp voice can use */
break;
+ 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;
+
+ memset(flow->host_server_name, 0, sizeof(flow->host_server_name));
+
+ for(j=0; j<i; j++)
+ flow->host_server_name[j] = payload[k++];
+
+ if(strstr((char*)flow->host_server_name, "google.com") != NULL) {
+ *is_duo = 1;
+ flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, 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)) {
@@ -173,7 +299,12 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
return(NDPI_IS_STUN);
} else if(msg_len == 76) {
*is_duo = 1;
- return(NDPI_IS_STUN);
+
+ 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);
}
}
break;
@@ -185,6 +316,9 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
&& (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");
+#endif
flow->protos.stun_ssl.stun.is_skype = 1;
return(NDPI_IS_STUN);
}
@@ -201,6 +335,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
case 0x0800:
/* printf("====>>>> %04X\n", attribute); */
flow->protos.stun_ssl.stun.is_skype = 1;
+#ifdef DEBUG_STUN
+ printf("==> Skype (2) found\n");
+#endif
+
return(NDPI_IS_STUN);
break;
@@ -213,6 +351,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
&& ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03))
) {
flow->protos.stun_ssl.stun.is_skype = 1;
+#ifdef DEBUG_STUN
+ printf("==> Skype (3) found\n");
+#endif
+
return(NDPI_IS_STUN);
}
break;
@@ -221,7 +363,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
can_this_be_whatsapp_voice = 0;
flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO;
break;
-
+
default:
/* This means this STUN packet cannot be confused with whatsapp voice */
#ifdef DEBUG_STUN
@@ -249,15 +391,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
udp_stun_found:
if(can_this_be_whatsapp_voice) {
struct ndpi_packet_struct *packet = &flow->packet;
-
+
flow->protos.stun_ssl.stun.num_processed_pkts++;
#ifdef DEBUG_STUN
printf("==>> NDPI_PROTOCOL_WHATSAPP_VOICE\n");
#endif
- if((ntohs(packet->udp->source) == 3478) || (ntohs(packet->udp->dest) == 3478))
- flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_VOICE;
- else
+ 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_VOICE;
+ } 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_VOICE;
return((flow->protos.stun_ssl.stun.num_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN);
@@ -295,23 +438,24 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n
if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload + 2,
packet->payload_packet_len - 2,
&is_whatsapp, &is_messenger, &is_duo) == NDPI_IS_STUN) {
- if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
if(is_messenger) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
return;
} else if(is_duo) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
return;
} else if(flow->protos.stun_ssl.stun.is_skype) {
NDPI_LOG_INFO(ndpi_struct, "found Skype\n");
if((flow->protos.stun_ssl.stun.num_processed_pkts >= 8) || (flow->protos.stun_ssl.stun.num_binding_requests >= 4))
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE);
} else {
NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n"); /* Ummmmm we're in the TCP branch. This code looks bad */
- ndpi_int_stun_add_connection(ndpi_struct,
- is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, flow);
+ ndpi_int_stun_add_connection(ndpi_struct, flow,
+ is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN,
+ NDPI_PROTOCOL_UNKNOWN);
}
return;
@@ -323,26 +467,25 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n
if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload,
packet->payload_packet_len,
&is_whatsapp, &is_messenger, &is_duo) == NDPI_IS_STUN) {
- if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
if(is_messenger) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
return;
} else if(is_duo) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
return;
} else if(flow->protos.stun_ssl.stun.is_skype) {
NDPI_LOG_INFO(ndpi_struct, "Found Skype\n");
/* flow->protos.stun_ssl.stun.num_binding_requests < 4) ? NDPI_PROTOCOL_SKYPE_CALL_IN : NDPI_PROTOCOL_SKYPE_CALL_OUT */
if((flow->protos.stun_ssl.stun.num_processed_pkts >= 8) || (flow->protos.stun_ssl.stun.num_binding_requests >= 4))
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE);
} else {
NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n");
- ndpi_int_stun_add_connection(ndpi_struct,
+ ndpi_int_stun_add_connection(ndpi_struct, flow,
is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO)
- : NDPI_PROTOCOL_STUN,
- flow);
+ : NDPI_PROTOCOL_STUN, NDPI_PROTOCOL_UNKNOWN);
}
return;
diff --git a/src/lib/protocols/teamspeak.c b/src/lib/protocols/teamspeak.c
index 214a2fe99..170be1d7f 100644
--- a/src/lib/protocols/teamspeak.c
+++ b/src/lib/protocols/teamspeak.c
@@ -35,32 +35,43 @@ void ndpi_search_teamspeak(struct ndpi_detection_module_struct *ndpi_struct, str
struct ndpi_packet_struct *packet = &flow->packet;
NDPI_LOG_DBG(ndpi_struct, "search teamspeak\n");
+
- if (packet->udp != NULL) {
+#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) {
+ 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 if (packet->tcp != NULL) {
- u_int16_t tdport, tsport;
- tsport = ntohs(packet->tcp->source), tdport = ntohs(packet->tcp->dest);
- /* 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)) ||
+ else
+#endif
+
+ if(packet->tcp != NULL) {
+ u_int16_t tdport, tsport;
+ tsport = ntohs(packet->tcp->source), tdport = ntohs(packet->tcp->dest);
+ /* 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 */
- } 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);
- }
- }
+ 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 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
+ }
+
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}
diff --git a/src/lib/protocols/ssl.c b/src/lib/protocols/tls.c
index 18e8ca469..d9b7b0962 100644
--- a/src/lib/protocols/ssl.c
+++ b/src/lib/protocols/tls.c
@@ -1,7 +1,7 @@
/*
- * ssl.c
+ * tls.c - SSL/TLS/DTLS dissector
*
- * Copyright (C) 2016-18 - ntop.org
+ * Copyright (C) 2016-19 - ntop.org
*
* This file is part of nDPI, an open source deep packet inspection
* library based on the OpenDPI and PACE technology by ipoque GmbH
@@ -23,13 +23,14 @@
#include "ndpi_protocol_ids.h"
-#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SSL
+#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_TLS
#include "ndpi_api.h"
+#include "ndpi_md5.h"
-/* #define CERTIFICATE_DEBUG 1 */
+// #define DEBUG_TLS 1
-#define NDPI_MAX_SSL_REQUEST_SIZE 10000
+#define NDPI_MAX_TLS_REQUEST_SIZE 10000
/* Skype.c */
extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct,
@@ -37,220 +38,23 @@ extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct,
/* **************************************** */
-typedef struct MD5Context {
- uint32_t buf[4];
- uint32_t bits[2];
- unsigned char in[64];
-} MD5_CTX;
-
-/* **************************************** */
-
-static int is_big_endian(void) {
- static const int n = 1;
- return ((char *) &n)[0] == 0;
-}
-
-static void byteReverse(unsigned char *buf, unsigned longs) {
- uint32_t t;
-
- // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
- if (is_big_endian()) {
- do {
- t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- * (uint32_t *) buf = t;
- buf += 4;
- } while (--longs);
- }
-}
-
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
-// initialization constants.
-static void MD5Init(MD5_CTX *ctx) {
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
-
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
- uint32_t a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
- uint32_t t;
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
- ctx->bits[1]++;
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f;
-
- if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
-
- t = 64 - t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += t;
- len -= t;
- }
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += 64;
- len -= 64;
- }
-
- memcpy(ctx->in, buf, len);
-}
-
-static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
- unsigned count;
- unsigned char *p;
- uint32_t *c = (uint32_t*)ctx->in;
-
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- p = ctx->in + count;
- *p++ = 0x80;
- count = 64 - 1 - count;
- if (count < 8) {
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- memset(ctx->in, 0, 56);
- } else {
- memset(p, 0, count - 8);
- }
- byteReverse(ctx->in, 14);
-
- c[14] = ctx->bits[0];
- c[15] = ctx->bits[1];
-
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
- memset((char *) ctx, 0, sizeof(*ctx));
-}
-
-/* **************************************** */
-
-static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow, u_int32_t protocol)
-{
+static u_int32_t ndpi_tls_refine_master_protocol(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow, u_int32_t protocol) {
struct ndpi_packet_struct *packet = &flow->packet;
if(((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.ja3_client[0] != '\0'))
|| ((flow->l4.tcp.ssl_seen_server_cert == 1) && (flow->protos.stun_ssl.ssl.ja3_server[0] != '\0'))
// || (flow->host_server_name[0] != '\0')
)
- protocol = NDPI_PROTOCOL_SSL;
+ protocol = NDPI_PROTOCOL_TLS;
else
- protocol = NDPI_PROTOCOL_SSL_NO_CERT;
+ protocol = NDPI_PROTOCOL_TLS_NO_CERT;
if(packet->tcp != NULL) {
switch(protocol) {
- case NDPI_PROTOCOL_SSL:
- case NDPI_PROTOCOL_SSL_NO_CERT:
+ case NDPI_PROTOCOL_TLS:
+ case NDPI_PROTOCOL_TLS_NO_CERT:
{
/*
In case of SSL there are probably sub-protocols
@@ -273,18 +77,21 @@ static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_st
return protocol;
}
-static void ndpi_int_ssl_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow, u_int32_t protocol)
-{
- if((protocol != NDPI_PROTOCOL_SSL)
- && (protocol != NDPI_PROTOCOL_SSL_NO_CERT)) {
+/* **************************************** */
+
+static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow, u_int32_t protocol) {
+ if((protocol != NDPI_PROTOCOL_TLS)
+ && (protocol != NDPI_PROTOCOL_TLS_NO_CERT)) {
ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_UNKNOWN);
} else {
- protocol = ndpi_ssl_refine_master_protocol(ndpi_struct, flow, protocol);
+ protocol = ndpi_tls_refine_master_protocol(ndpi_struct, flow, protocol);
ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_UNKNOWN);
}
}
+/* **************************************** */
+
/* Can't call libc functions from kernel space, define some stub instead */
#define ndpi_isalpha(ch) (((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
@@ -296,8 +103,9 @@ static void ndpi_int_ssl_add_connection(struct ndpi_detection_module_struct *ndp
((ch) >= '[' && (ch) <= '`') || \
((ch) >= '{' && (ch) <= '~'))
-static void stripCertificateTrailer(char *buffer, int buffer_len) {
+/* **************************************** */
+static void stripCertificateTrailer(char *buffer, int buffer_len) {
int i, is_puny;
// printf("->%s<-\n", buffer);
@@ -346,42 +154,53 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) {
buffer[i] = tolower(buffer[i]);
}
+/* **************************************** */
+
/* https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967 */
#define JA3_STR_LEN 1024
#define MAX_NUM_JA3 128
struct ja3_info {
- u_int16_t ssl_version;
+ u_int16_t tls_version;
u_int16_t num_cipher, cipher[MAX_NUM_JA3];
- u_int16_t num_ssl_extension, ssl_extension[MAX_NUM_JA3];
+ u_int16_t num_tls_extension, tls_extension[MAX_NUM_JA3];
u_int16_t num_elliptic_curve, elliptic_curve[MAX_NUM_JA3];
u_int8_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA3];
};
/* **************************************** */
-/* code fixes courtesy of Alexsandro Brahm <alex@digistar.com.br> */
-int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
+int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
char *buffer, int buffer_len) {
struct ndpi_packet_struct *packet = &flow->packet;
struct ja3_info ja3;
+ int i;
u_int8_t invalid_ja3 = 0;
- u_int16_t ssl_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len;
+ u_int16_t pkt_tls_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len;
char ja3_str[JA3_STR_LEN];
- MD5_CTX ctx;
+ ndpi_MD5_CTX ctx;
u_char md5_hash[16];
- flow->protos.stun_ssl.ssl.ssl_version = ssl_version;
+ if(packet->udp) {
+ /* Check if this is DTLS or return */
+ if((packet->payload[1] != 0xfe)
+ || ((packet->payload[2] != 0xff) && (packet->payload[2] != 0xfd))) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return(0);
+ }
+ }
+
+ flow->protos.stun_ssl.ssl.ssl_version = pkt_tls_version;
memset(&ja3, 0, sizeof(ja3));
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
{
- u_int16_t ssl_len = (packet->payload[3] << 8) + packet->payload[4];
+ u_int16_t tls_len = (packet->payload[3] << 8) + packet->payload[4];
- printf("SSL Record [version: %u][len: %u]\n", ssl_version, ssl_len);
+ printf("SSL Record [version: 0x%04X][len: %u]\n", pkt_tls_version, tls_len);
}
#endif
@@ -390,9 +209,21 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
Patches courtesy of Denys Fedoryshchenko <nuclearcat@nuclearcat.com>
*/
if(packet->payload[0] == 0x16 /* Handshake */) {
- u_int16_t total_len = (packet->payload[3] << 8) + packet->payload[4] + 5 /* SSL Header */;
- u_int8_t handshake_protocol = packet->payload[5]; /* handshake protocol a bit misleading, it is message type according TLS specs */
+ u_int16_t total_len;
+ u_int8_t handshake_protocol, header_len;
+
+ if(packet->tcp) {
+ header_len = 5; /* SSL Header */
+ handshake_protocol = packet->payload[5]; /* handshake protocol a bit misleading, it is message type according TLS specs */
+ total_len = (packet->payload[3] << 8) + packet->payload[4];
+ } else {
+ header_len = 13; /* DTLS header */
+ handshake_protocol = packet->payload[13];
+ total_len = ntohs(*((u_int16_t*)&packet->payload[11]));
+ }
+ total_len += header_len;
+
memset(buffer, 0, buffer_len);
/* Truncate total len, search at least in incomplete packet */
@@ -401,48 +232,58 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
/* At least "magic" 3 bytes, null for string end, otherwise no need to waste cpu cycles */
if(total_len > 4) {
- int i;
-
-#ifdef CERTIFICATE_DEBUG
+ u_int16_t base_offset = packet->tcp ? 43 : 59;
+
+#ifdef DEBUG_TLS
printf("SSL [len: %u][handshake_protocol: %02X]\n", packet->payload_packet_len, handshake_protocol);
#endif
-
+
if((handshake_protocol == 0x02)
- || (handshake_protocol == 0xb) /* Server Hello and Certificate message types are interesting for us */) {
+ || (handshake_protocol == 0x0b) /* Server Hello and Certificate message types are interesting for us */) {
u_int num_found = 0;
- u_int16_t ssl_version = ntohs(*((u_int16_t*)&packet->payload[9]));
+ u_int16_t tls_version;
+ int i;
- ja3.ssl_version = ssl_version;
+ if(packet->tcp)
+ tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+4]));
+ else
+ tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+12]));
+
+ ja3.tls_version = tls_version;
if(handshake_protocol == 0x02) {
- u_int16_t offset = 43, extension_len, j;
- u_int8_t session_id_len = packet->payload[43];
+ u_int16_t offset = base_offset, extension_len, j;
+ u_int8_t session_id_len = packet->payload[offset];
-#ifdef CERTIFICATE_DEBUG
- printf("SSL Server Hello [version: 0x%04X]\n", ssl_version);
+#ifdef DEBUG_TLS
+ printf("SSL Server Hello [version: 0x%04X]\n", tls_version);
#endif
/*
The server hello decides about the SSL version of this flow
https://networkengineering.stackexchange.com/questions/55752/why-does-wireshark-show-version-tls-1-2-here-instead-of-tls-1-3
*/
- flow->protos.stun_ssl.ssl.ssl_version = ssl_version;
-
- if(ssl_version < 0x7F15 /* TLS 1.3 lacks of session id */)
- offset += session_id_len+1;
+ flow->protos.stun_ssl.ssl.ssl_version = tls_version;
+ if(packet->udp)
+ offset += 1;
+ else {
+ if(tls_version < 0x7F15 /* TLS 1.3 lacks of session id */)
+ offset += session_id_len+1;
+ }
+
ja3.num_cipher = 1, ja3.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset]));
flow->protos.stun_ssl.ssl.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja3.cipher[0]);
flow->protos.stun_ssl.ssl.server_cipher = ja3.cipher[0];
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("SSL [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.cipher[0]);
#endif
offset += 2 + 1;
extension_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("SSL [server][extension_len: %u]\n", extension_len);
#endif
offset += 2;
@@ -455,17 +296,17 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
id = ntohs(*((u_int16_t*)&packet->payload[offset]));
len = ntohs(*((u_int16_t*)&packet->payload[offset+2]));
- if(ja3.num_ssl_extension < MAX_NUM_JA3)
- ja3.ssl_extension[ja3.num_ssl_extension++] = id;
+ if(ja3.num_tls_extension < MAX_NUM_JA3)
+ ja3.tls_extension[ja3.num_tls_extension++] = id;
-#ifdef CERTIFICATE_DEBUG
- printf("SSL [server][extension_id: %u]\n", id);
+#ifdef DEBUG_TLS
+ printf("SSL [server][extension_id: %u/0x%04X]\n", id, id);
#endif
i += 4 + len, offset += 4 + len;
}
- ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.ssl_version);
+ ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_version);
for(i=0; i<ja3.num_cipher; i++)
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.cipher[i]);
@@ -474,26 +315,26 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
/* ********** */
- for(i=0; i<ja3.num_ssl_extension; i++)
- ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.ssl_extension[i]);
+ for(i=0; i<ja3.num_tls_extension; i++)
+ ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.tls_extension[i]);
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("SSL [server] %s\n", ja3_str);
#endif
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("[JA3] Server: %s \n", ja3_str);
#endif
- MD5Init(&ctx);
- MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
- MD5Final(md5_hash, &ctx);
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
+ ndpi_MD5Final(md5_hash, &ctx);
for(i=0, j=0; i<16; i++)
j += snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j],
sizeof(flow->protos.stun_ssl.ssl.ja3_server)-j, "%02x", md5_hash[i]);
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("[JA3] Server: %s \n", flow->protos.stun_ssl.ssl.ja3_server);
#endif
@@ -554,28 +395,46 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
}
}
} else if(handshake_protocol == 0x01 /* Client Hello */) {
- u_int offset, base_offset = 43;
+ u_int offset;
- if(base_offset + 2 <= packet->payload_packet_len) {
- u_int16_t session_id_len = packet->payload[base_offset];
- u_int16_t ssl_version = ntohs(*((u_int16_t*)&packet->payload[9]));
+#ifdef DEBUG_TLS
+ printf("[base_offset: %u][payload_packet_len: %u]\n", base_offset, packet->payload_packet_len);
+#endif
- ja3.ssl_version = ssl_version;
+ if(base_offset + 2 <= packet->payload_packet_len) {
+ u_int16_t session_id_len;
+ u_int16_t tls_version;
+ if(packet->tcp)
+ tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+4]));
+ else
+ tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+12]));
+
+ session_id_len = packet->payload[base_offset];
+
+ ja3.tls_version = tls_version;
+
if((session_id_len+base_offset+2) <= total_len) {
- u_int16_t cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
- u_int16_t i, cipher_offset = base_offset + session_id_len + 3;
+ u_int16_t cipher_len, cipher_offset;
-#ifdef CERTIFICATE_DEBUG
- printf("Client SSL [client cipher_len: %u]\n", cipher_len);
+ if(packet->tcp) {
+ cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
+ cipher_offset = base_offset + session_id_len + 3;
+ } else {
+ cipher_len = ntohs(*((u_int16_t*)&packet->payload[base_offset+2]));
+ cipher_offset = base_offset+4;
+ }
+
+#ifdef DEBUG_TLS
+ printf("Client SSL [client cipher_len: %u][tls_version: 0x%04X]\n", cipher_len, tls_version);
#endif
if((cipher_offset+cipher_len) <= total_len) {
for(i=0; i<cipher_len;) {
u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i];
-#ifdef CERTIFICATE_DEBUG
- printf("Client SSL [cipher suite: %u] [%u/%u]\n", ntohs(*id), i, cipher_len);
+#ifdef DEBUG_TLS
+ printf("Client SSL [cipher suite: %u/0x%04X] [%u/%u]\n", ntohs(*id), ntohs(*id), i, cipher_len);
#endif
if((*id == 0) || (packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1])) {
/*
@@ -587,7 +446,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
ja3.cipher[ja3.num_cipher++] = ntohs(*id);
else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL Invalid cipher %u\n", ja3.num_cipher);
#endif
}
@@ -597,7 +456,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
}
} else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len);
#endif
}
@@ -610,11 +469,11 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t compression_len;
u_int16_t extensions_len;
- offset++;
+ offset += packet->tcp ? 1 : 2;
compression_len = packet->payload[offset];
offset++;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL [compression_len: %u]\n", compression_len);
#endif
@@ -625,7 +484,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
extensions_len = ntohs(*((u_int16_t*)&packet->payload[offset]));
offset += 2;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL [extensions_len: %u]\n", extensions_len);
#endif
@@ -644,19 +503,19 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+extension_offset]));
extension_offset += 2;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL [extension_id: %u][extension_len: %u]\n", extension_id, extension_len);
#endif
if((extension_id == 0) || (packet->payload[extn_off] != packet->payload[extn_off+1])) {
/* Skip GREASE */
- if(ja3.num_ssl_extension < MAX_NUM_JA3)
- ja3.ssl_extension[ja3.num_ssl_extension++] = extension_id;
+ if(ja3.num_tls_extension < MAX_NUM_JA3)
+ ja3.tls_extension[ja3.num_tls_extension++] = extension_id;
else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
- printf("Client SSL Invalid extensions %u\n", ja3.num_ssl_extension);
+#ifdef DEBUG_TLS
+ printf("Client SSL Invalid extensions %u\n", ja3.num_tls_extension);
#endif
}
}
@@ -676,9 +535,9 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
sizeof(flow->protos.stun_ssl.ssl.client_certificate), "%s", buffer);
}
} else if(extension_id == 10 /* supported groups */) {
- u_int16_t i, s_offset = offset+extension_offset + 2;
-
-#ifdef CERTIFICATE_DEBUG
+ u_int16_t s_offset = offset+extension_offset + 2;
+
+#ifdef DEBUG_TLS
printf("Client SSL [EllipticCurveGroups: len=%u]\n", extension_len);
#endif
@@ -686,8 +545,8 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
for(i=0; i<extension_len-2;) {
u_int16_t s_group = ntohs(*((u_int16_t*)&packet->payload[s_offset+i]));
-#ifdef CERTIFICATE_DEBUG
- printf("Client SSL [EllipticCurve: %u]\n", s_group);
+#ifdef DEBUG_TLS
+ printf("Client SSL [EllipticCurve: %u/0x%04X]\n", s_group, s_group);
#endif
if((s_group == 0) || (packet->payload[s_offset+i] != packet->payload[s_offset+i+1])) {
/* Skip GREASE */
@@ -695,7 +554,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
ja3.elliptic_curve[ja3.num_elliptic_curve++] = s_group;
else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve);
#endif
}
@@ -705,21 +564,21 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
}
} else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL Invalid len %u vs %u\n", (s_offset+extension_len-1), total_len);
#endif
}
} else if(extension_id == 11 /* ec_point_formats groups */) {
- u_int16_t i, s_offset = offset+extension_offset + 1;
-
-#ifdef CERTIFICATE_DEBUG
+ u_int16_t s_offset = offset+extension_offset + 1;
+
+#ifdef DEBUG_TLS
printf("Client SSL [EllipticCurveFormat: len=%u]\n", extension_len);
#endif
if((s_offset+extension_len) < total_len) {
for(i=0; i<extension_len-1;i++) {
u_int8_t s_group = packet->payload[s_offset+i];
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL [EllipticCurveFormat: %u]\n", s_group);
#endif
@@ -727,14 +586,14 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
ja3.elliptic_curve_point_format[ja3.num_elliptic_curve_point_format++] = s_group;
else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve_point_format);
#endif
}
}
} else {
invalid_ja3 = 1;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL Invalid len %u vs %u\n", s_offset+extension_len, total_len);
#endif
}
@@ -742,13 +601,13 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
extension_offset += extension_len;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Client SSL [extension_offset/len: %u/%u]\n", extension_offset, extension_len);
#endif
} /* while */
if(!invalid_ja3) {
- ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.ssl_version);
+ ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_version);
for(i=0; i<ja3.num_cipher; i++) {
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
@@ -759,9 +618,9 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
/* ********** */
- for(i=0; i<ja3.num_ssl_extension; i++)
+ for(i=0; i<ja3.num_tls_extension; i++)
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
- (i > 0) ? "-" : "", ja3.ssl_extension[i]);
+ (i > 0) ? "-" : "", ja3.tls_extension[i]);
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ",");
@@ -777,19 +636,20 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u",
(i > 0) ? "-" : "", ja3.elliptic_curve_point_format[i]);
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("[JA3] Client: %s \n", ja3_str);
#endif
-
- MD5Init(&ctx);
- MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
- MD5Final(md5_hash, &ctx);
+
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
+ ndpi_MD5Final(md5_hash, &ctx);
for(i=0, j=0; i<16; i++)
j += snprintf(&flow->protos.stun_ssl.ssl.ja3_client[j],
- sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x", md5_hash[i]);
+ sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x",
+ md5_hash[i]);
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client);
#endif
}
@@ -807,6 +667,8 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct,
return(0); /* Not found */
}
+/* **************************************** */
+
void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
char *buffer, int buffer_len) {
@@ -862,7 +724,7 @@ void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct,
if(is_printable == 1) {
snprintf(flow->protos.stun_ssl.ssl.server_organization,
sizeof(flow->protos.stun_ssl.ssl.server_organization), "%s", buffer);
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
printf("Certificate organization: %s\n", flow->protos.stun_ssl.ssl.server_organization);
#endif
}
@@ -870,20 +732,24 @@ void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct,
}
}
+/* **************************************** */
-int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
+int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
/* consider only specific SSL packets (handshake) */
if((packet->payload_packet_len > 9) && (packet->payload[0] == 0x16)) {
char certificate[64];
- char organization[64];
int rc;
certificate[0] = '\0';
- rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate));
+ rc = getTLScertificate(ndpi_struct, flow, certificate, sizeof(certificate));
packet->ssl_certificate_num_checks++;
+
if(rc > 0) {
+ char organization[64];
+
// try fetch server organization once server certificate is found
organization[0] = '\0';
getSSLorganization(ndpi_struct, flow, organization, sizeof(organization));
@@ -893,20 +759,25 @@ int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi
/* 0 means we're done processing extra packets (since we found what we wanted) */
return 0;
}
+
/* Client hello, Server Hello, and certificate packets probably all checked in this case */
- if((packet->ssl_certificate_num_checks >= 3)
+ if(((packet->ssl_certificate_num_checks >= 3)
&& (flow->l4.tcp.seen_syn)
&& (flow->l4.tcp.seen_syn_ack)
&& (flow->l4.tcp.seen_ack) /* We have seen the 3-way handshake */)
- {
- /* We're done processing extra packets since we've probably checked all possible cert packets */
+ || (flow->protos.stun_ssl.ssl.ja3_server[0] != '\0')
+ ) {
+ /* We're done processing extra packets since we've probably checked all possible cert packets */
return 0;
}
}
+
/* 1 means keep looking for more packets */
return 1;
}
+/* **************************************** */
+
void sslInitExtraPacketProcessing(int caseNum, struct ndpi_flow_struct *flow) {
flow->check_extra_packets = 1;
/* 0 is the case for waiting for the server certificate */
@@ -917,30 +788,33 @@ void sslInitExtraPacketProcessing(int caseNum, struct ndpi_flow_struct *flow) {
}
}
-int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
+/* **************************************** */
+
+int tlsDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
if((packet->payload_packet_len > 9)
&& (packet->payload[0] == 0x16 /* consider only specific SSL packets (handshake) */)) {
if((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN)
- || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL)) {
+ || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS)) {
char certificate[64];
int rc;
certificate[0] = '\0';
- rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate));
+ rc = getTLScertificate(ndpi_struct, flow, certificate, sizeof(certificate));
packet->ssl_certificate_num_checks++;
if(rc > 0) {
packet->ssl_certificate_detected++;
-#ifdef CERTIFICATE_DEBUG
+#ifdef DEBUG_TLS
NDPI_LOG_DBG2(ndpi_struct, "***** [SSL] %s\n", certificate);
#endif
ndpi_protocol_match_result ret_match;
u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate,
strlen(certificate),
&ret_match,
- NDPI_PROTOCOL_SSL);
+ NDPI_PROTOCOL_TLS);
if(subproto != NDPI_PROTOCOL_UNKNOWN) {
/* If we've detected the subprotocol from client certificate but haven't had a chance
@@ -952,11 +826,11 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s
}
ndpi_set_detected_protocol(ndpi_struct, flow, subproto,
- ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL));
+ ndpi_tls_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS));
return(rc); /* Fix courtesy of Gianluca Costa <g.costa@xplico.org> */
}
- if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0)
+ if(ndpi_is_tls_tor(ndpi_struct, flow, certificate) != 0)
return(rc);
}
@@ -969,29 +843,30 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s
&& (flow->protos.stun_ssl.ssl.server_certificate[0] != '\0'))
/* || ((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) */
) {
- ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL);
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
}
}
}
return(0);
}
-static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow)
-{
+/* **************************************** */
+
+static void tls_mark_and_payload_search_for_other_protocols(struct ndpi_detection_module_struct
+ *ndpi_struct, struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
u_int32_t a;
u_int32_t end;
if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_UNENCRYPTED_JABBER) != 0)
- goto check_for_ssl_payload;
+ goto check_for_tls_payload;
if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_OSCAR) != 0)
- goto check_for_ssl_payload;
+ goto check_for_tls_payload;
else
- goto no_check_for_ssl_payload;
+ goto no_check_for_tls_payload;
- check_for_ssl_payload:
+ check_for_tls_payload:
end = packet->payload_packet_len - 20;
for (a = 5; a < end; a++) {
@@ -1000,7 +875,7 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detectio
if(NDPI_COMPARE_PROTOCOL_TO_BITMASK
(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_UNENCRYPTED_JABBER) != 0) {
NDPI_LOG_INFO(ndpi_struct, "found ssl jabber unencrypted\n");
- ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNENCRYPTED_JABBER);
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNENCRYPTED_JABBER);
return;
}
}
@@ -1027,7 +902,7 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detectio
flow->dst->oscar_last_safe_access_time = packet->tick_timestamp;
}
- ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR);
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR);
return;
}
}
@@ -1037,31 +912,32 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detectio
(memcmp(&packet->payload[a], "my.screenname.aol.com", 21) == 0
|| memcmp(&packet->payload[a], "sns-static.aolcdn.com", 21) == 0)) {
NDPI_LOG_DBG(ndpi_struct, "found OSCAR SERVER SSL DETECTED\n");
- ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR);
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR);
return;
}
}
}
- no_check_for_ssl_payload:
+ no_check_for_tls_payload:
if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) {
NDPI_LOG_DBG(ndpi_struct, "found ssl connection\n");
- sslDetectProtocolFromCertificate(ndpi_struct, flow);
+ tlsDetectProtocolFromCertificate(ndpi_struct, flow);
if(!packet->ssl_certificate_detected
&& (!(flow->l4.tcp.ssl_seen_client_cert && flow->l4.tcp.ssl_seen_server_cert))) {
/* SSL without certificate (Skype, Ultrasurf?) */
NDPI_LOG_INFO(ndpi_struct, "found ssl NO_CERT\n");
- ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL_NO_CERT);
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS_NO_CERT);
} else if(packet->ssl_certificate_num_checks >= 3) {
NDPI_LOG_INFO(ndpi_struct, "found ssl\n");
- ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL);
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
}
}
}
+/* **************************************** */
-static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct *ndpi_struct,
+static u_int8_t ndpi_search_tlsv3_direction1(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
@@ -1126,7 +1002,7 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct
if(packet->payload_packet_len >= temp + 5 && (packet->payload[temp] == 0x14 || packet->payload[temp] == 0x16)
&& packet->payload[temp + 1] == 0x03) {
u_int32_t temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5;
- if(temp + temp2 > NDPI_MAX_SSL_REQUEST_SIZE) {
+ if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) {
return 1;
}
temp += temp2;
@@ -1137,7 +1013,7 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct
if(packet->payload_packet_len >= temp + 5 &&
packet->payload[temp] == 0x16 && packet->payload[temp + 1] == 0x03) {
temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5;
- if(temp + temp2 > NDPI_MAX_SSL_REQUEST_SIZE) {
+ if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) {
return 1;
}
temp += temp2;
@@ -1148,7 +1024,7 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct
if(packet->payload_packet_len >= temp + 5 &&
packet->payload[temp] == 0x16 && packet->payload[temp + 1] == 0x03) {
temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5;
- if(temp + temp2 > NDPI_MAX_SSL_REQUEST_SIZE) {
+ if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) {
return 1;
}
temp += temp2;
@@ -1164,20 +1040,51 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct
return 0;
}
-void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
-{
+/* **************************************** */
+
+void ndpi_search_tls_tcp_udp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
u_int8_t ret;
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) {
+ if(packet->udp != NULL) {
+ /* DTLS dissector */
+#ifdef DEBUG_TLS
+ int rc = /* sslTryAndRetrieveServerCertificate(...) */
+#endif
+ sslTryAndRetrieveServerCertificate(ndpi_struct, flow);
+
+#ifdef DEBUG_TLS
+ printf("==>> %u [rc: %u][len: %u][%s][version: %u]\n",
+ flow->guessed_host_protocol_id, rc, packet->payload_packet_len, flow->protos.stun_ssl.ssl.ja3_server,
+ flow->protos.stun_ssl.ssl.ssl_version);
+#endif
+
+ if(flow->protos.stun_ssl.ssl.ssl_version != 0) {
+ flow->guessed_protocol_id = NDPI_PROTOCOL_TLS;
+
+ if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) {
+ /* In Signal protocol STUN turns into DTLS... */
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SIGNAL);
+ } else if(flow->protos.stun_ssl.ssl.ja3_server[0] != '\0') {
+ /* Wait the server certificate the bless this flow as TLS */
+ ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS);
+ }
+ }
+
+ return;
+ }
+
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
if(flow->l4.tcp.ssl_stage == 3 && packet->payload_packet_len > 20 && flow->packet_counter < 5) {
/* this should only happen, when we detected SSL with a packet that had parts of the certificate in subsequent packets
* so go on checking for certificate patterns for a couple more packets
*/
NDPI_LOG_DBG2(ndpi_struct,
"ssl flow but check another packet for patterns\n");
- ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) {
+ tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
+
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
/* still ssl so check another packet */
return;
} else {
@@ -1185,11 +1092,12 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc
return;
}
}
+
return;
}
NDPI_LOG_DBG(ndpi_struct, "search ssl\n");
-
+
/* Check if this is whatsapp first (this proto runs over port 443) */
if((packet->payload_packet_len > 5)
&& ((packet->payload[0] == 'W')
@@ -1206,10 +1114,10 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc
return;
} else {
/* No whatsapp, let's try SSL */
- if(sslDetectProtocolFromCertificate(ndpi_struct, flow) > 0)
+ if(tlsDetectProtocolFromCertificate(ndpi_struct, flow) > 0)
return;
- }
-
+ }
+
if(packet->payload_packet_len > 40 && flow->l4.tcp.ssl_stage == 0) {
NDPI_LOG_DBG2(ndpi_struct, "first ssl packet\n");
// SSLv2 Record
@@ -1234,14 +1142,14 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc
if(packet->payload[0] == 0x17 && packet->payload[1] == 0x03
&& (packet->payload[2] == 0x00 || packet->payload[2] == 0x01 ||
packet->payload[2] == 0x02 || packet->payload[2] == 0x03)) {
- if(packet->payload_packet_len - ntohs(get_u_int16_t(packet->payload, 3)) == 5) {
- NDPI_LOG_DBG2(ndpi_struct, "TLS len match\n");
- flow->l4.tcp.ssl_stage = 1 + packet->packet_direction;
- return;
- }
+ if(packet->payload_packet_len - ntohs(get_u_int16_t(packet->payload, 3)) == 5) {
+ NDPI_LOG_DBG2(ndpi_struct, "TLS len match\n");
+ flow->l4.tcp.ssl_stage = 1 + packet->packet_direction;
+ return;
+ }
}
}
-
+
if(packet->payload_packet_len > 40 &&
flow->l4.tcp.ssl_stage == 1 + packet->packet_direction
&& flow->packet_direction_counter[packet->packet_direction] < 5) {
@@ -1255,20 +1163,20 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc
&& (packet->payload[4] == 0x00 || packet->payload[4] == 0x01 || packet->payload[4] == 0x02)
&& (packet->payload_packet_len - 2) >= packet->payload[1]) {
NDPI_LOG_DBG2(ndpi_struct, "sslv2 server len match\n");
- ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
+ tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
return;
}
- ret = ndpi_search_sslv3_direction1(ndpi_struct, flow);
+ ret = ndpi_search_tlsv3_direction1(ndpi_struct, flow);
if(ret == 1) {
NDPI_LOG_DBG2(ndpi_struct, "sslv3 server len match\n");
- ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
+ tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
return;
} else if(ret == 2) {
NDPI_LOG_DBG2(ndpi_struct,
"sslv3 server len match with split packet -> check some more packets for SSL patterns\n");
- ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
- if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) {
+ tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow);
+ if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
flow->l4.tcp.ssl_stage = 3;
}
return;
@@ -1281,16 +1189,18 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc
}
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+
return;
}
+/* **************************************** */
-void init_ssl_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
-{
- ndpi_set_bitmask_protocol_detection("SSL", ndpi_struct, detection_bitmask, *id,
- NDPI_PROTOCOL_SSL,
- ndpi_search_ssl_tcp,
- NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_WITH_PAYLOAD,
+void init_tls_dissector(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) {
+ ndpi_set_bitmask_protocol_detection("TLS", ndpi_struct, detection_bitmask, *id,
+ NDPI_PROTOCOL_TLS,
+ ndpi_search_tls_tcp_udp,
+ NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD,
SAVE_DETECTION_BITMASK_AS_UNKNOWN,
ADD_TO_DETECTION_BITMASK);
diff --git a/src/lib/protocols/tor.c b/src/lib/protocols/tor.c
index f1c6f586a..3b2dd06c4 100644
--- a/src/lib/protocols/tor.c
+++ b/src/lib/protocols/tor.c
@@ -18,12 +18,12 @@ static void ndpi_int_tor_add_connection(struct ndpi_detection_module_struct
}
-int ndpi_is_ssl_tor(struct ndpi_detection_module_struct *ndpi_struct,
+int ndpi_is_tls_tor(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow, char *certificate) {
int prev_num = 0, numbers_found = 0, num_found = 0, i, len, num_impossible = 0;
char dummy[48], *dot, *name;
-
- if(certificate == NULL)
+
+ if((certificate == NULL) || (certificate[0] == '\0'))
return(0);
else
len = strlen(certificate);
@@ -96,11 +96,13 @@ int ndpi_is_ssl_tor(struct ndpi_detection_module_struct *ndpi_struct,
void ndpi_search_tor(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;
- u_int16_t dport = 0, sport = 0;
NDPI_LOG_DBG(ndpi_struct, "search for TOR\n");
- if(packet->tcp != NULL) {
+ if((packet->tcp != NULL)
+ && (!packet->ssl_certificate_detected)) {
+ u_int16_t dport, sport;
+
sport = ntohs(packet->tcp->source), dport = ntohs(packet->tcp->dest);
NDPI_LOG_DBG2(ndpi_struct, "calculating TOR over tcp\n");
diff --git a/src/lib/protocols/yahoo.c b/src/lib/protocols/yahoo.c
index 3be953939..972466dc8 100644
--- a/src/lib/protocols/yahoo.c
+++ b/src/lib/protocols/yahoo.c
@@ -367,7 +367,7 @@ void ndpi_search_yahoo(struct ndpi_detection_module_struct *ndpi_struct, struct
if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN
|| packet->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP
- || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) {
+ || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) {
/* search over TCP */
ndpi_search_yahoo_tcp(ndpi_struct, flow);
}