Skip to content

Commit 433aeed

Browse files
committed
Improve ICMPv4 and ICMPv6 handling in XDP and TC as well
1 parent c02a0c0 commit 433aeed

6 files changed

+89
-53
lines changed

counter.c

+74-37
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define AF_INET 2
4141
#define AF_INET6 10
4242
#define TASK_COMM_LEN 16
43+
#define IPPROTO_ICMPV6 58
4344

4445
#define OK 1
4546
#define NOK 0
@@ -112,9 +113,9 @@ static inline int process_ip4(struct iphdr *ip4, void *data_end, statkey *key) {
112113

113114
key->src_port = bpf_ntohs(tcp->source);
114115
key->dst_port = bpf_ntohs(tcp->dest);
115-
}
116116

117-
break;
117+
break;
118+
}
118119
case IPPROTO_UDP: {
119120
struct udphdr *udp = (void *)ip4 + sizeof(*ip4);
120121

@@ -125,9 +126,24 @@ static inline int process_ip4(struct iphdr *ip4, void *data_end, statkey *key) {
125126

126127
key->src_port = bpf_ntohs(udp->source);
127128
key->dst_port = bpf_ntohs(udp->dest);
129+
130+
break;
128131
}
132+
case IPPROTO_ICMP: {
133+
struct icmphdr *icmp = (void *)ip4 + sizeof(*ip4);
129134

130-
break;
135+
// validate ICMP size
136+
if ((void *)icmp + sizeof(*icmp) > data_end) {
137+
return NOK;
138+
}
139+
140+
// store ICMP type in src port
141+
key->src_port = icmp->type;
142+
// store ICMP code in dst port
143+
key->dst_port = icmp->code;
144+
145+
break;
146+
}
131147
}
132148

133149
return OK;
@@ -167,9 +183,9 @@ static inline int process_ip6(struct ipv6hdr *ip6, void *data_end,
167183

168184
key->src_port = bpf_ntohs(tcp->source);
169185
key->dst_port = bpf_ntohs(tcp->dest);
170-
}
171186

172-
break;
187+
break;
188+
}
173189
case IPPROTO_UDP: {
174190
struct udphdr *udp = (void *)ip6 + sizeof(*ip6);
175191

@@ -180,17 +196,32 @@ static inline int process_ip6(struct ipv6hdr *ip6, void *data_end,
180196

181197
key->src_port = bpf_ntohs(udp->source);
182198
key->dst_port = bpf_ntohs(udp->dest);
199+
200+
break;
183201
}
202+
case IPPROTO_ICMPV6: {
203+
struct icmp6hdr *icmp = (void *)ip6 + sizeof(*ip6);
184204

185-
break;
205+
// validate ICMPv6 size
206+
if ((void *)icmp + sizeof(*icmp) > data_end) {
207+
return NOK;
208+
}
209+
210+
// store ICMP type in src port
211+
key->src_port = icmp->icmp6_type;
212+
// store ICMP code in dst port
213+
key->dst_port = icmp->icmp6_code;
214+
215+
break;
216+
}
186217
}
187218

188219
return OK;
189220
}
190221

191222
/**
192-
* Process the Ethernet header and extract relevant information to populate the
193-
* key.
223+
* Process the Ethernet header and extract relevant information to populate
224+
* the key.
194225
*
195226
* @param data pointer to the start of the Ethernet header
196227
* @param data_end pointer to the end of the packet data
@@ -217,19 +248,21 @@ static inline void process_eth(void *data, void *data_end, __u64 pkt_len) {
217248
case ETH_P_IP: {
218249
struct iphdr *ip4 = (void *)eth + sizeof(*eth);
219250

220-
if (process_ip4(ip4, data_end, &key) == NOK)
251+
if (process_ip4(ip4, data_end, &key) == NOK) {
221252
return;
222-
}
253+
}
223254

224-
break;
255+
break;
256+
}
225257
case ETH_P_IPV6: {
226258
struct ipv6hdr *ip6 = (void *)eth + sizeof(*eth);
227259

228-
if (process_ip6(ip6, data_end, &key) == NOK)
260+
if (process_ip6(ip6, data_end, &key) == NOK) {
229261
return;
230-
}
262+
}
231263

232-
break;
264+
break;
265+
}
233266
default:
234267
return;
235268
}
@@ -319,17 +352,17 @@ int tc_count_packets(struct __sk_buff *skb) {
319352
}
320353

321354
/**
322-
* Process TCP socket information and populate the key structure with extracted
323-
* data.
355+
* Process TCP socket information and populate the key structure with
356+
* extracted data.
324357
*
325358
* @param sk pointer to the socket structure
326359
* @param key pointer to the statkey structure to be populated
327360
* @param pid process ID associated with the socket
328361
*
329362
* This function reads the socket's address family and based on whether it is
330-
* IPv4 or IPv6, it extracts the source and destination IP addresses and ports.
331-
* It also sets the protocol to TCP and assigns the provided process ID to the
332-
* key.
363+
* IPv4 or IPv6, it extracts the source and destination IP addresses and
364+
* ports. It also sets the protocol to TCP and assigns the provided process ID
365+
* to the key.
333366
*
334367
* The function handles both IPv4 and IPv6 addresses by converting them to an
335368
* IPv6-mapped format for uniformity.
@@ -360,7 +393,6 @@ static inline void process_tcp(struct sock *sk, statkey *key, pid_t pid) {
360393
break;
361394
}
362395
default: {
363-
364396
return;
365397
}
366398
}
@@ -378,7 +410,8 @@ static inline void process_tcp(struct sock *sk, statkey *key, pid_t pid) {
378410
}
379411

380412
/**
381-
* Process UDP socket information from a sk_buff and populate the key structure.
413+
* Process UDP socket information from a sk_buff and populate the key
414+
* structure.
382415
*
383416
* @param skb pointer to the socket buffer containing the UDP packet
384417
* @param key pointer to the statkey structure to be populated
@@ -425,6 +458,8 @@ static inline void process_udp_recv(struct sk_buff *skb, statkey *key,
425458

426459
break;
427460
}
461+
default:
462+
return;
428463
}
429464

430465
key->src_port = bpf_ntohs(BPF_CORE_READ(udphdr, source));
@@ -468,9 +503,9 @@ static inline size_t process_icmp4(struct sk_buff *skb, statkey *key,
468503

469504
static inline size_t process_icmp6(struct sk_buff *skb, statkey *key,
470505
pid_t pid) {
471-
struct icmphdr *icmphdr =
472-
(struct icmphdr *)(BPF_CORE_READ(skb, head) +
473-
BPF_CORE_READ(skb, transport_header));
506+
struct icmp6hdr *icmphdr =
507+
(struct icmp6hdr *)(BPF_CORE_READ(skb, head) +
508+
BPF_CORE_READ(skb, transport_header));
474509

475510
struct ipv6hdr *iphdr =
476511
(struct ipv6hdr *)(BPF_CORE_READ(skb, head) +
@@ -480,11 +515,11 @@ static inline size_t process_icmp6(struct sk_buff *skb, statkey *key,
480515
BPF_CORE_READ_INTO(&key->dstip, iphdr, daddr);
481516

482517
// store ICMP type in src port
483-
key->src_port = BPF_CORE_READ(icmphdr, type);
518+
key->src_port = BPF_CORE_READ(icmphdr, icmp6_type);
484519
// store ICMP code in dst port
485-
key->dst_port = BPF_CORE_READ(icmphdr, code);
520+
key->dst_port = BPF_CORE_READ(icmphdr, icmp6_code);
486521

487-
key->proto = IPPROTO_ICMP;
522+
key->proto = IPPROTO_ICMPV6;
488523
key->pid = pid;
489524

490525
size_t msglen = bpf_ntohs(BPF_CORE_READ(iphdr, payload_len));
@@ -493,7 +528,8 @@ static inline size_t process_icmp6(struct sk_buff *skb, statkey *key,
493528
}
494529

495530
/**
496-
* Process UDP socket information from a sk_buff and populate the key structure.
531+
* Process UDP socket information from a sk_buff and populate the key
532+
* structure.
497533
*
498534
* @param skb pointer to the socket buffer containing the UDP packet
499535
* @param key pointer to the statkey structure to be populated
@@ -525,7 +561,8 @@ static inline size_t process_udp_send(struct sk_buff *skb, statkey *key,
525561
* packet and the given size in bytes. If the key is already present, the
526562
* packet and byte counters are atomically incremented.
527563
*
528-
* @param key pointer to the statkey structure containing the key to be updated
564+
* @param key pointer to the statkey structure containing the key to be
565+
* updated
529566
* @param size size of the packet to be counted
530567
*
531568
* @throws none
@@ -547,8 +584,8 @@ static inline void update_val(statkey *key, size_t size) {
547584
/**
548585
* Hook function for kprobe on tcp_sendmsg function.
549586
*
550-
* Populates the statkey structure with information from the UDP packet and the
551-
* process ID associated with the packet, and updates the packet and byte
587+
* Populates the statkey structure with information from the UDP packet and
588+
* the process ID associated with the packet, and updates the packet and byte
552589
* counters in the packet count map.
553590
*
554591
* @param sk pointer to the socket structure
@@ -647,8 +684,8 @@ int BPF_KPROBE(ip_send_skb, struct net *net, struct sk_buff *skb) {
647684
/**
648685
* Hook function for kprobe on skb_consume_udp function.
649686
*
650-
* Populates the statkey structure with information from the UDP packet and the
651-
* process ID associated with the packet, and updates the packet and byte
687+
* Populates the statkey structure with information from the UDP packet and
688+
* the process ID associated with the packet, and updates the packet and byte
652689
* counters in the packet count map.
653690
*
654691
* @param sk pointer to the socket structure
@@ -678,8 +715,8 @@ int BPF_KPROBE(skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len) {
678715
/**
679716
* Hook function for kprobe on icmp_send function.
680717
*
681-
* Populates the statkey structure with information from the ICMP packet and the
682-
* process ID associated with the packet, and updates the packet and byte
718+
* Populates the statkey structure with information from the ICMP packet and
719+
* the process ID associated with the packet, and updates the packet and byte
683720
* counters in the packet count map.
684721
*
685722
* @param skb pointer to the socket buffer containing the ICMP packet
@@ -738,8 +775,8 @@ int BPF_KPROBE(icmp6_send, struct sk_buff *skb, int type) {
738775
/**
739776
* Hook function for kprobe on icmp_rcv function.
740777
*
741-
* Populates the statkey structure with information from the ICMP packet and the
742-
* process ID associated with the packet, and updates the packet and byte
778+
* Populates the statkey structure with information from the ICMP packet and
779+
* the process ID associated with the packet, and updates the packet and byte
743780
* counters in the packet count map.
744781
*
745782
* @param skb pointer to the socket buffer containing the ICMP packet

counter_arm64_bpfel.o

1.71 KB
Binary file not shown.

counter_x86_bpfel.o

1.7 KB
Binary file not shown.

flags.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333

3434
const (
3535
defaultIface = "eth0"
36-
defaultTimeout = 1 * time.Hour
36+
defaultTimeout = 10 * time.Minute
3737
defaultXDPMode = "auto"
3838
XDPAttachModeNone link.XDPAttachFlags = 0
3939
)

main.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -151,25 +151,25 @@ func startKprobes(hooks []kprobeHook, links []link.Link) []link.Link {
151151

152152
err := features.HaveProgramType(ebpf.Kprobe)
153153
if errors.Is(err, ebpf.ErrNotSupported) {
154-
log.Fatalf("Kprobes are not supported on this kernel")
154+
log.Fatalf("KProbes are not supported on this kernel")
155155
}
156156

157157
if err != nil {
158-
log.Fatalf("Error checking Kprobes support: %v", err)
158+
log.Fatalf("Error checking KProbes support: %v", err)
159159
}
160160

161161
for _, kp := range hooks {
162162
l, err = link.Kprobe(kp.kprobe, kp.prog, nil)
163163
if err != nil {
164-
log.Printf("Unable to attach %q Kprobe: %v", kp.kprobe, err)
164+
log.Printf("Unable to attach %q KProbe: %v", kp.kprobe, err)
165165

166166
continue
167167
}
168168

169169
links = append(links, l)
170170
}
171171

172-
log.Printf("Starting on interface %q using Kprobes mode w/ PID tracking, listening for %v",
172+
log.Printf("Starting on interface %q using KProbes mode w/ PID tracking, listening for %v",
173173
*ifname, durafmt.Parse(*timeout))
174174

175175
return links

output.go

+10-11
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,19 @@ func outputPlain(m []statEntry) {
109109
var sb strings.Builder
110110

111111
for _, v := range m {
112-
if *useKprobes {
113-
switch v.Proto {
114-
case "ICMPv4", "IPv6-ICMP":
115-
sb.WriteString(fmt.Sprintf("bitrate: %v, packets: %d, bytes: %d, proto: %v, src: %v, dst: %v, type: %d, code: %d",
116-
formatBitrate(v.Bitrate), v.Packets, v.Bytes, v.Proto, v.SrcIP, v.DstIP, v.SrcPort, v.DstPort))
117-
default:
118-
sb.WriteString(fmt.Sprintf("bitrate: %v, packets: %d, bytes: %d, proto: %v, src: %v:%d, dst: %v:%d",
119-
formatBitrate(v.Bitrate), v.Packets, v.Bytes, v.Proto, v.SrcIP, v.SrcPort, v.DstIP, v.DstPort))
120-
}
121-
sb.WriteString(fmt.Sprintf(", pid: %d, comm: %v", v.Pid, v.Comm))
122-
} else {
112+
switch v.Proto {
113+
case "ICMPv4", "IPv6-ICMP":
114+
sb.WriteString(fmt.Sprintf("bitrate: %v, packets: %d, bytes: %d, proto: %v, src: %v, dst: %v, type: %d, code: %d",
115+
formatBitrate(v.Bitrate), v.Packets, v.Bytes, v.Proto, v.SrcIP, v.DstIP, v.SrcPort, v.DstPort))
116+
default:
123117
sb.WriteString(fmt.Sprintf("bitrate: %v, packets: %d, bytes: %d, proto: %v, src: %v:%d, dst: %v:%d",
124118
formatBitrate(v.Bitrate), v.Packets, v.Bytes, v.Proto, v.SrcIP, v.SrcPort, v.DstIP, v.DstPort))
125119
}
120+
121+
if *useKprobes {
122+
sb.WriteString(fmt.Sprintf(", pid: %d, comm: %v", v.Pid, v.Comm))
123+
}
124+
126125
sb.WriteString("\n")
127126
}
128127

0 commit comments

Comments
 (0)