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