Commit | Line | Data |
---|---|---|
f74599f7 TG |
1 | /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch> |
2 | * | |
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. | |
6 | * | |
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. | |
11 | */ | |
12 | ||
e8acf8f4 | 13 | #include "vmlinux.h" |
c2f4f559 | 14 | #include "net_shared.h" |
7cf245a3 | 15 | #include <bpf/bpf_helpers.h> |
f74599f7 TG |
16 | #include <string.h> |
17 | ||
18 | # define printk(fmt, ...) \ | |
19 | ({ \ | |
20 | char ____fmt[] = fmt; \ | |
21 | bpf_trace_printk(____fmt, sizeof(____fmt), \ | |
22 | ##__VA_ARGS__); \ | |
23 | }) | |
24 | ||
25 | #define CB_MAGIC 1234 | |
26 | ||
27 | /* Test: Pass all packets through */ | |
28 | SEC("nop") | |
29 | int do_nop(struct __sk_buff *skb) | |
30 | { | |
31 | return BPF_OK; | |
32 | } | |
33 | ||
34 | /* Test: Verify context information can be accessed */ | |
35 | SEC("test_ctx") | |
36 | int do_test_ctx(struct __sk_buff *skb) | |
37 | { | |
38 | skb->cb[0] = CB_MAGIC; | |
dac808c9 | 39 | printk("len %d hash %d protocol %d", skb->len, skb->hash, |
f74599f7 | 40 | skb->protocol); |
dac808c9 | 41 | printk("cb %d ingress_ifindex %d ifindex %d", skb->cb[0], |
f74599f7 TG |
42 | skb->ingress_ifindex, skb->ifindex); |
43 | ||
44 | return BPF_OK; | |
45 | } | |
46 | ||
47 | /* Test: Ensure skb->cb[] buffer is cleared */ | |
48 | SEC("test_cb") | |
49 | int do_test_cb(struct __sk_buff *skb) | |
50 | { | |
dac808c9 | 51 | printk("cb0: %x cb1: %x cb2: %x", skb->cb[0], skb->cb[1], |
f74599f7 | 52 | skb->cb[2]); |
dac808c9 | 53 | printk("cb3: %x cb4: %x", skb->cb[3], skb->cb[4]); |
f74599f7 TG |
54 | |
55 | return BPF_OK; | |
56 | } | |
57 | ||
58 | /* Test: Verify skb data can be read */ | |
59 | SEC("test_data") | |
60 | int 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) { | |
dac808c9 | 67 | printk("packet truncated"); |
f74599f7 TG |
68 | return BPF_DROP; |
69 | } | |
70 | ||
dac808c9 | 71 | printk("src: %x dst: %x", iph->saddr, iph->daddr); |
f74599f7 TG |
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 | ||
84 | static 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) { | |
dac808c9 | 92 | printk("bpf_l4_csum_replace failed: %d", ret); |
f74599f7 TG |
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) { | |
dac808c9 | 115 | printk("bpf_l4_csum_replace failed: %d"); |
f74599f7 TG |
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) { | |
dac808c9 | 122 | printk("bpf_l3_csum_replace failed: %d", ret); |
f74599f7 TG |
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) { | |
dac808c9 | 132 | printk("bpf_skb_store_bytes() failed: %d", ret); |
f74599f7 TG |
133 | return BPF_DROP; |
134 | } | |
135 | ||
136 | return BPF_OK; | |
137 | } | |
138 | ||
139 | /* Test: Verify skb data can be modified */ | |
140 | SEC("test_rewrite") | |
141 | int 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) { | |
dac808c9 | 148 | printk("bpf_skb_load_bytes failed: %d", ret); |
f74599f7 TG |
149 | return BPF_DROP; |
150 | } | |
151 | ||
152 | if (old_ip == 0x2fea8c0) { | |
dac808c9 | 153 | printk("out: rewriting from %x to %x", old_ip, new_ip); |
f74599f7 TG |
154 | return rewrite(skb, old_ip, new_ip, 1); |
155 | } | |
156 | ||
157 | return BPF_OK; | |
158 | } | |
159 | ||
160 | static 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) { | |
dac808c9 | 168 | printk("skb_change_head() failed: %d", ret); |
f74599f7 TG |
169 | } |
170 | ||
c2f4f559 | 171 | ehdr.h_proto = bpf_htons(ETH_P_IP); |
f74599f7 TG |
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) { | |
dac808c9 | 177 | printk("skb_store_bytes() failed: %d", ret); |
f74599f7 TG |
178 | return BPF_DROP; |
179 | } | |
180 | ||
181 | return bpf_redirect(ifindex, 0); | |
182 | } | |
183 | ||
184 | SEC("push_ll_and_redirect_silent") | |
185 | int do_push_ll_and_redirect_silent(struct __sk_buff *skb) | |
186 | { | |
187 | return __do_push_ll_and_redirect(skb); | |
188 | } | |
189 | ||
190 | SEC("push_ll_and_redirect") | |
191 | int 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) | |
dac808c9 | 197 | printk("redirected to %d", ifindex); |
f74599f7 TG |
198 | |
199 | return ret; | |
200 | } | |
201 | ||
202 | static 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 | ||
220 | SEC("fill_garbage") | |
221 | int do_fill_garbage(struct __sk_buff *skb) | |
222 | { | |
223 | __fill_garbage(skb); | |
dac808c9 | 224 | printk("Set initial 96 bytes of header to FF"); |
f74599f7 TG |
225 | return BPF_OK; |
226 | } | |
227 | ||
228 | SEC("fill_garbage_and_redirect") | |
229 | int do_fill_garbage_and_redirect(struct __sk_buff *skb) | |
230 | { | |
231 | int ifindex = DST_IFINDEX; | |
232 | __fill_garbage(skb); | |
dac808c9 | 233 | printk("redirected to %d", ifindex); |
f74599f7 TG |
234 | return bpf_redirect(ifindex, 0); |
235 | } | |
236 | ||
237 | /* Drop all packets */ | |
238 | SEC("drop_all") | |
239 | int do_drop_all(struct __sk_buff *skb) | |
240 | { | |
dac808c9 | 241 | printk("dropping with: %d", BPF_DROP); |
f74599f7 TG |
242 | return BPF_DROP; |
243 | } | |
244 | ||
245 | char _license[] SEC("license") = "GPL"; |