18c2ecf20Sopenharmony_ci/* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
48c2ecf20Sopenharmony_ci * modify it under the terms of version 2 of the GNU General Public
58c2ecf20Sopenharmony_ci * License as published by the Free Software Foundation.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
88c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
98c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
108c2ecf20Sopenharmony_ci * General Public License for more details.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <stdint.h>
148c2ecf20Sopenharmony_ci#include <stddef.h>
158c2ecf20Sopenharmony_ci#include <linux/bpf.h>
168c2ecf20Sopenharmony_ci#include <linux/ip.h>
178c2ecf20Sopenharmony_ci#include <linux/in.h>
188c2ecf20Sopenharmony_ci#include <linux/in6.h>
198c2ecf20Sopenharmony_ci#include <linux/tcp.h>
208c2ecf20Sopenharmony_ci#include <linux/udp.h>
218c2ecf20Sopenharmony_ci#include <linux/icmpv6.h>
228c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
238c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h>
248c2ecf20Sopenharmony_ci#include <string.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci# define printk(fmt, ...)						\
278c2ecf20Sopenharmony_ci		({							\
288c2ecf20Sopenharmony_ci			char ____fmt[] = fmt;				\
298c2ecf20Sopenharmony_ci			bpf_trace_printk(____fmt, sizeof(____fmt),	\
308c2ecf20Sopenharmony_ci				     ##__VA_ARGS__);			\
318c2ecf20Sopenharmony_ci		})
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define CB_MAGIC 1234
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Test: Pass all packets through */
368c2ecf20Sopenharmony_ciSEC("nop")
378c2ecf20Sopenharmony_ciint do_nop(struct __sk_buff *skb)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	return BPF_OK;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* Test: Verify context information can be accessed */
438c2ecf20Sopenharmony_ciSEC("test_ctx")
448c2ecf20Sopenharmony_ciint do_test_ctx(struct __sk_buff *skb)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	skb->cb[0] = CB_MAGIC;
478c2ecf20Sopenharmony_ci	printk("len %d hash %d protocol %d\n", skb->len, skb->hash,
488c2ecf20Sopenharmony_ci	       skb->protocol);
498c2ecf20Sopenharmony_ci	printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0],
508c2ecf20Sopenharmony_ci	       skb->ingress_ifindex, skb->ifindex);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return BPF_OK;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Test: Ensure skb->cb[] buffer is cleared */
568c2ecf20Sopenharmony_ciSEC("test_cb")
578c2ecf20Sopenharmony_ciint do_test_cb(struct __sk_buff *skb)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1],
608c2ecf20Sopenharmony_ci	       skb->cb[2]);
618c2ecf20Sopenharmony_ci	printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return BPF_OK;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/* Test: Verify skb data can be read */
678c2ecf20Sopenharmony_ciSEC("test_data")
688c2ecf20Sopenharmony_ciint do_test_data(struct __sk_buff *skb)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	void *data = (void *)(long)skb->data;
718c2ecf20Sopenharmony_ci	void *data_end = (void *)(long)skb->data_end;
728c2ecf20Sopenharmony_ci	struct iphdr *iph = data;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (data + sizeof(*iph) > data_end) {
758c2ecf20Sopenharmony_ci		printk("packet truncated\n");
768c2ecf20Sopenharmony_ci		return BPF_DROP;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	printk("src: %x dst: %x\n", iph->saddr, iph->daddr);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return BPF_OK;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define IP_CSUM_OFF offsetof(struct iphdr, check)
858c2ecf20Sopenharmony_ci#define IP_DST_OFF offsetof(struct iphdr, daddr)
868c2ecf20Sopenharmony_ci#define IP_SRC_OFF offsetof(struct iphdr, saddr)
878c2ecf20Sopenharmony_ci#define IP_PROTO_OFF offsetof(struct iphdr, protocol)
888c2ecf20Sopenharmony_ci#define TCP_CSUM_OFF offsetof(struct tcphdr, check)
898c2ecf20Sopenharmony_ci#define UDP_CSUM_OFF offsetof(struct udphdr, check)
908c2ecf20Sopenharmony_ci#define IS_PSEUDO 0x10
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
938c2ecf20Sopenharmony_ci			  uint32_t new_ip, int rw_daddr)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	int ret, off = 0, flags = IS_PSEUDO;
968c2ecf20Sopenharmony_ci	uint8_t proto;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
998c2ecf20Sopenharmony_ci	if (ret < 0) {
1008c2ecf20Sopenharmony_ci		printk("bpf_l4_csum_replace failed: %d\n", ret);
1018c2ecf20Sopenharmony_ci		return BPF_DROP;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	switch (proto) {
1058c2ecf20Sopenharmony_ci	case IPPROTO_TCP:
1068c2ecf20Sopenharmony_ci		off = TCP_CSUM_OFF;
1078c2ecf20Sopenharmony_ci		break;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	case IPPROTO_UDP:
1108c2ecf20Sopenharmony_ci		off = UDP_CSUM_OFF;
1118c2ecf20Sopenharmony_ci		flags |= BPF_F_MARK_MANGLED_0;
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	case IPPROTO_ICMPV6:
1158c2ecf20Sopenharmony_ci		off = offsetof(struct icmp6hdr, icmp6_cksum);
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (off) {
1208c2ecf20Sopenharmony_ci		ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
1218c2ecf20Sopenharmony_ci					  flags | sizeof(new_ip));
1228c2ecf20Sopenharmony_ci		if (ret < 0) {
1238c2ecf20Sopenharmony_ci			printk("bpf_l4_csum_replace failed: %d\n");
1248c2ecf20Sopenharmony_ci			return BPF_DROP;
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
1298c2ecf20Sopenharmony_ci	if (ret < 0) {
1308c2ecf20Sopenharmony_ci		printk("bpf_l3_csum_replace failed: %d\n", ret);
1318c2ecf20Sopenharmony_ci		return BPF_DROP;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (rw_daddr)
1358c2ecf20Sopenharmony_ci		ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
1368c2ecf20Sopenharmony_ci	else
1378c2ecf20Sopenharmony_ci		ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (ret < 0) {
1408c2ecf20Sopenharmony_ci		printk("bpf_skb_store_bytes() failed: %d\n", ret);
1418c2ecf20Sopenharmony_ci		return BPF_DROP;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return BPF_OK;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/* Test: Verify skb data can be modified */
1488c2ecf20Sopenharmony_ciSEC("test_rewrite")
1498c2ecf20Sopenharmony_ciint do_test_rewrite(struct __sk_buff *skb)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	uint32_t old_ip, new_ip = 0x3fea8c0;
1528c2ecf20Sopenharmony_ci	int ret;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
1558c2ecf20Sopenharmony_ci	if (ret < 0) {
1568c2ecf20Sopenharmony_ci		printk("bpf_skb_load_bytes failed: %d\n", ret);
1578c2ecf20Sopenharmony_ci		return BPF_DROP;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (old_ip == 0x2fea8c0) {
1618c2ecf20Sopenharmony_ci		printk("out: rewriting from %x to %x\n", old_ip, new_ip);
1628c2ecf20Sopenharmony_ci		return rewrite(skb, old_ip, new_ip, 1);
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return BPF_OK;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	uint64_t smac = SRC_MAC, dmac = DST_MAC;
1718c2ecf20Sopenharmony_ci	int ret, ifindex = DST_IFINDEX;
1728c2ecf20Sopenharmony_ci	struct ethhdr ehdr;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	ret = bpf_skb_change_head(skb, 14, 0);
1758c2ecf20Sopenharmony_ci	if (ret < 0) {
1768c2ecf20Sopenharmony_ci		printk("skb_change_head() failed: %d\n", ret);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ehdr.h_proto = __constant_htons(ETH_P_IP);
1808c2ecf20Sopenharmony_ci	memcpy(&ehdr.h_source, &smac, 6);
1818c2ecf20Sopenharmony_ci	memcpy(&ehdr.h_dest, &dmac, 6);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
1848c2ecf20Sopenharmony_ci	if (ret < 0) {
1858c2ecf20Sopenharmony_ci		printk("skb_store_bytes() failed: %d\n", ret);
1868c2ecf20Sopenharmony_ci		return BPF_DROP;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return bpf_redirect(ifindex, 0);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ciSEC("push_ll_and_redirect_silent")
1938c2ecf20Sopenharmony_ciint do_push_ll_and_redirect_silent(struct __sk_buff *skb)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	return __do_push_ll_and_redirect(skb);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ciSEC("push_ll_and_redirect")
1998c2ecf20Sopenharmony_ciint do_push_ll_and_redirect(struct __sk_buff *skb)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	int ret, ifindex = DST_IFINDEX;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ret = __do_push_ll_and_redirect(skb);
2048c2ecf20Sopenharmony_ci	if (ret >= 0)
2058c2ecf20Sopenharmony_ci		printk("redirected to %d\n", ifindex);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return ret;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic inline void __fill_garbage(struct __sk_buff *skb)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	uint64_t f = 0xFFFFFFFFFFFFFFFF;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
2158c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
2168c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
2178c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
2188c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
2198c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
2208c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
2218c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
2228c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
2238c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
2248c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
2258c2ecf20Sopenharmony_ci	bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ciSEC("fill_garbage")
2298c2ecf20Sopenharmony_ciint do_fill_garbage(struct __sk_buff *skb)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	__fill_garbage(skb);
2328c2ecf20Sopenharmony_ci	printk("Set initial 96 bytes of header to FF\n");
2338c2ecf20Sopenharmony_ci	return BPF_OK;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ciSEC("fill_garbage_and_redirect")
2378c2ecf20Sopenharmony_ciint do_fill_garbage_and_redirect(struct __sk_buff *skb)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int ifindex = DST_IFINDEX;
2408c2ecf20Sopenharmony_ci	__fill_garbage(skb);
2418c2ecf20Sopenharmony_ci	printk("redirected to %d\n", ifindex);
2428c2ecf20Sopenharmony_ci	return bpf_redirect(ifindex, 0);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci/* Drop all packets */
2468c2ecf20Sopenharmony_ciSEC("drop_all")
2478c2ecf20Sopenharmony_ciint do_drop_all(struct __sk_buff *skb)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	printk("dropping with: %d\n", BPF_DROP);
2508c2ecf20Sopenharmony_ci	return BPF_DROP;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cichar _license[] SEC("license") = "GPL";
254