1 /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
15 #include <linux/bpf.h>
18 #include <linux/in6.h>
19 #include <linux/tcp.h>
20 #include <linux/udp.h>
21 #include <linux/icmpv6.h>
22 #include <linux/if_ether.h>
23 #include <bpf/bpf_helpers.h>
26 # define printk(fmt, ...) \
28 char ____fmt[] = fmt; \
29 bpf_trace_printk(____fmt, sizeof(____fmt), \
35 /* Test: Pass all packets through */
37 int do_nop(struct __sk_buff
*skb
)
42 /* Test: Verify context information can be accessed */
44 int do_test_ctx(struct __sk_buff
*skb
)
46 skb
->cb
[0] = CB_MAGIC
;
47 printk("len %d hash %d protocol %d\n", skb
->len
, skb
->hash
,
49 printk("cb %d ingress_ifindex %d ifindex %d\n", skb
->cb
[0],
50 skb
->ingress_ifindex
, skb
->ifindex
);
55 /* Test: Ensure skb->cb[] buffer is cleared */
57 int do_test_cb(struct __sk_buff
*skb
)
59 printk("cb0: %x cb1: %x cb2: %x\n", skb
->cb
[0], skb
->cb
[1],
61 printk("cb3: %x cb4: %x\n", skb
->cb
[3], skb
->cb
[4]);
66 /* Test: Verify skb data can be read */
68 int do_test_data(struct __sk_buff
*skb
)
70 void *data
= (void *)(long)skb
->data
;
71 void *data_end
= (void *)(long)skb
->data_end
;
72 struct iphdr
*iph
= data
;
74 if (data
+ sizeof(*iph
) > data_end
) {
75 printk("packet truncated\n");
79 printk("src: %x dst: %x\n", iph
->saddr
, iph
->daddr
);
84 #define IP_CSUM_OFF offsetof(struct iphdr, check)
85 #define IP_DST_OFF offsetof(struct iphdr, daddr)
86 #define IP_SRC_OFF offsetof(struct iphdr, saddr)
87 #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
88 #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
89 #define UDP_CSUM_OFF offsetof(struct udphdr, check)
90 #define IS_PSEUDO 0x10
92 static inline int rewrite(struct __sk_buff
*skb
, uint32_t old_ip
,
93 uint32_t new_ip
, int rw_daddr
)
95 int ret
, off
= 0, flags
= IS_PSEUDO
;
98 ret
= bpf_skb_load_bytes(skb
, IP_PROTO_OFF
, &proto
, 1);
100 printk("bpf_l4_csum_replace failed: %d\n", ret
);
111 flags
|= BPF_F_MARK_MANGLED_0
;
115 off
= offsetof(struct icmp6hdr
, icmp6_cksum
);
120 ret
= bpf_l4_csum_replace(skb
, off
, old_ip
, new_ip
,
121 flags
| sizeof(new_ip
));
123 printk("bpf_l4_csum_replace failed: %d\n");
128 ret
= bpf_l3_csum_replace(skb
, IP_CSUM_OFF
, old_ip
, new_ip
, sizeof(new_ip
));
130 printk("bpf_l3_csum_replace failed: %d\n", ret
);
135 ret
= bpf_skb_store_bytes(skb
, IP_DST_OFF
, &new_ip
, sizeof(new_ip
), 0);
137 ret
= bpf_skb_store_bytes(skb
, IP_SRC_OFF
, &new_ip
, sizeof(new_ip
), 0);
140 printk("bpf_skb_store_bytes() failed: %d\n", ret
);
147 /* Test: Verify skb data can be modified */
149 int do_test_rewrite(struct __sk_buff
*skb
)
151 uint32_t old_ip
, new_ip
= 0x3fea8c0;
154 ret
= bpf_skb_load_bytes(skb
, IP_DST_OFF
, &old_ip
, 4);
156 printk("bpf_skb_load_bytes failed: %d\n", ret
);
160 if (old_ip
== 0x2fea8c0) {
161 printk("out: rewriting from %x to %x\n", old_ip
, new_ip
);
162 return rewrite(skb
, old_ip
, new_ip
, 1);
168 static inline int __do_push_ll_and_redirect(struct __sk_buff
*skb
)
170 uint64_t smac
= SRC_MAC
, dmac
= DST_MAC
;
171 int ret
, ifindex
= DST_IFINDEX
;
174 ret
= bpf_skb_change_head(skb
, 14, 0);
176 printk("skb_change_head() failed: %d\n", ret
);
179 ehdr
.h_proto
= __constant_htons(ETH_P_IP
);
180 memcpy(&ehdr
.h_source
, &smac
, 6);
181 memcpy(&ehdr
.h_dest
, &dmac
, 6);
183 ret
= bpf_skb_store_bytes(skb
, 0, &ehdr
, sizeof(ehdr
), 0);
185 printk("skb_store_bytes() failed: %d\n", ret
);
189 return bpf_redirect(ifindex
, 0);
192 SEC("push_ll_and_redirect_silent")
193 int do_push_ll_and_redirect_silent(struct __sk_buff
*skb
)
195 return __do_push_ll_and_redirect(skb
);
198 SEC("push_ll_and_redirect")
199 int do_push_ll_and_redirect(struct __sk_buff
*skb
)
201 int ret
, ifindex
= DST_IFINDEX
;
203 ret
= __do_push_ll_and_redirect(skb
);
205 printk("redirected to %d\n", ifindex
);
210 static inline void __fill_garbage(struct __sk_buff
*skb
)
212 uint64_t f
= 0xFFFFFFFFFFFFFFFF;
214 bpf_skb_store_bytes(skb
, 0, &f
, sizeof(f
), 0);
215 bpf_skb_store_bytes(skb
, 8, &f
, sizeof(f
), 0);
216 bpf_skb_store_bytes(skb
, 16, &f
, sizeof(f
), 0);
217 bpf_skb_store_bytes(skb
, 24, &f
, sizeof(f
), 0);
218 bpf_skb_store_bytes(skb
, 32, &f
, sizeof(f
), 0);
219 bpf_skb_store_bytes(skb
, 40, &f
, sizeof(f
), 0);
220 bpf_skb_store_bytes(skb
, 48, &f
, sizeof(f
), 0);
221 bpf_skb_store_bytes(skb
, 56, &f
, sizeof(f
), 0);
222 bpf_skb_store_bytes(skb
, 64, &f
, sizeof(f
), 0);
223 bpf_skb_store_bytes(skb
, 72, &f
, sizeof(f
), 0);
224 bpf_skb_store_bytes(skb
, 80, &f
, sizeof(f
), 0);
225 bpf_skb_store_bytes(skb
, 88, &f
, sizeof(f
), 0);
229 int do_fill_garbage(struct __sk_buff
*skb
)
232 printk("Set initial 96 bytes of header to FF\n");
236 SEC("fill_garbage_and_redirect")
237 int do_fill_garbage_and_redirect(struct __sk_buff
*skb
)
239 int ifindex
= DST_IFINDEX
;
241 printk("redirected to %d\n", ifindex
);
242 return bpf_redirect(ifindex
, 0);
245 /* Drop all packets */
247 int do_drop_all(struct __sk_buff
*skb
)
249 printk("dropping with: %d\n", BPF_DROP
);
253 char _license
[] SEC("license") = "GPL";