Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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
 13#include <stdint.h>
 14#include <stddef.h>
 15#include <linux/bpf.h>
 16#include <linux/ip.h>
 17#include <linux/in.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_helpers.h"
 24#include <string.h>
 25
 26# define printk(fmt, ...)						\
 27		({							\
 28			char ____fmt[] = fmt;				\
 29			bpf_trace_printk(____fmt, sizeof(____fmt),	\
 30				     ##__VA_ARGS__);			\
 31		})
 32
 33#define CB_MAGIC 1234
 34
 35/* Test: Pass all packets through */
 36SEC("nop")
 37int do_nop(struct __sk_buff *skb)
 38{
 39	return BPF_OK;
 40}
 41
 42/* Test: Verify context information can be accessed */
 43SEC("test_ctx")
 44int do_test_ctx(struct __sk_buff *skb)
 45{
 46	skb->cb[0] = CB_MAGIC;
 47	printk("len %d hash %d protocol %d\n", skb->len, skb->hash,
 48	       skb->protocol);
 49	printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0],
 50	       skb->ingress_ifindex, skb->ifindex);
 51
 52	return BPF_OK;
 53}
 54
 55/* Test: Ensure skb->cb[] buffer is cleared */
 56SEC("test_cb")
 57int do_test_cb(struct __sk_buff *skb)
 58{
 59	printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1],
 60	       skb->cb[2]);
 61	printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]);
 62
 63	return BPF_OK;
 64}
 65
 66/* Test: Verify skb data can be read */
 67SEC("test_data")
 68int do_test_data(struct __sk_buff *skb)
 69{
 70	void *data = (void *)(long)skb->data;
 71	void *data_end = (void *)(long)skb->data_end;
 72	struct iphdr *iph = data;
 73
 74	if (data + sizeof(*iph) > data_end) {
 75		printk("packet truncated\n");
 76		return BPF_DROP;
 77	}
 78
 79	printk("src: %x dst: %x\n", iph->saddr, iph->daddr);
 80
 81	return BPF_OK;
 82}
 83
 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
 91
 92static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
 93			  uint32_t new_ip, int rw_daddr)
 94{
 95	int ret, off = 0, flags = IS_PSEUDO;
 96	uint8_t proto;
 97
 98	ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
 99	if (ret < 0) {
100		printk("bpf_l4_csum_replace failed: %d\n", ret);
101		return BPF_DROP;
102	}
103
104	switch (proto) {
105	case IPPROTO_TCP:
106		off = TCP_CSUM_OFF;
107		break;
108
109	case IPPROTO_UDP:
110		off = UDP_CSUM_OFF;
111		flags |= BPF_F_MARK_MANGLED_0;
112		break;
113
114	case IPPROTO_ICMPV6:
115		off = offsetof(struct icmp6hdr, icmp6_cksum);
116		break;
117	}
118
119	if (off) {
120		ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
121					  flags | sizeof(new_ip));
122		if (ret < 0) {
123			printk("bpf_l4_csum_replace failed: %d\n");
124			return BPF_DROP;
125		}
126	}
127
128	ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
129	if (ret < 0) {
130		printk("bpf_l3_csum_replace failed: %d\n", ret);
131		return BPF_DROP;
132	}
133
134	if (rw_daddr)
135		ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
136	else
137		ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
138
139	if (ret < 0) {
140		printk("bpf_skb_store_bytes() failed: %d\n", ret);
141		return BPF_DROP;
142	}
143
144	return BPF_OK;
145}
146
147/* Test: Verify skb data can be modified */
148SEC("test_rewrite")
149int do_test_rewrite(struct __sk_buff *skb)
150{
151	uint32_t old_ip, new_ip = 0x3fea8c0;
152	int ret;
153
154	ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
155	if (ret < 0) {
156		printk("bpf_skb_load_bytes failed: %d\n", ret);
157		return BPF_DROP;
158	}
159
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);
163	}
164
165	return BPF_OK;
166}
167
168static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
169{
170	uint64_t smac = SRC_MAC, dmac = DST_MAC;
171	int ret, ifindex = DST_IFINDEX;
172	struct ethhdr ehdr;
173
174	ret = bpf_skb_change_head(skb, 14, 0);
175	if (ret < 0) {
176		printk("skb_change_head() failed: %d\n", ret);
177	}
178
179	ehdr.h_proto = __constant_htons(ETH_P_IP);
180	memcpy(&ehdr.h_source, &smac, 6);
181	memcpy(&ehdr.h_dest, &dmac, 6);
182
183	ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
184	if (ret < 0) {
185		printk("skb_store_bytes() failed: %d\n", ret);
186		return BPF_DROP;
187	}
188
189	return bpf_redirect(ifindex, 0);
190}
191
192SEC("push_ll_and_redirect_silent")
193int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
194{
195	return __do_push_ll_and_redirect(skb);
196}
197
198SEC("push_ll_and_redirect")
199int do_push_ll_and_redirect(struct __sk_buff *skb)
200{
201	int ret, ifindex = DST_IFINDEX;
202
203	ret = __do_push_ll_and_redirect(skb);
204	if (ret >= 0)
205		printk("redirected to %d\n", ifindex);
206
207	return ret;
208}
209
210static inline void __fill_garbage(struct __sk_buff *skb)
211{
212	uint64_t f = 0xFFFFFFFFFFFFFFFF;
213
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);
226}
227
228SEC("fill_garbage")
229int do_fill_garbage(struct __sk_buff *skb)
230{
231	__fill_garbage(skb);
232	printk("Set initial 96 bytes of header to FF\n");
233	return BPF_OK;
234}
235
236SEC("fill_garbage_and_redirect")
237int do_fill_garbage_and_redirect(struct __sk_buff *skb)
238{
239	int ifindex = DST_IFINDEX;
240	__fill_garbage(skb);
241	printk("redirected to %d\n", ifindex);
242	return bpf_redirect(ifindex, 0);
243}
244
245/* Drop all packets */
246SEC("drop_all")
247int do_drop_all(struct __sk_buff *skb)
248{
249	printk("dropping with: %d\n", BPF_DROP);
250	return BPF_DROP;
251}
252
253char _license[] SEC("license") = "GPL";