brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 9a13dbb Raw
246 lines · c
1/* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>2 *3 * This program is free software; you can redistribute it and/or4 * modify it under the terms of version 2 of the GNU General Public5 * License as published by the Free Software Foundation.6 *7 * This program is distributed in the hope that it will be useful, but8 * WITHOUT ANY WARRANTY; without even the implied warranty of9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU10 * General Public License for more details.11 */12 13#include "vmlinux.h"14#include "net_shared.h"15#include <bpf/bpf_helpers.h>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 123426 27/* Test: Pass all packets through */28SEC("nop")29int do_nop(struct __sk_buff *skb)30{31	return BPF_OK;32}33 34/* Test: Verify context information can be accessed */35SEC("test_ctx")36int do_test_ctx(struct __sk_buff *skb)37{38	skb->cb[0] = CB_MAGIC;39	printk("len %d hash %d protocol %d", skb->len, skb->hash,40	       skb->protocol);41	printk("cb %d ingress_ifindex %d ifindex %d", skb->cb[0],42	       skb->ingress_ifindex, skb->ifindex);43 44	return BPF_OK;45}46 47/* Test: Ensure skb->cb[] buffer is cleared */48SEC("test_cb")49int do_test_cb(struct __sk_buff *skb)50{51	printk("cb0: %x cb1: %x cb2: %x", skb->cb[0], skb->cb[1],52	       skb->cb[2]);53	printk("cb3: %x cb4: %x", skb->cb[3], skb->cb[4]);54 55	return BPF_OK;56}57 58/* Test: Verify skb data can be read */59SEC("test_data")60int 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) {67		printk("packet truncated");68		return BPF_DROP;69	}70 71	printk("src: %x dst: %x", iph->saddr, iph->daddr);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 0x1083 84static 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) {92		printk("bpf_l4_csum_replace failed: %d", ret);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) {115			printk("bpf_l4_csum_replace failed: %d");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) {122		printk("bpf_l3_csum_replace failed: %d", ret);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	else129		ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);130 131	if (ret < 0) {132		printk("bpf_skb_store_bytes() failed: %d", ret);133		return BPF_DROP;134	}135 136	return BPF_OK;137}138 139/* Test: Verify skb data can be modified */140SEC("test_rewrite")141int 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) {148		printk("bpf_skb_load_bytes failed: %d", ret);149		return BPF_DROP;150	}151 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);155	}156 157	return BPF_OK;158}159 160static 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) {168		printk("skb_change_head() failed: %d", ret);169	}170 171	ehdr.h_proto = bpf_htons(ETH_P_IP);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) {177		printk("skb_store_bytes() failed: %d", ret);178		return BPF_DROP;179	}180 181	return bpf_redirect(ifindex, 0);182}183 184SEC("push_ll_and_redirect_silent")185int do_push_ll_and_redirect_silent(struct __sk_buff *skb)186{187	return __do_push_ll_and_redirect(skb);188}189 190SEC("push_ll_and_redirect")191int 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)197		printk("redirected to %d", ifindex);198 199	return ret;200}201 202static 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 220SEC("fill_garbage")221int do_fill_garbage(struct __sk_buff *skb)222{223	__fill_garbage(skb);224	printk("Set initial 96 bytes of header to FF");225	return BPF_OK;226}227 228SEC("fill_garbage_and_redirect")229int do_fill_garbage_and_redirect(struct __sk_buff *skb)230{231	int ifindex = DST_IFINDEX;232	__fill_garbage(skb);233	printk("redirected to %d", ifindex);234	return bpf_redirect(ifindex, 0);235}236 237/* Drop all packets */238SEC("drop_all")239int do_drop_all(struct __sk_buff *skb)240{241	printk("dropping with: %d", BPF_DROP);242	return BPF_DROP;243}244 245char _license[] SEC("license") = "GPL";246