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