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.
14 #include "net_shared.h"
15 #include <bpf/bpf_helpers.h>
18 # define printk(fmt, ...) \
20 char ____fmt[] = fmt; \
21 bpf_trace_printk(____fmt, sizeof(____fmt), \
27 /* Test: Pass all packets through */
29 int do_nop(struct __sk_buff *skb)
34 /* Test: Verify context information can be accessed */
36 int do_test_ctx(struct __sk_buff *skb)
38 skb->cb[0] = CB_MAGIC;
39 printk("len %d hash %d protocol %d", skb->len, skb->hash,
41 printk("cb %d ingress_ifindex %d ifindex %d", skb->cb[0],
42 skb->ingress_ifindex, skb->ifindex);
47 /* Test: Ensure skb->cb[] buffer is cleared */
49 int do_test_cb(struct __sk_buff *skb)
51 printk("cb0: %x cb1: %x cb2: %x", skb->cb[0], skb->cb[1],
53 printk("cb3: %x cb4: %x", skb->cb[3], skb->cb[4]);
58 /* Test: Verify skb data can be read */
60 int do_test_data(struct __sk_buff *skb)
62 void *data = (void *)(long)skb->data;
63 void *data_end = (void *)(long)skb->data_end;
64 struct iphdr *iph = data;
66 if (data + sizeof(*iph) > data_end) {
67 printk("packet truncated");
71 printk("src: %x dst: %x", iph->saddr, iph->daddr);
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
84 static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
85 uint32_t new_ip, int rw_daddr)
87 int ret, off = 0, flags = IS_PSEUDO;
90 ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
92 printk("bpf_l4_csum_replace failed: %d", ret);
103 flags |= BPF_F_MARK_MANGLED_0;
107 off = offsetof(struct icmp6hdr, icmp6_cksum);
112 ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
113 flags | sizeof(new_ip));
115 printk("bpf_l4_csum_replace failed: %d");
120 ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
122 printk("bpf_l3_csum_replace failed: %d", ret);
127 ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
129 ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
132 printk("bpf_skb_store_bytes() failed: %d", ret);
139 /* Test: Verify skb data can be modified */
141 int do_test_rewrite(struct __sk_buff *skb)
143 uint32_t old_ip, new_ip = 0x3fea8c0;
146 ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
148 printk("bpf_skb_load_bytes failed: %d", ret);
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);
160 static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
162 uint64_t smac = SRC_MAC, dmac = DST_MAC;
163 int ret, ifindex = DST_IFINDEX;
166 ret = bpf_skb_change_head(skb, 14, 0);
168 printk("skb_change_head() failed: %d", ret);
171 ehdr.h_proto = bpf_htons(ETH_P_IP);
172 memcpy(&ehdr.h_source, &smac, 6);
173 memcpy(&ehdr.h_dest, &dmac, 6);
175 ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
177 printk("skb_store_bytes() failed: %d", ret);
181 return bpf_redirect(ifindex, 0);
184 SEC("push_ll_and_redirect_silent")
185 int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
187 return __do_push_ll_and_redirect(skb);
190 SEC("push_ll_and_redirect")
191 int do_push_ll_and_redirect(struct __sk_buff *skb)
193 int ret, ifindex = DST_IFINDEX;
195 ret = __do_push_ll_and_redirect(skb);
197 printk("redirected to %d", ifindex);
202 static inline void __fill_garbage(struct __sk_buff *skb)
204 uint64_t f = 0xFFFFFFFFFFFFFFFF;
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);
221 int do_fill_garbage(struct __sk_buff *skb)
224 printk("Set initial 96 bytes of header to FF");
228 SEC("fill_garbage_and_redirect")
229 int do_fill_garbage_and_redirect(struct __sk_buff *skb)
231 int ifindex = DST_IFINDEX;
233 printk("redirected to %d", ifindex);
234 return bpf_redirect(ifindex, 0);
237 /* Drop all packets */
239 int do_drop_all(struct __sk_buff *skb)
241 printk("dropping with: %d", BPF_DROP);
245 char _license[] SEC("license") = "GPL";