Skip to content

Commit 8a3aa62

Browse files
authored
USDT probes: add two new probes for detecting IP fragments (ntop#3134)
1 parent 9db9a7f commit 8a3aa62

File tree

7 files changed

+78
-10
lines changed

7 files changed

+78
-10
lines changed

.github/workflows/build.yml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,16 @@ jobs:
290290
# Verify both probes are present
291291
readelf -n example/ndpiReader | grep -q 'flow_classified'
292292
readelf -n example/ndpiReader | grep -q 'hostname_set'
293+
readelf -n example/ndpiReader | grep -q 'fragment_ipv4'
294+
readelf -n example/ndpiReader | grep -q 'fragment_ipv6'
293295
echo "All expected USDT probes found."
294296
- name: List probes via bpftrace
295297
run: |
296298
sudo bpftrace -l "usdt:./example/ndpiReader:ndpi:*" | tee /tmp/probe_list.txt
297299
grep -q 'flow_classified' /tmp/probe_list.txt
298300
grep -q 'hostname_set' /tmp/probe_list.txt
301+
grep -q 'fragment_ipv4' /tmp/probe_list.txt
302+
grep -q 'fragment_ipv6' /tmp/probe_list.txt
299303
echo "bpftrace can see all probes."
300304
- name: Test flow_classified probe with ndpiReader
301305
run: |
@@ -333,7 +337,7 @@ jobs:
333337
# Verify we actually traced some hostnames
334338
grep -q '@hostnames:' /tmp/bpf_hostname.txt
335339
echo "hostname_set probe: OK"
336-
- name: Test both probes simultaneously
340+
- name: Test both hostname_set and flow_classified simultaneously
337341
run: |
338342
sudo bpftrace -e '
339343
usdt:./example/ndpiReader:ndpi:hostname_set {
@@ -345,3 +349,29 @@ jobs:
345349
grep -q '@classified' /tmp/bpf_both.txt
346350
grep -q '@hostnames' /tmp/bpf_both.txt
347351
echo "Both probes fired successfully."
352+
- name: Test fragment_ipv4 probe with ndpiReader
353+
run: |
354+
READER=$(realpath example/ndpiReader)
355+
sudo ./bpftrace -I . --include ndpi_types.h \
356+
-e 'usdt:./example/ndpiReader:ndpi:fragment_ipv4 {
357+
$iph = (struct ndpi_iphdr *)arg0;
358+
@frags = count();
359+
@top[ntop($iph->saddr)] = count();
360+
}' -c './example/ndpiReader -q -i tests/pcap/ip_fragmented_garbage.pcap' 2>&1 | tee /tmp/frag_ipv4.txt
361+
# Verify we actually traced some hostnames
362+
grep -q '@frags:' /tmp/frag_ipv4.txt
363+
grep -q '@top' /tmp/frag_ipv4.txt
364+
echo "fragment_ipv4 probe: OK"
365+
- name: Test fragment_ipv6 probe with ndpiReader
366+
run: |
367+
READER=$(realpath example/ndpiReader)
368+
sudo ./bpftrace -I . --include ndpi_types.h \
369+
-e 'usdt:./example/ndpiReader:ndpi:fragment_ipv6 {
370+
$ip6h = (struct ndpi_ipv6hdr *)arg0;
371+
@frags = count();
372+
@top[ntop($ip6h->ip6_src.u6_addr.u6_addr8)] = count();
373+
}' -c './example/ndpiReader -q -i tests/pcap/dns_fragmented.pcap' 2>&1 | tee /tmp/frag_ipv6.txt
374+
# Verify we actually traced some hostnames
375+
grep -q '@frags:' /tmp/frag_ipv6.txt
376+
grep -q '@top' /tmp/frag_ipv6.txt
377+
echo "fragment_ipv6 probe: OK"

doc/usdt.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ Available Probes
6969
HTTP (Host header), QUIC, NetBIOS, DHCP, STUN, and others.
7070
The hostname is provided directly as a string for convenience;
7171
the flow pointer gives access to all other flow fields.
72+
* - ``fragment_ipv4``
73+
- | ``arg0``: pointer to IPv4 header (``struct ndpi_iphdr *``)
74+
- Fires when a (IPv4) packet processed by the library is fragmented
75+
at IP layer.
76+
* - ``fragment_ipv6``
77+
- | ``arg0``: pointer to IPv6 header (``struct ndpi_ipv6hdr *``)
78+
- Fires when a (IPv6) packet processed by the library is fragmented
79+
at IP layer.
7280

7381
bpftrace Notes
7482
--------------

example/reader_util.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ static struct ndpi_flow_info *get_ndpi_flow_info6(struct ndpi_workflow * workflo
10521052
const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr));
10531053
if(ipsize < sizeof(struct ndpi_ipv6hdr) + ip_len)
10541054
return(NULL);
1055-
if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &l4proto) != 0) {
1055+
if(ndpi_handle_ipv6_extension_headers(NULL, iph6, ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &l4proto) != 0) {
10561056
return(NULL);
10571057
}
10581058
iph.protocol = l4proto;
@@ -2564,7 +2564,7 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow,
25642564
const u_int8_t *l4ptr = (((const u_int8_t *) iph6) + sizeof(struct ndpi_ipv6hdr));
25652565
u_int16_t ipsize = header->caplen - ip_offset;
25662566

2567-
if(ndpi_handle_ipv6_extension_headers(ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &proto) != 0) {
2567+
if(ndpi_handle_ipv6_extension_headers(NULL, iph6, ipsize - sizeof(struct ndpi_ipv6hdr), &l4ptr, &ip_len, &proto) != 0) {
25682568
return(nproto);
25692569
}
25702570

src/include/ndpi_main.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ extern "C" {
8080
#define ndpi_match_strprefix(payload, payload_len, str) \
8181
ndpi_match_prefix((payload), (payload_len), (str), (sizeof(str)-1))
8282

83-
int ndpi_handle_ipv6_extension_headers(u_int16_t l3len,
83+
int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi_str,
84+
const struct ndpi_ipv6hdr *ip6h,
85+
u_int16_t l3len,
8486
const u_int8_t ** l4ptr, u_int16_t * l4len,
8587
u_int8_t * nxt_hdr);
8688

src/include/ndpi_private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,8 @@ void exclude_dissector(struct ndpi_detection_module_struct *ndpi_str, struct ndp
662662

663663
char *strptime(const char *s, const char *format, struct tm *tm);
664664

665-
u_int8_t iph_is_valid_and_not_fragmented(const struct ndpi_iphdr *iph, const u_int16_t ipsize);
665+
u_int8_t iph_is_valid_and_not_fragmented(struct ndpi_detection_module_struct *ndpi_str,
666+
const struct ndpi_iphdr *iph, const u_int16_t ipsize);
666667

667668
int current_pkt_from_client_to_server(const struct ndpi_detection_module_struct *ndpi_str, const struct ndpi_flow_struct *flow);
668669
int current_pkt_from_server_to_client(const struct ndpi_detection_module_struct *ndpi_str, const struct ndpi_flow_struct *flow);

src/lib/ndpi_main.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <netinet/ip.h>
2727
#endif
2828

29+
2930
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN
3031

3132
#include "ndpi_config.h"
@@ -7715,8 +7716,14 @@ static void ndpi_enabled_callbacks_init(struct ndpi_detection_module_struct *ndp
77157716
* nxt_hdr: first byte of the layer 4 packet
77167717
* returns 0 upon success and 1 upon failure
77177718
*/
7718-
int ndpi_handle_ipv6_extension_headers(u_int16_t l3len, const u_int8_t **l4ptr,
7719+
int ndpi_handle_ipv6_extension_headers(struct ndpi_detection_module_struct *ndpi_str,
7720+
const struct ndpi_ipv6hdr *ip6h,
7721+
u_int16_t l3len, const u_int8_t **l4ptr,
77197722
u_int16_t *l4len, u_int8_t *nxt_hdr) {
7723+
#ifndef HAVE_USDT
7724+
__ndpi_unused_param(ip6h);
7725+
#endif
7726+
77207727
while(l3len > 1 && (*nxt_hdr == 0 || *nxt_hdr == 43 || *nxt_hdr == 44 || *nxt_hdr == 60 || *nxt_hdr == 135 || *nxt_hdr == 59)) {
77217728
u_int16_t ehdr_len, frag_offset;
77227729

@@ -7736,6 +7743,16 @@ int ndpi_handle_ipv6_extension_headers(u_int16_t l3len, const u_int8_t **l4ptr,
77367743
}
77377744
l3len -= 5;
77387745

7746+
if(ndpi_str) {
7747+
uint16_t offlg = ntohs(*(u_int16_t *)((*l4ptr) + 2));
7748+
if((offlg & 0xfff8) != 0 || (offlg & 0x0001) != 0) {
7749+
NDPI_LOG_DBG(ndpi_str, "IP(v6) fragment\n");
7750+
7751+
NDPI_DTRACE1(fragment_ipv6,
7752+
ip6h /* IPV6 header */);
7753+
}
7754+
}
7755+
77397756
*nxt_hdr = (*l4ptr)[0];
77407757
frag_offset = ntohs(*(u_int16_t *)((*l4ptr) + 2)) >> 3;
77417758
// Handle ipv6 fragments as the ipv4 ones: keep the first fragment, drop the others
@@ -7777,12 +7794,22 @@ int ndpi_handle_ipv6_extension_headers(u_int16_t l3len, const u_int8_t **l4ptr,
77777794
/* ******************************************************************** */
77787795

77797796
/* Used by dns.c */
7780-
u_int8_t iph_is_valid_and_not_fragmented(const struct ndpi_iphdr *iph, const u_int16_t ipsize) {
7797+
u_int8_t iph_is_valid_and_not_fragmented(struct ndpi_detection_module_struct *ndpi_str,
7798+
const struct ndpi_iphdr *iph, const u_int16_t ipsize) {
77817799
/*
77827800
returned value:
77837801
0: fragmented
77847802
1: not fragmented
77857803
*/
7804+
7805+
if((ntohs(iph->frag_off) & 0x2000) ||
7806+
(ntohs(iph->frag_off) & 0x1fff)) {
7807+
NDPI_LOG_DBG(ndpi_str, "IP(v4) fragment\n");
7808+
7809+
NDPI_DTRACE1(fragment_ipv4,
7810+
iph /* IPV4 header */);
7811+
}
7812+
77867813
//#ifdef REQUIRE_FULL_PACKETS
77877814

77887815
if(iph->protocol == IPPROTO_UDP) {
@@ -7844,7 +7871,7 @@ static u_int8_t ndpi_detection_get_l4_internal(struct ndpi_detection_module_stru
78447871
}
78457872

78467873
/* 0: fragmented; 1: not fragmented */
7847-
if(iph != NULL && iph_is_valid_and_not_fragmented(iph, l3_len)) {
7874+
if(iph != NULL && iph_is_valid_and_not_fragmented(ndpi_str, iph, l3_len)) {
78487875
u_int16_t len = ndpi_min(ntohs(iph->tot_len), l3_len);
78497876
u_int16_t hlen = (iph->ihl * 4);
78507877

@@ -7863,7 +7890,7 @@ static u_int8_t ndpi_detection_get_l4_internal(struct ndpi_detection_module_stru
78637890
l4protocol = iph_v6->ip6_hdr.ip6_un1_nxt;
78647891

78657892
// we need to handle IPv6 extension headers if present
7866-
if(ndpi_handle_ipv6_extension_headers(l3_len - sizeof(struct ndpi_ipv6hdr), &l4ptr, &l4len, &l4protocol) != 0) {
7893+
if(ndpi_handle_ipv6_extension_headers(ndpi_str, iph_v6, l3_len - sizeof(struct ndpi_ipv6hdr), &l4ptr, &l4len, &l4protocol) != 0) {
78677894
return(1);
78687895
}
78697896

src/lib/protocols/dns.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ static void search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct
926926

927927
/* 0: fragmented; 1: not fragmented */
928928
if((flags & 0x20)
929-
|| (iph_is_valid_and_not_fragmented(packet->iph, packet->l3_packet_len) == 0)) {
929+
|| (iph_is_valid_and_not_fragmented(ndpi_struct, packet->iph, packet->l3_packet_len) == 0)) {
930930
ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED, NULL);
931931
}
932932
} else if(packet->iphv6 != NULL) {

0 commit comments

Comments
 (0)