1*f74599f7SThomas Graf /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch> 2*f74599f7SThomas Graf * 3*f74599f7SThomas Graf * This program is free software; you can redistribute it and/or 4*f74599f7SThomas Graf * modify it under the terms of version 2 of the GNU General Public 5*f74599f7SThomas Graf * License as published by the Free Software Foundation. 6*f74599f7SThomas Graf * 7*f74599f7SThomas Graf * This program is distributed in the hope that it will be useful, but 8*f74599f7SThomas Graf * WITHOUT ANY WARRANTY; without even the implied warranty of 9*f74599f7SThomas Graf * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10*f74599f7SThomas Graf * General Public License for more details. 11*f74599f7SThomas Graf */ 12*f74599f7SThomas Graf 13*f74599f7SThomas Graf #include <stdint.h> 14*f74599f7SThomas Graf #include <stddef.h> 15*f74599f7SThomas Graf #include <linux/bpf.h> 16*f74599f7SThomas Graf #include <linux/ip.h> 17*f74599f7SThomas Graf #include <linux/in.h> 18*f74599f7SThomas Graf #include <linux/in6.h> 19*f74599f7SThomas Graf #include <linux/tcp.h> 20*f74599f7SThomas Graf #include <linux/udp.h> 21*f74599f7SThomas Graf #include <linux/icmpv6.h> 22*f74599f7SThomas Graf #include <linux/if_ether.h> 23*f74599f7SThomas Graf #include "bpf_helpers.h" 24*f74599f7SThomas Graf #include <string.h> 25*f74599f7SThomas Graf 26*f74599f7SThomas Graf # define printk(fmt, ...) \ 27*f74599f7SThomas Graf ({ \ 28*f74599f7SThomas Graf char ____fmt[] = fmt; \ 29*f74599f7SThomas Graf bpf_trace_printk(____fmt, sizeof(____fmt), \ 30*f74599f7SThomas Graf ##__VA_ARGS__); \ 31*f74599f7SThomas Graf }) 32*f74599f7SThomas Graf 33*f74599f7SThomas Graf #define CB_MAGIC 1234 34*f74599f7SThomas Graf 35*f74599f7SThomas Graf /* Test: Pass all packets through */ 36*f74599f7SThomas Graf SEC("nop") 37*f74599f7SThomas Graf int do_nop(struct __sk_buff *skb) 38*f74599f7SThomas Graf { 39*f74599f7SThomas Graf return BPF_OK; 40*f74599f7SThomas Graf } 41*f74599f7SThomas Graf 42*f74599f7SThomas Graf /* Test: Verify context information can be accessed */ 43*f74599f7SThomas Graf SEC("test_ctx") 44*f74599f7SThomas Graf int do_test_ctx(struct __sk_buff *skb) 45*f74599f7SThomas Graf { 46*f74599f7SThomas Graf skb->cb[0] = CB_MAGIC; 47*f74599f7SThomas Graf printk("len %d hash %d protocol %d\n", skb->len, skb->hash, 48*f74599f7SThomas Graf skb->protocol); 49*f74599f7SThomas Graf printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0], 50*f74599f7SThomas Graf skb->ingress_ifindex, skb->ifindex); 51*f74599f7SThomas Graf 52*f74599f7SThomas Graf return BPF_OK; 53*f74599f7SThomas Graf } 54*f74599f7SThomas Graf 55*f74599f7SThomas Graf /* Test: Ensure skb->cb[] buffer is cleared */ 56*f74599f7SThomas Graf SEC("test_cb") 57*f74599f7SThomas Graf int do_test_cb(struct __sk_buff *skb) 58*f74599f7SThomas Graf { 59*f74599f7SThomas Graf printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1], 60*f74599f7SThomas Graf skb->cb[2]); 61*f74599f7SThomas Graf printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]); 62*f74599f7SThomas Graf 63*f74599f7SThomas Graf return BPF_OK; 64*f74599f7SThomas Graf } 65*f74599f7SThomas Graf 66*f74599f7SThomas Graf /* Test: Verify skb data can be read */ 67*f74599f7SThomas Graf SEC("test_data") 68*f74599f7SThomas Graf int do_test_data(struct __sk_buff *skb) 69*f74599f7SThomas Graf { 70*f74599f7SThomas Graf void *data = (void *)(long)skb->data; 71*f74599f7SThomas Graf void *data_end = (void *)(long)skb->data_end; 72*f74599f7SThomas Graf struct iphdr *iph = data; 73*f74599f7SThomas Graf 74*f74599f7SThomas Graf if (data + sizeof(*iph) > data_end) { 75*f74599f7SThomas Graf printk("packet truncated\n"); 76*f74599f7SThomas Graf return BPF_DROP; 77*f74599f7SThomas Graf } 78*f74599f7SThomas Graf 79*f74599f7SThomas Graf printk("src: %x dst: %x\n", iph->saddr, iph->daddr); 80*f74599f7SThomas Graf 81*f74599f7SThomas Graf return BPF_OK; 82*f74599f7SThomas Graf } 83*f74599f7SThomas Graf 84*f74599f7SThomas Graf #define IP_CSUM_OFF offsetof(struct iphdr, check) 85*f74599f7SThomas Graf #define IP_DST_OFF offsetof(struct iphdr, daddr) 86*f74599f7SThomas Graf #define IP_SRC_OFF offsetof(struct iphdr, saddr) 87*f74599f7SThomas Graf #define IP_PROTO_OFF offsetof(struct iphdr, protocol) 88*f74599f7SThomas Graf #define TCP_CSUM_OFF offsetof(struct tcphdr, check) 89*f74599f7SThomas Graf #define UDP_CSUM_OFF offsetof(struct udphdr, check) 90*f74599f7SThomas Graf #define IS_PSEUDO 0x10 91*f74599f7SThomas Graf 92*f74599f7SThomas Graf static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip, 93*f74599f7SThomas Graf uint32_t new_ip, int rw_daddr) 94*f74599f7SThomas Graf { 95*f74599f7SThomas Graf int ret, off = 0, flags = IS_PSEUDO; 96*f74599f7SThomas Graf uint8_t proto; 97*f74599f7SThomas Graf 98*f74599f7SThomas Graf ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1); 99*f74599f7SThomas Graf if (ret < 0) { 100*f74599f7SThomas Graf printk("bpf_l4_csum_replace failed: %d\n", ret); 101*f74599f7SThomas Graf return BPF_DROP; 102*f74599f7SThomas Graf } 103*f74599f7SThomas Graf 104*f74599f7SThomas Graf switch (proto) { 105*f74599f7SThomas Graf case IPPROTO_TCP: 106*f74599f7SThomas Graf off = TCP_CSUM_OFF; 107*f74599f7SThomas Graf break; 108*f74599f7SThomas Graf 109*f74599f7SThomas Graf case IPPROTO_UDP: 110*f74599f7SThomas Graf off = UDP_CSUM_OFF; 111*f74599f7SThomas Graf flags |= BPF_F_MARK_MANGLED_0; 112*f74599f7SThomas Graf break; 113*f74599f7SThomas Graf 114*f74599f7SThomas Graf case IPPROTO_ICMPV6: 115*f74599f7SThomas Graf off = offsetof(struct icmp6hdr, icmp6_cksum); 116*f74599f7SThomas Graf break; 117*f74599f7SThomas Graf } 118*f74599f7SThomas Graf 119*f74599f7SThomas Graf if (off) { 120*f74599f7SThomas Graf ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip, 121*f74599f7SThomas Graf flags | sizeof(new_ip)); 122*f74599f7SThomas Graf if (ret < 0) { 123*f74599f7SThomas Graf printk("bpf_l4_csum_replace failed: %d\n"); 124*f74599f7SThomas Graf return BPF_DROP; 125*f74599f7SThomas Graf } 126*f74599f7SThomas Graf } 127*f74599f7SThomas Graf 128*f74599f7SThomas Graf ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip)); 129*f74599f7SThomas Graf if (ret < 0) { 130*f74599f7SThomas Graf printk("bpf_l3_csum_replace failed: %d\n", ret); 131*f74599f7SThomas Graf return BPF_DROP; 132*f74599f7SThomas Graf } 133*f74599f7SThomas Graf 134*f74599f7SThomas Graf if (rw_daddr) 135*f74599f7SThomas Graf ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0); 136*f74599f7SThomas Graf else 137*f74599f7SThomas Graf ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0); 138*f74599f7SThomas Graf 139*f74599f7SThomas Graf if (ret < 0) { 140*f74599f7SThomas Graf printk("bpf_skb_store_bytes() failed: %d\n", ret); 141*f74599f7SThomas Graf return BPF_DROP; 142*f74599f7SThomas Graf } 143*f74599f7SThomas Graf 144*f74599f7SThomas Graf return BPF_OK; 145*f74599f7SThomas Graf } 146*f74599f7SThomas Graf 147*f74599f7SThomas Graf /* Test: Verify skb data can be modified */ 148*f74599f7SThomas Graf SEC("test_rewrite") 149*f74599f7SThomas Graf int do_test_rewrite(struct __sk_buff *skb) 150*f74599f7SThomas Graf { 151*f74599f7SThomas Graf uint32_t old_ip, new_ip = 0x3fea8c0; 152*f74599f7SThomas Graf int ret; 153*f74599f7SThomas Graf 154*f74599f7SThomas Graf ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4); 155*f74599f7SThomas Graf if (ret < 0) { 156*f74599f7SThomas Graf printk("bpf_skb_load_bytes failed: %d\n", ret); 157*f74599f7SThomas Graf return BPF_DROP; 158*f74599f7SThomas Graf } 159*f74599f7SThomas Graf 160*f74599f7SThomas Graf if (old_ip == 0x2fea8c0) { 161*f74599f7SThomas Graf printk("out: rewriting from %x to %x\n", old_ip, new_ip); 162*f74599f7SThomas Graf return rewrite(skb, old_ip, new_ip, 1); 163*f74599f7SThomas Graf } 164*f74599f7SThomas Graf 165*f74599f7SThomas Graf return BPF_OK; 166*f74599f7SThomas Graf } 167*f74599f7SThomas Graf 168*f74599f7SThomas Graf static inline int __do_push_ll_and_redirect(struct __sk_buff *skb) 169*f74599f7SThomas Graf { 170*f74599f7SThomas Graf uint64_t smac = SRC_MAC, dmac = DST_MAC; 171*f74599f7SThomas Graf int ret, ifindex = DST_IFINDEX; 172*f74599f7SThomas Graf struct ethhdr ehdr; 173*f74599f7SThomas Graf 174*f74599f7SThomas Graf ret = bpf_skb_change_head(skb, 14, 0); 175*f74599f7SThomas Graf if (ret < 0) { 176*f74599f7SThomas Graf printk("skb_change_head() failed: %d\n", ret); 177*f74599f7SThomas Graf } 178*f74599f7SThomas Graf 179*f74599f7SThomas Graf ehdr.h_proto = __constant_htons(ETH_P_IP); 180*f74599f7SThomas Graf memcpy(&ehdr.h_source, &smac, 6); 181*f74599f7SThomas Graf memcpy(&ehdr.h_dest, &dmac, 6); 182*f74599f7SThomas Graf 183*f74599f7SThomas Graf ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0); 184*f74599f7SThomas Graf if (ret < 0) { 185*f74599f7SThomas Graf printk("skb_store_bytes() failed: %d\n", ret); 186*f74599f7SThomas Graf return BPF_DROP; 187*f74599f7SThomas Graf } 188*f74599f7SThomas Graf 189*f74599f7SThomas Graf return bpf_redirect(ifindex, 0); 190*f74599f7SThomas Graf } 191*f74599f7SThomas Graf 192*f74599f7SThomas Graf SEC("push_ll_and_redirect_silent") 193*f74599f7SThomas Graf int do_push_ll_and_redirect_silent(struct __sk_buff *skb) 194*f74599f7SThomas Graf { 195*f74599f7SThomas Graf return __do_push_ll_and_redirect(skb); 196*f74599f7SThomas Graf } 197*f74599f7SThomas Graf 198*f74599f7SThomas Graf SEC("push_ll_and_redirect") 199*f74599f7SThomas Graf int do_push_ll_and_redirect(struct __sk_buff *skb) 200*f74599f7SThomas Graf { 201*f74599f7SThomas Graf int ret, ifindex = DST_IFINDEX; 202*f74599f7SThomas Graf 203*f74599f7SThomas Graf ret = __do_push_ll_and_redirect(skb); 204*f74599f7SThomas Graf if (ret >= 0) 205*f74599f7SThomas Graf printk("redirected to %d\n", ifindex); 206*f74599f7SThomas Graf 207*f74599f7SThomas Graf return ret; 208*f74599f7SThomas Graf } 209*f74599f7SThomas Graf 210*f74599f7SThomas Graf static inline void __fill_garbage(struct __sk_buff *skb) 211*f74599f7SThomas Graf { 212*f74599f7SThomas Graf uint64_t f = 0xFFFFFFFFFFFFFFFF; 213*f74599f7SThomas Graf 214*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0); 215*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0); 216*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0); 217*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0); 218*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0); 219*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0); 220*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0); 221*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0); 222*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0); 223*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0); 224*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0); 225*f74599f7SThomas Graf bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0); 226*f74599f7SThomas Graf } 227*f74599f7SThomas Graf 228*f74599f7SThomas Graf SEC("fill_garbage") 229*f74599f7SThomas Graf int do_fill_garbage(struct __sk_buff *skb) 230*f74599f7SThomas Graf { 231*f74599f7SThomas Graf __fill_garbage(skb); 232*f74599f7SThomas Graf printk("Set initial 96 bytes of header to FF\n"); 233*f74599f7SThomas Graf return BPF_OK; 234*f74599f7SThomas Graf } 235*f74599f7SThomas Graf 236*f74599f7SThomas Graf SEC("fill_garbage_and_redirect") 237*f74599f7SThomas Graf int do_fill_garbage_and_redirect(struct __sk_buff *skb) 238*f74599f7SThomas Graf { 239*f74599f7SThomas Graf int ifindex = DST_IFINDEX; 240*f74599f7SThomas Graf __fill_garbage(skb); 241*f74599f7SThomas Graf printk("redirected to %d\n", ifindex); 242*f74599f7SThomas Graf return bpf_redirect(ifindex, 0); 243*f74599f7SThomas Graf } 244*f74599f7SThomas Graf 245*f74599f7SThomas Graf /* Drop all packets */ 246*f74599f7SThomas Graf SEC("drop_all") 247*f74599f7SThomas Graf int do_drop_all(struct __sk_buff *skb) 248*f74599f7SThomas Graf { 249*f74599f7SThomas Graf printk("dropping with: %d\n", BPF_DROP); 250*f74599f7SThomas Graf return BPF_DROP; 251*f74599f7SThomas Graf } 252*f74599f7SThomas Graf 253*f74599f7SThomas Graf char _license[] SEC("license") = "GPL"; 254