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 extern int bpf_dynptr_from_skb(struct sk_buff *skb, __u64 flags, 16 struct bpf_dynptr *ptr__uninit) __ksym; 17 extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, uint32_t offset, 18 void *buffer, uint32_t buffer__sz) __ksym; 19 20 volatile int shootdowns = 0; 21 22 static bool is_frag_v4(struct iphdr *iph) 23 { 24 int offset; 25 int flags; 26 27 offset = bpf_ntohs(iph->frag_off); 28 flags = offset & ~IP_OFFSET; 29 offset &= IP_OFFSET; 30 offset <<= 3; 31 32 return (flags & IP_MF) || offset; 33 } 34 35 static bool is_frag_v6(struct ipv6hdr *ip6h) 36 { 37 /* Simplifying assumption that there are no extension headers 38 * between fixed header and fragmentation header. This assumption 39 * is only valid in this test case. It saves us the hassle of 40 * searching all potential extension headers. 41 */ 42 return ip6h->nexthdr == NEXTHDR_FRAGMENT; 43 } 44 45 static int handle_v4(struct sk_buff *skb) 46 { 47 struct bpf_dynptr ptr; 48 u8 iph_buf[20] = {}; 49 struct iphdr *iph; 50 51 if (bpf_dynptr_from_skb(skb, 0, &ptr)) 52 return NF_DROP; 53 54 iph = bpf_dynptr_slice(&ptr, 0, iph_buf, sizeof(iph_buf)); 55 if (!iph) 56 return NF_DROP; 57 58 /* Shootdown any frags */ 59 if (is_frag_v4(iph)) { 60 shootdowns++; 61 return NF_DROP; 62 } 63 64 return NF_ACCEPT; 65 } 66 67 static int handle_v6(struct sk_buff *skb) 68 { 69 struct bpf_dynptr ptr; 70 struct ipv6hdr *ip6h; 71 u8 ip6h_buf[40] = {}; 72 73 if (bpf_dynptr_from_skb(skb, 0, &ptr)) 74 return NF_DROP; 75 76 ip6h = bpf_dynptr_slice(&ptr, 0, ip6h_buf, sizeof(ip6h_buf)); 77 if (!ip6h) 78 return NF_DROP; 79 80 /* Shootdown any frags */ 81 if (is_frag_v6(ip6h)) { 82 shootdowns++; 83 return NF_DROP; 84 } 85 86 return NF_ACCEPT; 87 } 88 89 SEC("netfilter") 90 int defrag(struct bpf_nf_ctx *ctx) 91 { 92 struct sk_buff *skb = ctx->skb; 93 94 switch (bpf_ntohs(skb->protocol)) { 95 case ETH_P_IP: 96 return handle_v4(skb); 97 case ETH_P_IPV6: 98 return handle_v6(skb); 99 default: 100 return NF_ACCEPT; 101 } 102 } 103 104 char _license[] SEC("license") = "GPL"; 105