From 673b6e73451cce242aa612c06e80b5865b243ed6 Mon Sep 17 00:00:00 2001 From: Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:52:31 +0100 Subject: [PATCH] HTTP: faster processing of asymmetric flows (#2198) --- src/include/ndpi_typedefs.h | 1 + src/lib/protocols/http.c | 16 ++++++++++++++-- .../default/result/http_asymmetric.pcapng.out | 6 +++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 718fec8348f..e7338b0fc9c 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -798,6 +798,7 @@ struct ndpi_flow_tcp_struct { /* NDPI_PROTOCOL_HTTP */ u_int32_t http_stage:3; + u_int32_t http_asymmetric_stage:2; /* NDPI_PROTOCOL_GNUTELLA */ u_int32_t gnutella_stage:2; // 0 - 2 diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index 68ba42561fc..2d894f345cd 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -1411,6 +1411,8 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct requests. The easiest (but costly) idea is to reset the state and process it (i.e. we keep the metadata of the last request that we have processed) */ + if(flow->l4.tcp.http_asymmetric_stage < 2) + flow->l4.tcp.http_asymmetric_stage++; reset(ndpi_struct, flow); process_request(ndpi_struct, flow, filename_start); return; @@ -1437,6 +1439,8 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct NDPI_LOG_DBG2(ndpi_struct, "Another piece of response\n"); if(is_response(ndpi_struct, flow)) { /* See the comment above about how we handle consecutive requests/responses */ + if(flow->l4.tcp.http_asymmetric_stage < 2) + flow->l4.tcp.http_asymmetric_stage++; reset(ndpi_struct, flow); process_response(ndpi_struct, flow); return; @@ -1467,8 +1471,16 @@ static void ndpi_search_http_tcp(struct ndpi_detection_module_struct *ndpi_struc NDPI_LOG_DBG(ndpi_struct, "search HTTP\n"); ndpi_check_http_tcp(ndpi_struct, flow); - if(flow->host_server_name[0] != '\0'&& - flow->http.response_status_code != 0) { + if((flow->host_server_name[0] != '\0'&& + flow->http.response_status_code != 0) || + /* We have found 3 consecutive requests (without the reply) or 3 + consecutive replies (without the request). If the traffic is really + asymmetric, stop here, because we will never find the metadata from + both the request and the reply. We wait for 3 events (instead of 2) + to avoid false positives triggered by missing/dropped packets */ + (flow->l4.tcp.http_asymmetric_stage == 2 && + (flow->packet_direction_complete_counter[0] == 0 || + flow->packet_direction_complete_counter[1] == 0))) { flow->extra_packets_func = NULL; /* We're good now */ if(flow->initial_binary_bytes_len) ndpi_analyze_content_signature(ndpi_struct, flow); diff --git a/tests/cfgs/default/result/http_asymmetric.pcapng.out b/tests/cfgs/default/result/http_asymmetric.pcapng.out index 50c52b91859..d65e7683a5a 100644 --- a/tests/cfgs/default/result/http_asymmetric.pcapng.out +++ b/tests/cfgs/default/result/http_asymmetric.pcapng.out @@ -1,6 +1,6 @@ -Guessed flow protos: 1 +Guessed flow protos: 0 -DPI Packets (TCP): 21 (10.50 pkts/flow) +DPI Packets (TCP): 18 (9.00 pkts/flow) Confidence DPI : 2 (flows) Num dissector calls: 26 (13.00 diss/flow) LRU cache ookla: 0/0/0 (insert/search/found) @@ -26,4 +26,4 @@ Patricia protocols IPv6: 0/0 (search/found) HTTP 23 9961 2 1 TCP 192.168.1.146:80 -> 192.168.1.103:1044 [proto: 7/HTTP][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 11][cat: Web/5][13 pkts/8357 bytes -> 0 pkts/0 bytes][Goodput ratio: 91/0][5.11 sec][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 464/0 5000/0 1435/0][Pkt Len c2s/s2c min/avg/max/stddev: 60/0 643/0 1514/0 626/0][StatusCode: 404][Content-Type: text/html][Server: Apache/2.4.41 (Ubuntu)][Risk: ** HTTP Susp User-Agent **** Error Code **** Unidirectional Traffic **][Risk Score: 120][Risk Info: No client to server traffic / HTTP Error Code 404 / Empty or missing User-Agent][PLAIN TEXT (HTTP/1.1 200 OK)][Plen Bins: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,57,0,0] - 2 TCP 192.168.0.1:1044 -> 10.10.10.1:80 [proto: 7/HTTP][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 10][cat: Web/5][10 pkts/1604 bytes -> 0 pkts/0 bytes][Goodput ratio: 66/0][5.11 sec][Hostname/SNI: proxy.wiresharkfest.acropolis.local][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 567/0 4951/0 1550/0][Pkt Len c2s/s2c min/avg/max/stddev: 54/0 160/0 418/0 160/0][URL: proxy.wiresharkfest.acropolis.local/favicon.ico][User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No server to client traffic][PLAIN TEXT (GET / HTTP/1.1)][Plen Bins: 0,0,0,0,0,0,0,0,0,0,66,33,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] + 2 TCP 192.168.0.1:1044 -> 10.10.10.1:80 [proto: 7/HTTP][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 7][cat: Web/5][10 pkts/1604 bytes -> 0 pkts/0 bytes][Goodput ratio: 66/0][5.11 sec][Hostname/SNI: proxy.wiresharkfest.acropolis.local][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 567/0 4951/0 1550/0][Pkt Len c2s/s2c min/avg/max/stddev: 54/0 160/0 418/0 160/0][URL: proxy.wiresharkfest.acropolis.local/favicon.ico][User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No server to client traffic][PLAIN TEXT (GET / HTTP/1.1)][Plen Bins: 0,0,0,0,0,0,0,0,0,0,66,33,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]