167117Sdfr/* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch> 267117Sdfr * 367117Sdfr * This program is free software; you can redistribute it and/or 467117Sdfr * modify it under the terms of version 2 of the GNU General Public 567117Sdfr * License as published by the Free Software Foundation. 667117Sdfr * 767117Sdfr * This program is distributed in the hope that it will be useful, but 867117Sdfr * WITHOUT ANY WARRANTY; without even the implied warranty of 967117Sdfr * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1067117Sdfr * General Public License for more details. 1167117Sdfr */ 1267117Sdfr 1367117Sdfr#include "vmlinux.h" 1467117Sdfr#include "net_shared.h" 1567117Sdfr#include <bpf/bpf_helpers.h> 1667117Sdfr#include <string.h> 1767117Sdfr 1867117Sdfr# define printk(fmt, ...) \ 1967117Sdfr ({ \ 2067117Sdfr char ____fmt[] = fmt; \ 2167117Sdfr bpf_trace_printk(____fmt, sizeof(____fmt), \ 2267117Sdfr ##__VA_ARGS__); \ 2367117Sdfr }) 2467117Sdfr 2567117Sdfr#define CB_MAGIC 1234 2667117Sdfr 2767117Sdfr/* Test: Pass all packets through */ 2867117SdfrSEC("nop") 2967117Sdfrint do_nop(struct __sk_buff *skb) 30111777Sobrien{ 31111777Sobrien return BPF_OK; 32111777Sobrien} 3367117Sdfr 3467117Sdfr/* Test: Verify context information can be accessed */ 3567117SdfrSEC("test_ctx") 3667117Sdfrint do_test_ctx(struct __sk_buff *skb) 3767117Sdfr{ 3867117Sdfr skb->cb[0] = CB_MAGIC; 3967117Sdfr printk("len %d hash %d protocol %d", skb->len, skb->hash, 4067117Sdfr skb->protocol); 4167117Sdfr printk("cb %d ingress_ifindex %d ifindex %d", skb->cb[0], 4267117Sdfr skb->ingress_ifindex, skb->ifindex); 4367117Sdfr 4484755Sdfr return BPF_OK; 4567117Sdfr} 4684755Sdfr 47115084Smarcel/* Test: Ensure skb->cb[] buffer is cleared */ 48115084SmarcelSEC("test_cb") 49115084Smarcelint do_test_cb(struct __sk_buff *skb) 5067117Sdfr{ 51115084Smarcel printk("cb0: %x cb1: %x cb2: %x", skb->cb[0], skb->cb[1], 5284755Sdfr skb->cb[2]); 5384755Sdfr printk("cb3: %x cb4: %x", skb->cb[3], skb->cb[4]); 54115084Smarcel 5567117Sdfr return BPF_OK; 5667117Sdfr} 5767117Sdfr 58/* Test: Verify skb data can be read */ 59SEC("test_data") 60int do_test_data(struct __sk_buff *skb) 61{ 62 void *data = (void *)(long)skb->data; 63 void *data_end = (void *)(long)skb->data_end; 64 struct iphdr *iph = data; 65 66 if (data + sizeof(*iph) > data_end) { 67 printk("packet truncated"); 68 return BPF_DROP; 69 } 70 71 printk("src: %x dst: %x", iph->saddr, iph->daddr); 72 73 return BPF_OK; 74} 75 76#define IP_CSUM_OFF offsetof(struct iphdr, check) 77#define IP_DST_OFF offsetof(struct iphdr, daddr) 78#define IP_SRC_OFF offsetof(struct iphdr, saddr) 79#define IP_PROTO_OFF offsetof(struct iphdr, protocol) 80#define TCP_CSUM_OFF offsetof(struct tcphdr, check) 81#define UDP_CSUM_OFF offsetof(struct udphdr, check) 82#define IS_PSEUDO 0x10 83 84static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip, 85 uint32_t new_ip, int rw_daddr) 86{ 87 int ret, off = 0, flags = IS_PSEUDO; 88 uint8_t proto; 89 90 ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1); 91 if (ret < 0) { 92 printk("bpf_l4_csum_replace failed: %d", ret); 93 return BPF_DROP; 94 } 95 96 switch (proto) { 97 case IPPROTO_TCP: 98 off = TCP_CSUM_OFF; 99 break; 100 101 case IPPROTO_UDP: 102 off = UDP_CSUM_OFF; 103 flags |= BPF_F_MARK_MANGLED_0; 104 break; 105 106 case IPPROTO_ICMPV6: 107 off = offsetof(struct icmp6hdr, icmp6_cksum); 108 break; 109 } 110 111 if (off) { 112 ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip, 113 flags | sizeof(new_ip)); 114 if (ret < 0) { 115 printk("bpf_l4_csum_replace failed: %d"); 116 return BPF_DROP; 117 } 118 } 119 120 ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip)); 121 if (ret < 0) { 122 printk("bpf_l3_csum_replace failed: %d", ret); 123 return BPF_DROP; 124 } 125 126 if (rw_daddr) 127 ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0); 128 else 129 ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0); 130 131 if (ret < 0) { 132 printk("bpf_skb_store_bytes() failed: %d", ret); 133 return BPF_DROP; 134 } 135 136 return BPF_OK; 137} 138 139/* Test: Verify skb data can be modified */ 140SEC("test_rewrite") 141int do_test_rewrite(struct __sk_buff *skb) 142{ 143 uint32_t old_ip, new_ip = 0x3fea8c0; 144 int ret; 145 146 ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4); 147 if (ret < 0) { 148 printk("bpf_skb_load_bytes failed: %d", ret); 149 return BPF_DROP; 150 } 151 152 if (old_ip == 0x2fea8c0) { 153 printk("out: rewriting from %x to %x", old_ip, new_ip); 154 return rewrite(skb, old_ip, new_ip, 1); 155 } 156 157 return BPF_OK; 158} 159 160static inline int __do_push_ll_and_redirect(struct __sk_buff *skb) 161{ 162 uint64_t smac = SRC_MAC, dmac = DST_MAC; 163 int ret, ifindex = DST_IFINDEX; 164 struct ethhdr ehdr; 165 166 ret = bpf_skb_change_head(skb, 14, 0); 167 if (ret < 0) { 168 printk("skb_change_head() failed: %d", ret); 169 } 170 171 ehdr.h_proto = bpf_htons(ETH_P_IP); 172 memcpy(&ehdr.h_source, &smac, 6); 173 memcpy(&ehdr.h_dest, &dmac, 6); 174 175 ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0); 176 if (ret < 0) { 177 printk("skb_store_bytes() failed: %d", ret); 178 return BPF_DROP; 179 } 180 181 return bpf_redirect(ifindex, 0); 182} 183 184SEC("push_ll_and_redirect_silent") 185int do_push_ll_and_redirect_silent(struct __sk_buff *skb) 186{ 187 return __do_push_ll_and_redirect(skb); 188} 189 190SEC("push_ll_and_redirect") 191int do_push_ll_and_redirect(struct __sk_buff *skb) 192{ 193 int ret, ifindex = DST_IFINDEX; 194 195 ret = __do_push_ll_and_redirect(skb); 196 if (ret >= 0) 197 printk("redirected to %d", ifindex); 198 199 return ret; 200} 201 202static inline void __fill_garbage(struct __sk_buff *skb) 203{ 204 uint64_t f = 0xFFFFFFFFFFFFFFFF; 205 206 bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0); 207 bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0); 208 bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0); 209 bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0); 210 bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0); 211 bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0); 212 bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0); 213 bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0); 214 bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0); 215 bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0); 216 bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0); 217 bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0); 218} 219 220SEC("fill_garbage") 221int do_fill_garbage(struct __sk_buff *skb) 222{ 223 __fill_garbage(skb); 224 printk("Set initial 96 bytes of header to FF"); 225 return BPF_OK; 226} 227 228SEC("fill_garbage_and_redirect") 229int do_fill_garbage_and_redirect(struct __sk_buff *skb) 230{ 231 int ifindex = DST_IFINDEX; 232 __fill_garbage(skb); 233 printk("redirected to %d", ifindex); 234 return bpf_redirect(ifindex, 0); 235} 236 237/* Drop all packets */ 238SEC("drop_all") 239int do_drop_all(struct __sk_buff *skb) 240{ 241 printk("dropping with: %d", BPF_DROP); 242 return BPF_DROP; 243} 244 245char _license[] SEC("license") = "GPL"; 246