1 // SPDX-License-Identifier: GPL-2.0-only 2 #include "vmlinux.h" 3 #include <bpf/bpf_helpers.h> 4 #include <bpf/bpf_endian.h> 5 #include "bpf_tracing_net.h" 6 7 #define NF_DROP 0 8 #define NF_ACCEPT 1 9 #define ETH_P_IP 0x0800 10 #define ETH_P_IPV6 0x86DD 11 #define IP_MF 0x2000 12 #define IP_OFFSET 0x1FFF 13 #define NEXTHDR_FRAGMENT 44 14 15 volatile int shootdowns = 0; 16 17 static bool is_frag_v4(struct iphdr *iph) 18 { 19 int offset; 20 int flags; 21 22 offset = bpf_ntohs(iph->frag_off); 23 flags = offset & ~IP_OFFSET; 24 offset &= IP_OFFSET; 25 offset <<= 3; 26 27 return (flags & IP_MF) || offset; 28 } 29 30 static bool is_frag_v6(struct ipv6hdr *ip6h) 31 { 32 /* Simplifying assumption that there are no extension headers 33 * between fixed header and fragmentation header. This assumption 34 * is only valid in this test case. It saves us the hassle of 35 * searching all potential extension headers. 36 */ 37 return ip6h->nexthdr == NEXTHDR_FRAGMENT; 38 } 39 40 static int handle_v4(struct __sk_buff *skb) 41 { 42 struct bpf_dynptr ptr; 43 u8 iph_buf[20] = {}; 44 struct iphdr *iph; 45 46 if (bpf_dynptr_from_skb(skb, 0, &ptr)) 47 return NF_DROP; 48 49 iph = bpf_dynptr_slice(&ptr, 0, iph_buf, sizeof(iph_buf)); 50 if (!iph) 51 return NF_DROP; 52 53 /* Shootdown any frags */ 54 if (is_frag_v4(iph)) { 55 shootdowns++; 56 return NF_DROP; 57 } 58 59 return NF_ACCEPT; 60 } 61 62 static int handle_v6(struct __sk_buff *skb) 63 { 64 struct bpf_dynptr ptr; 65 struct ipv6hdr *ip6h; 66 u8 ip6h_buf[40] = {}; 67 68 if (bpf_dynptr_from_skb(skb, 0, &ptr)) 69 return NF_DROP; 70 71 ip6h = bpf_dynptr_slice(&ptr, 0, ip6h_buf, sizeof(ip6h_buf)); 72 if (!ip6h) 73 return NF_DROP; 74 75 /* Shootdown any frags */ 76 if (is_frag_v6(ip6h)) { 77 shootdowns++; 78 return NF_DROP; 79 } 80 81 return NF_ACCEPT; 82 } 83 84 SEC("netfilter") 85 int defrag(struct bpf_nf_ctx *ctx) 86 { 87 struct __sk_buff *skb = (struct __sk_buff *)ctx->skb; 88 89 switch (bpf_ntohs(ctx->skb->protocol)) { 90 case ETH_P_IP: 91 return handle_v4(skb); 92 case ETH_P_IPV6: 93 return handle_v6(skb); 94 default: 95 return NF_ACCEPT; 96 } 97 } 98 99 char _license[] SEC("license") = "GPL"; 100