123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /* Copyright (c) 2016 Thomas Graf <[email protected]>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
- #include <stdint.h>
- #include <stddef.h>
- #include <linux/bpf.h>
- #include <linux/ip.h>
- #include <linux/in.h>
- #include <linux/in6.h>
- #include <linux/tcp.h>
- #include <linux/udp.h>
- #include <linux/icmpv6.h>
- #include <linux/if_ether.h>
- #include <bpf/bpf_helpers.h>
- #include <string.h>
- # define printk(fmt, ...) \
- ({ \
- char ____fmt[] = fmt; \
- bpf_trace_printk(____fmt, sizeof(____fmt), \
- ##__VA_ARGS__); \
- })
- #define CB_MAGIC 1234
- /* Test: Pass all packets through */
- SEC("nop")
- int do_nop(struct __sk_buff *skb)
- {
- return BPF_OK;
- }
- /* Test: Verify context information can be accessed */
- SEC("test_ctx")
- int do_test_ctx(struct __sk_buff *skb)
- {
- skb->cb[0] = CB_MAGIC;
- printk("len %d hash %d protocol %d\n", skb->len, skb->hash,
- skb->protocol);
- printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0],
- skb->ingress_ifindex, skb->ifindex);
- return BPF_OK;
- }
- /* Test: Ensure skb->cb[] buffer is cleared */
- SEC("test_cb")
- int do_test_cb(struct __sk_buff *skb)
- {
- printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1],
- skb->cb[2]);
- printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]);
- return BPF_OK;
- }
- /* Test: Verify skb data can be read */
- SEC("test_data")
- int do_test_data(struct __sk_buff *skb)
- {
- void *data = (void *)(long)skb->data;
- void *data_end = (void *)(long)skb->data_end;
- struct iphdr *iph = data;
- if (data + sizeof(*iph) > data_end) {
- printk("packet truncated\n");
- return BPF_DROP;
- }
- printk("src: %x dst: %x\n", iph->saddr, iph->daddr);
- return BPF_OK;
- }
- #define IP_CSUM_OFF offsetof(struct iphdr, check)
- #define IP_DST_OFF offsetof(struct iphdr, daddr)
- #define IP_SRC_OFF offsetof(struct iphdr, saddr)
- #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
- #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
- #define UDP_CSUM_OFF offsetof(struct udphdr, check)
- #define IS_PSEUDO 0x10
- static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
- uint32_t new_ip, int rw_daddr)
- {
- int ret, off = 0, flags = IS_PSEUDO;
- uint8_t proto;
- ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
- if (ret < 0) {
- printk("bpf_l4_csum_replace failed: %d\n", ret);
- return BPF_DROP;
- }
- switch (proto) {
- case IPPROTO_TCP:
- off = TCP_CSUM_OFF;
- break;
- case IPPROTO_UDP:
- off = UDP_CSUM_OFF;
- flags |= BPF_F_MARK_MANGLED_0;
- break;
- case IPPROTO_ICMPV6:
- off = offsetof(struct icmp6hdr, icmp6_cksum);
- break;
- }
- if (off) {
- ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
- flags | sizeof(new_ip));
- if (ret < 0) {
- printk("bpf_l4_csum_replace failed: %d\n");
- return BPF_DROP;
- }
- }
- ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
- if (ret < 0) {
- printk("bpf_l3_csum_replace failed: %d\n", ret);
- return BPF_DROP;
- }
- if (rw_daddr)
- ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
- else
- ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
- if (ret < 0) {
- printk("bpf_skb_store_bytes() failed: %d\n", ret);
- return BPF_DROP;
- }
- return BPF_OK;
- }
- /* Test: Verify skb data can be modified */
- SEC("test_rewrite")
- int do_test_rewrite(struct __sk_buff *skb)
- {
- uint32_t old_ip, new_ip = 0x3fea8c0;
- int ret;
- ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
- if (ret < 0) {
- printk("bpf_skb_load_bytes failed: %d\n", ret);
- return BPF_DROP;
- }
- if (old_ip == 0x2fea8c0) {
- printk("out: rewriting from %x to %x\n", old_ip, new_ip);
- return rewrite(skb, old_ip, new_ip, 1);
- }
- return BPF_OK;
- }
- static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
- {
- uint64_t smac = SRC_MAC, dmac = DST_MAC;
- int ret, ifindex = DST_IFINDEX;
- struct ethhdr ehdr;
- ret = bpf_skb_change_head(skb, 14, 0);
- if (ret < 0) {
- printk("skb_change_head() failed: %d\n", ret);
- }
- ehdr.h_proto = __constant_htons(ETH_P_IP);
- memcpy(&ehdr.h_source, &smac, 6);
- memcpy(&ehdr.h_dest, &dmac, 6);
- ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
- if (ret < 0) {
- printk("skb_store_bytes() failed: %d\n", ret);
- return BPF_DROP;
- }
- return bpf_redirect(ifindex, 0);
- }
- SEC("push_ll_and_redirect_silent")
- int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
- {
- return __do_push_ll_and_redirect(skb);
- }
- SEC("push_ll_and_redirect")
- int do_push_ll_and_redirect(struct __sk_buff *skb)
- {
- int ret, ifindex = DST_IFINDEX;
- ret = __do_push_ll_and_redirect(skb);
- if (ret >= 0)
- printk("redirected to %d\n", ifindex);
- return ret;
- }
- static inline void __fill_garbage(struct __sk_buff *skb)
- {
- uint64_t f = 0xFFFFFFFFFFFFFFFF;
- bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
- bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
- }
- SEC("fill_garbage")
- int do_fill_garbage(struct __sk_buff *skb)
- {
- __fill_garbage(skb);
- printk("Set initial 96 bytes of header to FF\n");
- return BPF_OK;
- }
- SEC("fill_garbage_and_redirect")
- int do_fill_garbage_and_redirect(struct __sk_buff *skb)
- {
- int ifindex = DST_IFINDEX;
- __fill_garbage(skb);
- printk("redirected to %d\n", ifindex);
- return bpf_redirect(ifindex, 0);
- }
- /* Drop all packets */
- SEC("drop_all")
- int do_drop_all(struct __sk_buff *skb)
- {
- printk("dropping with: %d\n", BPF_DROP);
- return BPF_DROP;
- }
- char _license[] SEC("license") = "GPL";
|