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 15extern int bpf_dynptr_from_skb(struct sk_buff *skb, __u64 flags, 16 struct bpf_dynptr *ptr__uninit) __ksym; 17extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, uint32_t offset, 18 void *buffer, uint32_t buffer__sz) __ksym; 19 20volatile int shootdowns = 0; 21 22static 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 35static 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 45static 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 67static 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 89SEC("netfilter") 90int 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 104char _license[] SEC("license") = "GPL"; 105