From 4d11941d322b95728048446bb9d0a2d5fbb552f9 Mon Sep 17 00:00:00 2001
From: Ivan Nardi <12729895+IvanNardi@users.noreply.github.com>
Date: Thu, 30 Mar 2023 17:13:51 +0200
Subject: [PATCH] Ookla: rework detection (#1922)
The logic of the LRU cache has been changed: once we know an ip has
connected to an Ookla server, all the following (unknown) flows (for
a short time interval) from the same ip to the port 8080 are treated
as Ookla ones.
Most of the changes in this commit are about introducing the concept of
"aggressive detection". In some cases, to properly detect a
protocol we might use some statistical/behavior logic that, from one
side, let us to identify the protocol more often but, from the other
side, might lead to some false positives.
To allow the user/application to easily detect when such logic has been
triggered, the new confidence value `NDPI_CONFIDENCE_DPI_AGGRESSIVE` has been
added.
It is always possible to disable/configure this kind of logic via the
API.
Detection of Ookla flows using plain TLS over port 8080 is the first
example of aggressive detection in nDPI.
Tested with:
* Android 9.0 with app 4.8.3
* Ubuntu 20.04 with Firefox 110
* Win 10 with app 1.15 and 1.16
* Win 10 with Chrome 108, Edge 108 and Firefox 106
---
example/ndpiReader.c | 45 ++++++-
fuzz/fuzz_config.cpp | 5 +
src/include/ndpi_api.h | 5 +
src/include/ndpi_typedefs.h | 17 ++-
src/lib/ndpi_main.c | 56 ++++++++-
src/lib/protocols/http.c | 60 +--------
src/lib/protocols/ookla.c | 167 +++++++++++--------------
src/lib/protocols/tls.c | 25 +++-
tests/pcap/ookla.pcap | Bin 7485 -> 42424 bytes
tests/result/alexa-app.pcapng.out | 2 +-
tests/result/ookla.pcap.out | 46 ++++---
tests/result/skype.pcap.out | 2 +-
tests/result/skype_no_unknown.pcap.out | 2 +-
tests/result/synscan.pcap.out | 2 +-
14 files changed, 258 insertions(+), 176 deletions(-)
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 02cb7364bcd..452c0f5ae15 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -96,6 +96,7 @@ u_int8_t verbose = 0, enable_flow_stats = 0;
int nDPI_LogLevel = 0;
char *_debug_protocols = NULL;
char *_disabled_protocols = NULL;
+int aggressiveness[NDPI_MAX_SUPPORTED_PROTOCOLS];
static u_int8_t stats_flag = 0;
ndpi_init_prefs init_prefs = ndpi_no_prefs;
u_int8_t human_readeable_string_len = 5;
@@ -515,6 +516,7 @@ static void help(u_int long_help) {
" -z | Enable JA3+\n"
" -A | Dump internal statistics (LRU caches / Patricia trees / Ahocarasick automas / ...\n"
" -M | Memory allocation stats on data-path (only by the library). It works only on single-thread configuration\n"
+ " -Z proto:value | Set this value of aggressiveness for this protocol (0 to disable it). This flag can be used multiple times\n"
,
human_readeable_string_len,
min_pattern_len, max_pattern_len, max_num_packets_per_flow, max_packet_payload_dissection,
@@ -797,7 +799,7 @@ void printCSVHeader() {
*/
static void parseOptions(int argc, char **argv) {
int option_idx = 0;
- int opt;
+ int opt, i;
#ifndef USE_DPDK
char *__pcap_file = NULL;
int thread_id, do_capture = 0;
@@ -818,7 +820,10 @@ static void parseOptions(int argc, char **argv) {
}
#endif
- while((opt = getopt_long(argc, argv, "a:Ab:B:e:Ec:C:dDf:g:i:Ij:k:K:S:hHp:pP:l:r:s:tu:v:V:n:rp:x:w:zq0123:456:7:89:m:MT:U:",
+ for(i = 0; i < NDPI_MAX_SUPPORTED_PROTOCOLS; i++)
+ aggressiveness[i] = -1; /* Use the default value */
+
+ while((opt = getopt_long(argc, argv, "a:Ab:B:e:Ec:C:dDf:g:i:Ij:k:K:S:hHp:pP:l:r:s:tu:v:V:n:rp:x:w:zZ:q0123:456:7:89:m:MT:U:",
longopts, &option_idx)) != EOF) {
#ifdef DEBUG_TRACE
if(trace) fprintf(trace, " #### Handling option -%c [%s] #### \n", opt, optarg ? optarg : "");
@@ -950,6 +955,35 @@ static void parseOptions(int argc, char **argv) {
_disabled_protocols = ndpi_strdup(optarg);
break;
+ case 'Z': /* proto_name:aggr_value */
+ {
+ struct ndpi_detection_module_struct *module_tmp;
+ NDPI_PROTOCOL_BITMASK all;
+ char *saveptr, *tmp_str, *proto_str, *aggr_str;
+
+ /* Use a temporary module with all protocols enabled */
+ module_tmp = ndpi_init_detection_module(0);
+ if(!module_tmp)
+ break;
+ NDPI_BITMASK_SET_ALL(all);
+ ndpi_set_protocol_detection_bitmask2(module_tmp, &all);
+ ndpi_finalize_initialization(module_tmp);
+
+ tmp_str = ndpi_strdup(optarg);
+ if(tmp_str) {
+ proto_str = strtok_r(tmp_str, ":", &saveptr);
+ if(proto_str) {
+ aggr_str = strtok_r(NULL, ":", &saveptr);
+ if(aggr_str) {
+ aggressiveness[ndpi_get_protocol_id(module_tmp, proto_str)] = atoi(aggr_str);
+ }
+ }
+ }
+ ndpi_free(tmp_str);
+ ndpi_exit_detection_module(module_tmp);
+ break;
+ }
+
case 'h':
help(0);
break;
@@ -2413,6 +2447,7 @@ static void debug_printf(u_int32_t protocol, void *id_struct,
static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) {
NDPI_PROTOCOL_BITMASK enabled_bitmask;
struct ndpi_workflow_prefs prefs;
+ int i;
memset(&prefs, 0, sizeof(prefs));
prefs.decode_tunnels = decode_tunnels;
@@ -2472,6 +2507,12 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) {
NDPI_LRUCACHE_BITTORRENT, 32768);
/* Enable/disable LRU caches TTL here */
+ /* Set aggressiviness here */
+ for(i = 0; i < NDPI_MAX_SUPPORTED_PROTOCOLS; i++) {
+ if(aggressiveness[i] != -1)
+ ndpi_set_protocol_aggressiveness(ndpi_thread_info[thread_id].workflow->ndpi_struct, i, aggressiveness[i]);
+ }
+
ndpi_finalize_initialization(ndpi_thread_info[thread_id].workflow->ndpi_struct);
if(enable_doh_dot_detection)
diff --git a/fuzz/fuzz_config.cpp b/fuzz/fuzz_config.cpp
index de1bdd3e85d..2e0a27ff4c0 100644
--- a/fuzz/fuzz_config.cpp
+++ b/fuzz/fuzz_config.cpp
@@ -108,6 +108,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_set_opportunistic_tls(ndpi_info_mod, random_proto, random_value);
ndpi_get_opportunistic_tls(ndpi_info_mod, random_proto);
+ for(i = 0; i < NDPI_MAX_SUPPORTED_PROTOCOLS; i++) {
+ ndpi_set_protocol_aggressiveness(ndpi_info_mod, i, random_value);
+ ndpi_get_protocol_aggressiveness(ndpi_info_mod, i);
+ }
+
ndpi_finalize_initialization(ndpi_info_mod);
/* Random protocol configuration */
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h
index d1875b5d818..d3b02a4d57a 100644
--- a/src/include/ndpi_api.h
+++ b/src/include/ndpi_api.h
@@ -1031,6 +1031,11 @@ extern "C" {
int ndpi_get_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto);
+ int ndpi_set_protocol_aggressiveness(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int16_t proto, u_int32_t value);
+ u_int32_t ndpi_get_protocol_aggressiveness(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int16_t proto);
+
/**
* Find a protocol id associated with a string automata
*
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 6d560ef36fd..a5b1175bc4f 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -659,6 +659,14 @@ struct ndpi_lru_cache {
struct ndpi_lru_cache_entry *entries;
};
+
+/* Aggressiveness values */
+
+#define NDPI_AGGRESSIVENESS_DISABLED 0x00 /* For all protocols */
+
+/* Ookla */
+#define NDPI_AGGRESSIVENESS_OOKLA_TLS 0x01 /* Enable detection over TLS (using ookla cache) */
+
/* ************************************************** */
struct ndpi_flow_tcp_struct {
@@ -920,7 +928,8 @@ typedef enum {
NDPI_CONFIDENCE_DPI_CACHE, /* Classification results based on some LRU cache (i.e. correlation among sessions) */
NDPI_CONFIDENCE_DPI, /* Deep packet inspection */
NDPI_CONFIDENCE_MATCH_BY_IP, /* Classification obtained looking only at the IP addresses */
-
+ NDPI_CONFIDENCE_DPI_AGGRESSIVE, /* Aggressive DPI: it might be a false positive */
+
/*
IMPORTANT
@@ -1229,6 +1238,8 @@ struct ndpi_detection_module_struct {
int opportunistic_tls_pop_enabled;
int opportunistic_tls_ftp_enabled;
+ u_int32_t aggressiveness_ookla;
+
u_int16_t ndpi_to_user_proto_id[NDPI_MAX_NUM_CUSTOM_PROTOCOLS]; /* custom protocolId mapping */
ndpi_proto_defaults_t proto_defaults[NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS];
@@ -1563,6 +1574,10 @@ struct ndpi_flow_struct {
/* NDPI_PROTOCOL_Z3950 */
u_int8_t z3950_stage : 2; // 0-3
+ /* NDPI_PROTOCOL_OOKLA */
+ u_int8_t ookla_stage : 1;
+
+
/* NDPI_PROTOCOL_OPENVPN */
u_int8_t ovpn_session_id[8];
u_int8_t ovpn_counter;
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index f4266d87d03..dc5834549bc 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -198,6 +198,10 @@ extern void ndpi_unset_risk(struct ndpi_detection_module_struct *ndpi_str,
struct ndpi_flow_struct *flow, ndpi_risk_enum r);
extern u_int32_t make_mining_key(struct ndpi_flow_struct *flow);
extern int stun_search_into_zoom_cache(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow);
+extern void ookla_add_to_cache(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
+extern int ookla_search_into_cache(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
/* Forward */
static int addDefaultPort(struct ndpi_detection_module_struct *ndpi_str,
@@ -2932,7 +2936,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
ndpi_str->msteams_cache_num_entries = 1024;
ndpi_str->stun_zoom_cache_num_entries = 1024;
- ndpi_str->ookla_cache_ttl = 0;
+ ndpi_str->ookla_cache_ttl = 120; /* sec */
ndpi_str->bittorrent_cache_ttl = 0;
ndpi_str->zoom_cache_ttl = 0;
ndpi_str->stun_cache_ttl = 0;
@@ -2946,6 +2950,8 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
ndpi_str->opportunistic_tls_pop_enabled = 1;
ndpi_str->opportunistic_tls_ftp_enabled = 1;
+ ndpi_str->aggressiveness_ookla = NDPI_AGGRESSIVENESS_OOKLA_TLS;
+
for(i = 0; i < NUM_CUSTOM_CATEGORIES; i++)
ndpi_snprintf(ndpi_str->custom_category_labels[i], CUSTOM_CATEGORY_LABEL_LEN, "User custom category %u",
(unsigned int) (i + 1));
@@ -6254,6 +6260,13 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st
ret.app_protocol = flow->detected_protocol_stack[0];
}
+ /* Does it looks like Ookla? */
+ if(ret.app_protocol == NDPI_PROTOCOL_UNKNOWN &&
+ ntohs(flow->s_port) == 8080 && ookla_search_into_cache(ndpi_str, flow)) {
+ ndpi_set_detected_protocol(ndpi_str, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI_PARTIAL_CACHE);
+ ret.app_protocol = flow->detected_protocol_stack[0];
+ }
+
/* Classification by-port is the last resort */
if(enable_guess && ret.app_protocol == NDPI_PROTOCOL_UNKNOWN) {
@@ -8052,6 +8065,9 @@ const char *ndpi_confidence_get_name(ndpi_confidence_t confidence)
case NDPI_CONFIDENCE_MATCH_BY_IP:
return "Match by IP";
+ case NDPI_CONFIDENCE_DPI_AGGRESSIVE:
+ return "DPI (aggressive)";
+
default:
return NULL;
}
@@ -8572,6 +8588,11 @@ int ndpi_match_hostname_protocol(struct ndpi_detection_module_struct *ndpi_struc
ndpi_set_detected_protocol(ndpi_struct, flow, subproto, master_protocol, NDPI_CONFIDENCE_DPI);
if(!category_depends_on_master(master_protocol))
ndpi_int_change_category(ndpi_struct, flow, ret_match.protocol_category);
+
+ if(subproto == NDPI_PROTOCOL_OOKLA) {
+ ookla_add_to_cache(ndpi_struct, flow);
+ }
+
return(1);
} else
return(0);
@@ -9643,3 +9664,36 @@ int ndpi_get_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct,
return -1;
}
}
+
+/* ******************************************************************** */
+
+int ndpi_set_protocol_aggressiveness(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int16_t proto, u_int32_t value)
+{
+ if(!ndpi_struct)
+ return -1;
+
+ switch(proto) {
+ case NDPI_PROTOCOL_OOKLA:
+ ndpi_struct->aggressiveness_ookla = value;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/* ******************************************************************** */
+
+u_int32_t ndpi_get_protocol_aggressiveness(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int16_t proto)
+{
+ if(!ndpi_struct)
+ return -1;
+
+ switch(proto) {
+ case NDPI_PROTOCOL_OOKLA:
+ return ndpi_struct->aggressiveness_ookla;
+ default:
+ return -1;
+ }
+}
diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c
index e0f56c4e804..4f139b8d318 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -46,6 +46,9 @@ static const char* binary_file_ext[] = {
NULL
};
+extern void ookla_add_to_cache(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
+
static void ndpi_search_http_tcp(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow);
@@ -436,6 +439,7 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp
|| (strstr(flow->http.url, ":8080/upload?n=0.") != NULL))) {
/* This looks like Ookla speedtest */
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, master_protocol, NDPI_CONFIDENCE_DPI);
+ ookla_add_to_cache(ndpi_struct, flow);
}
}
@@ -1217,30 +1221,6 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
return;
}
- if((packet->payload_packet_len == 3) && memcmp(packet->payload, "HI\n", 3) == 0) {
- /* This looks like Ookla: we don't give up with HTTP yet */
- flow->l4.tcp.http_stage = 1;
- return;
- }
-
- if((packet->payload_packet_len == 40) && (flow->l4.tcp.http_stage == 0)) {
- /*
- -> QR O06L0072-6L91-4O43-857J-K8OO172L6L51
- <- QNUUX 2.5 2017-08-15.1314.4jn12m5
- -> MXFWUXJM 31625365
- */
-
- if((packet->payload[2] == ' ')
- && (packet->payload[11] == '-')
- && (packet->payload[16] == '-')
- && (packet->payload[21] == '-')
- && (packet->payload[26] == '-')
- && (packet->payload[39] == 0x0A)
- )
- flow->l4.tcp.http_stage = 1;
- return;
- }
-
if((packet->payload_packet_len == 23) && (memcmp(packet->payload, "", 23) == 0)) {
/*
@@ -1251,25 +1231,7 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
*/
ookla_found:
ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_CATEGORY_WEB);
-
- if(ndpi_struct->ookla_cache != NULL) {
- if(packet->iph != NULL) {
- if(packet->tcp->source == htons(8080))
- ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->saddr, 1 /* dummy */, ndpi_get_current_time(flow));
- else
- ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->daddr, 1 /* dummy */, ndpi_get_current_time(flow));
- } else if(packet->iphv6 != NULL) {
- u_int32_t h;
-
- if(packet->tcp->source == htons(8080))
- h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_src, sizeof(packet->iphv6->ip6_src));
- else
- h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_dst, sizeof(packet->iphv6->ip6_dst));
-
- ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, h, 1 /* dummy */, ndpi_get_current_time(flow));
- }
- }
-
+ ookla_add_to_cache(ndpi_struct, flow);
return;
}
@@ -1389,18 +1351,6 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct
} else if((flow->l4.tcp.http_stage == 1) || (flow->l4.tcp.http_stage == 2)) {
NDPI_LOG_DBG2(ndpi_struct, "HTTP stage %u: \n", flow->l4.tcp.http_stage);
- if((packet->payload_packet_len == 34) && (flow->l4.tcp.http_stage == 1)) {
- if((packet->payload[5] == ' ') && (packet->payload[9] == ' ')) {
- goto ookla_found;
- }
- }
-
- if((packet->payload_packet_len > 6) && memcmp(packet->payload, "HELLO ", 6) == 0) {
- /* This looks like Ookla */
- goto ookla_found;
- } else
- NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_OOKLA);
-
/**
At first check, if this is for sure a response packet
(in another direction. If not, if HTTP is detected do nothing now and return,
diff --git a/src/lib/protocols/ookla.c b/src/lib/protocols/ookla.c
index 0da42212cca..d7764e630fa 100644
--- a/src/lib/protocols/ookla.c
+++ b/src/lib/protocols/ookla.c
@@ -23,111 +23,92 @@
#include "ndpi_api.h"
+/* #define DEBUG_OOKLA_LRU */
+
const u_int16_t ookla_port = 8080;
/* ************************************************************* */
-static void ndpi_search_ookla(struct ndpi_detection_module_struct* ndpi_struct, struct ndpi_flow_struct* flow) {
- struct ndpi_packet_struct* packet = &ndpi_struct->packet;
- u_int32_t addr = 0;
- u_int16_t sport, dport;
-
- NDPI_LOG_DBG(ndpi_struct, "Ookla detection\n");
-
- if(packet->tcp)
- sport = ntohs(packet->tcp->source), dport = htons(packet->tcp->dest);
+static u_int32_t get_ookla_key(struct ndpi_flow_struct *flow)
+{
+ if(flow->is_ipv6)
+ return ndpi_quick_hash(flow->c_address.v6, 16);
else
- sport = ntohs(packet->udp->source), dport = htons(packet->udp->dest);
+ return ntohl(flow->c_address.v4);
+}
- if((sport != ookla_port) && (dport != ookla_port)) {
-#ifdef OOKLA_DEBUG
- printf("=>>>>>>>> [OOKLA IPv6] Skipping flow [%u -> %u]\n", sport, dport);
-#endif
- goto ookla_exclude;
- }
-
- if(packet->iphv6 != NULL) {
- if((dport == ookla_port) && (packet->payload_packet_len >= 3)) {
- u_int32_t h;
-
- if((packet->payload_packet_len == 3)
- && (packet->payload[0] == 0x48) /* HI\n */
- && (packet->payload[1] == 0x49)
- && (packet->payload[2] == 0x0A)) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
-
- if(ndpi_struct->ookla_cache != NULL) {
- /* In order to avoid creating an IPv6 LRU we hash the IPv6 address */
- h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_dst, sizeof(packet->iphv6->ip6_dst));
-
-#ifdef OOKLA_DEBUG
- printf("=>>>>>>>> [OOKLA IPv6] Adding %u\n", h);
-#endif
- ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, h, 1 /* dummy */, ndpi_get_current_time(flow));
- }
- return;
- } else {
- if(sport == ookla_port)
- h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_src, sizeof(packet->iphv6->ip6_src));
- else
- h = ndpi_quick_hash((unsigned char *)&packet->iphv6->ip6_dst, sizeof(packet->iphv6->ip6_dst));
-
- if(ndpi_struct->ookla_cache != NULL) {
- u_int16_t dummy;
-
-#ifdef OOKLA_DEBUG
- printf("=>>>>>>>> [OOKLA IPv6] Searching %u\n", h);
-#endif
-
- if(ndpi_lru_find_cache(ndpi_struct->ookla_cache, h, &dummy, 0 /* Don't remove it as it can be used for other connections */,
- ndpi_get_current_time(flow))) {
- NDPI_LOG_INFO(ndpi_struct, "found ookla tcp connection\n");
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI_CACHE);
-#ifdef OOKLA_DEBUG
- printf("=>>>>> Found %u\n", h);
-#endif
- return;
- } else {
-#ifdef OOKLA_DEBUG
- printf("=>>>>> NOT Found %u\n", h);
-#endif
- }
- }
- }
- } else {
+/* ************************************************************* */
- goto ookla_exclude;
- }
- } else {
- if(sport == ookla_port)
- addr = packet->iph->saddr;
- else
- addr = packet->iph->daddr;
-
-#ifdef OOKLA_DEBUG
- printf("=>>>>>>>> [OOKLA IPv4] Searching %u\n", addr);
-#endif
-
- if(ndpi_struct->ookla_cache != NULL) {
- 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_get_current_time(flow))) {
- NDPI_LOG_INFO(ndpi_struct, "found ookla tcp connection\n");
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI_CACHE);
-#ifdef OOKLA_DEBUG
- printf("=>>>>> Found %u\n", addr);
+int ookla_search_into_cache(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ u_int32_t key;
+ u_int16_t dummy;
+
+ if(ndpi_struct->ookla_cache) {
+ key = get_ookla_key(flow);
+#ifdef DEBUG_OOKLA_LRU
+ printf("[LRU OOKLA] Search %u\n", key);
#endif
- return;
- } else {
-#ifdef OOKLA_DEBUG
- printf("=>>>>> NOT Found %u\n", addr);
+
+ if(ndpi_lru_find_cache(ndpi_struct->ookla_cache, key,
+ &dummy, 0 /* Don't remove it as it can be used for other connections */,
+ ndpi_get_current_time(flow))) {
+#ifdef DEBUG_OOKLA_LRU
+ printf("[LRU OOKLA] Found\n");
#endif
- }
+ return 1;
}
}
+ return 0;
+}
+
+/* ************************************************************* */
+
+void ookla_add_to_cache(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ u_int32_t key;
+
+ if(ndpi_struct->ookla_cache) {
+ key = get_ookla_key(flow);
+#ifdef DEBUG_OOKLA_LRU
+ printf("[LRU OOKLA] ADDING %u\n", key);
+#endif
+ ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, key, 1 /* dummy */,
+ ndpi_get_current_time(flow));
+ }
+
+}
+
+/* ************************************************************* */
+
+void ndpi_search_ookla(struct ndpi_detection_module_struct* ndpi_struct, struct ndpi_flow_struct* flow) {
+ struct ndpi_packet_struct *packet = &ndpi_struct->packet;
+
+ NDPI_LOG_DBG(ndpi_struct, "Ookla detection\n");
+
+ if(ntohs(flow->s_port) != ookla_port && ntohs(flow->c_port) != ookla_port) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ if(flow->packet_counter == 1 &&
+ packet->payload_packet_len >= NDPI_STATICSTRING_LEN("HI") &&
+ memcmp(packet->payload, "HI", NDPI_STATICSTRING_LEN("HI")) == 0) {
+ flow->ookla_stage = 1;
+ return;
+ }
+ if(flow->packet_counter == 2 &&
+ flow->ookla_stage == 1 &&
+ packet->payload_packet_len >= NDPI_STATICSTRING_LEN("HELLO") &&
+ memcmp(packet->payload, "HELLO", NDPI_STATICSTRING_LEN("HELLO")) == 0) {
+ NDPI_LOG_INFO(ndpi_struct, "found ookla (Hi + Hello)\n");
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
+ ookla_add_to_cache(ndpi_struct, flow);
+ return;
+ }
- ookla_exclude:
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
}
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 8e3fbedb823..58b19d0d5f2 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -33,6 +33,8 @@ extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_st
extern int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
const u_int8_t *ua_ptr, u_int16_t ua_ptr_len);
+extern int ookla_search_into_cache(struct ndpi_detection_module_struct* ndpi_struct,
+ struct ndpi_flow_struct* flow);
/* QUIC/GQUIC stuff */
extern int quic_len(const uint8_t *buf, uint64_t *value);
extern int quic_len_buffer_still_required(uint8_t value);
@@ -1153,8 +1155,27 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef DEBUG_TLS_BLOCKS
printf("*** [TLS Block] No more blocks\n");
#endif
- flow->extra_packets_func = NULL;
- return(0); /* That's all */
+ /* An ookla flow? */
+ if((ndpi_struct->aggressiveness_ookla & NDPI_AGGRESSIVENESS_OOKLA_TLS) && /* Feature enabled */
+ (!something_went_wrong &&
+ flow->tls_quic.certificate_processed == 1 &&
+ flow->protos.tls_quic.hello_processed == 1) && /* TLS handshake found without errors */
+ flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS && /* No IMAPS/FTPS/... */
+ flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN && /* No sub-classification */
+ ntohs(flow->s_port) == 8080 && /* Ookla port */
+ ookla_search_into_cache(ndpi_struct, flow)) {
+ NDPI_LOG_INFO(ndpi_struct, "found ookla (cache over TLS)\n");
+ /* Even if a LRU cache is involved, NDPI_CONFIDENCE_DPI_AGGRESSIVE seems more
+ suited than NDPI_CONFIDENCE_DPI_CACHE */
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_TLS, NDPI_CONFIDENCE_DPI_AGGRESSIVE);
+ /* TLS over port 8080 usually triggers that risk; clear it */
+ ndpi_unset_risk(ndpi_struct, flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT);
+ flow->extra_packets_func = NULL;
+ return(0); /* That's all */
+ } else {
+ flow->extra_packets_func = NULL;
+ return(0); /* That's all */
+ }
} else
return(1);
}
diff --git a/tests/pcap/ookla.pcap b/tests/pcap/ookla.pcap
index 80123e85605ede23f4c8ca124685560a14d7e106..ac57c6d17656676169d23216f858b1d773ec80a3 100644
GIT binary patch
literal 42424
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
delta 837
zcmYL{T}V@59LC?RRj1k)O{<-gXxni+`#NWo1!+WRn{)!j2^PVqNbq(y-gJ{!3K4|8
zu!~5T2z4VgI?g^si?*(Wj0lQAi!=-`%ImKBe+=^O`JLbMyzh?Z#j1O`yW>;+*{oZ5
z#Q#5!a6wr3_3diu?ja$ofe{76y5<$KBUqqt=QxB5ZK`}6%o0%By~5cIR$P?qF`tm%
zbxqa}TLkpmKH+#nAvdLakf>c~<@Wd#fJ#_(7F!?jLM`eSvZQIw)X|4b26P~Jm@Q_uRa(gXj99K8CRoDR0gX}ycI$;=*Hwn=#pVHA{6Ih1IT#m-?;j+mg}(vQw8
z0e=I)L|m2mSRa8Wmpt$alA3%S>t(|RfR!_Gu6P#!OvH=ybf9N1>mh^ncL+*`O;7VL
z_wo8~gV*Q!_Om{gVEx!d0Jy%9;PreJ0A8p!$(6rn6|6Lm>xO{($rS6WxdW`1Q>>@f
z0O0)tX+EKh04tMeuB1;N6!Jrw2e+0XpnfaE`rrzHHyOTvc?dpUyv%u%*LOYxK>fMN
c`i(Em&)c+kef 46.44.253.187:80 [proto: 7.191/HTTP.Ookla][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 12][cat: Network/14][12 pkts/2238 bytes <-> 8 pkts/2082 bytes][Goodput ratio: 64/74][5.33 sec][bytes ratio: 0.036 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/4 528/47 5005/84 1493/28][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 186/260 430/523 168/194][Risk: ** HTTP Susp User-Agent **** HTTP Obsolete Server **][Risk Score: 150][Risk Info: Obsolete Apache server 2.2.22 / Empty or missing User-Agent][PLAIN TEXT (GET /crossdomain.xml HTTP/1.1)][Plen Bins: 0,0,0,0,0,0,0,0,0,0,12,75,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- 2 TCP 192.168.1.7:51215 <-> 46.44.253.187:8080 [proto: 191/Ookla][IP: 0/Unknown][ClearText][Confidence: DPI (cache)][DPI packets: 4][cat: Network/14][19 pkts/1421 bytes <-> 11 pkts/920 bytes][Goodput ratio: 11/20][0.80 sec][bytes ratio: 0.214 (Upload)][IAT c2s/s2c min/avg/max/stddev: 26/0 44/75 103/137 23/41][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 75/84 85/100 9/8][PLAIN TEXT ( 6HELLO 2.4 2016)][Plen Bins: 94,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.128 2
+
+
+ 1 TCP 192.168.1.128:35830 <-> 89.96.108.170:8080 [proto: 91.191/TLS.Ookla][IP: 0/Unknown][Encrypted][Confidence: DPI (aggressive)][DPI packets: 6][cat: Web/5][21 pkts/21216 bytes <-> 8 pkts/1950 bytes][Goodput ratio: 93/72][0.32 sec][Hostname/SNI: spd-pub-mi-01-01.fastwebnet.it][(Advertised) ALPNs: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2][bytes ratio: 0.832 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 17/61 274/280 62/109][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 1010/244 1514/387 612/138][TLSv1.3][JA3C: c279b0189edb9269da7bc43dea5e0c36][JA3S: fcb2d4d0991292272fcb1e464eedfd43][Firefox][Cipher: TLS_AES_128_GCM_SHA256][Plen Bins: 0,0,4,0,0,0,0,4,9,0,9,0,0,0,0,0,4,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0]
+ 2 TCP 192.168.1.128:48854 <-> 104.16.209.12:443 [proto: 91.191/TLS.Ookla][IP: 220/Cloudflare][Encrypted][Confidence: DPI][DPI packets: 6][cat: Network/14][8 pkts/1620 bytes <-> 6 pkts/3818 bytes][Goodput ratio: 67/89][0.06 sec][Hostname/SNI: www.speedtest.net][(Advertised) ALPNs: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2][bytes ratio: -0.404 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 7/5 18/15 7/6][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 202/636 583/1514 181/646][TLSv1.3][JA3C: 579ccef312d18482fc42e2b822ca2430][JA3S: eb1d94daa7e0344597e756a1fb6e7054][Firefox][Cipher: TLS_AES_128_GCM_SHA256][PLAIN TEXT (@oTAgOeedtest.net)][Plen Bins: 0,0,14,0,0,14,0,0,0,0,14,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0]
+ 3 TCP 192.168.1.7:51207 <-> 46.44.253.187:80 [proto: 7.191/HTTP.Ookla][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 12][cat: Network/14][12 pkts/2238 bytes <-> 8 pkts/2082 bytes][Goodput ratio: 64/74][5.33 sec][bytes ratio: 0.036 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/4 528/47 5005/84 1493/28][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 186/260 430/523 168/194][Risk: ** HTTP Susp User-Agent **** HTTP Obsolete Server **][Risk Score: 150][Risk Info: Obsolete Apache server 2.2.22 / Empty or missing User-Agent][PLAIN TEXT (GET /crossdomain.xml HTTP/1.1)][Plen Bins: 0,0,0,0,0,0,0,0,0,0,12,75,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+ 4 TCP 192.168.1.192:51156 <-> 89.96.108.170:8080 [proto: 191/Ookla][IP: 0/Unknown][ClearText][Confidence: DPI (partial cache)][DPI packets: 10][cat: Network/14][6 pkts/591 bytes <-> 4 pkts/1784 bytes][Goodput ratio: 32/85][0.05 sec][bytes ratio: -0.502 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 9/10 15/20 6/8][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 98/446 143/1514 31/617][PLAIN TEXT (gKRZvA)][Plen Bins: 0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0]
+ 5 TCP 192.168.1.7:51215 <-> 46.44.253.187:8080 [proto: 191/Ookla][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 6][cat: Network/14][19 pkts/1421 bytes <-> 11 pkts/920 bytes][Goodput ratio: 11/20][0.80 sec][bytes ratio: 0.214 (Upload)][IAT c2s/s2c min/avg/max/stddev: 26/0 44/75 103/137 23/41][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 75/84 85/100 9/8][PLAIN TEXT ( 6HELLO 2.4 2016)][Plen Bins: 94,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+ 6 TCP 192.168.1.192:37790 <-> 185.157.229.246:8080 [proto: 191/Ookla][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 6][cat: Network/14][6 pkts/454 bytes <-> 4 pkts/317 bytes][Goodput ratio: 11/14][0.06 sec][bytes ratio: 0.178 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 12/5 46/9 17/4][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 76/79 106/108 14/17][PLAIN TEXT (HELLO 2.9 )][Plen Bins: 50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
diff --git a/tests/result/skype.pcap.out b/tests/result/skype.pcap.out
index 5091e3a4e5f..d26ba706f76 100644
--- a/tests/result/skype.pcap.out
+++ b/tests/result/skype.pcap.out
@@ -7,7 +7,7 @@ Confidence Unknown : 59 (flows)
Confidence Match by port : 27 (flows)
Confidence DPI (partial) : 1 (flows)
Confidence DPI : 206 (flows)
-Num dissector calls: 26899 (91.81 diss/flow)
+Num dissector calls: 26897 (91.80 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/261/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
diff --git a/tests/result/skype_no_unknown.pcap.out b/tests/result/skype_no_unknown.pcap.out
index be90096f61e..328c50280ed 100644
--- a/tests/result/skype_no_unknown.pcap.out
+++ b/tests/result/skype_no_unknown.pcap.out
@@ -6,7 +6,7 @@ DPI Packets (other): 5 (1.00 pkts/flow)
Confidence Unknown : 44 (flows)
Confidence Match by port : 22 (flows)
Confidence DPI : 201 (flows)
-Num dissector calls: 22405 (83.91 diss/flow)
+Num dissector calls: 22404 (83.91 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/198/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
diff --git a/tests/result/synscan.pcap.out b/tests/result/synscan.pcap.out
index 9932b97b2e1..3bdf713b463 100644
--- a/tests/result/synscan.pcap.out
+++ b/tests/result/synscan.pcap.out
@@ -4,7 +4,7 @@ DPI Packets (TCP): 2011 (1.01 pkts/flow)
Confidence Unknown : 1862 (flows)
Confidence Match by port : 132 (flows)
Num dissector calls: 0 (0.00 diss/flow)
-LRU cache ookla: 0/0/0 (insert/search/found)
+LRU cache ookla: 0/2/0 (insert/search/found)
LRU cache bittorrent: 0/5976/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
LRU cache stun: 0/0/0 (insert/search/found)