Back to home page

OSCL-LXR

 
 

    


0001 /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
0002  *
0003  * This program is free software; you can redistribute it and/or
0004  * modify it under the terms of version 2 of the GNU General Public
0005  * License as published by the Free Software Foundation.
0006  *
0007  * This program is distributed in the hope that it will be useful, but
0008  * WITHOUT ANY WARRANTY; without even the implied warranty of
0009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0010  * General Public License for more details.
0011  */
0012 
0013 #include <stdint.h>
0014 #include <stddef.h>
0015 #include <linux/bpf.h>
0016 #include <linux/ip.h>
0017 #include <linux/in.h>
0018 #include <linux/in6.h>
0019 #include <linux/tcp.h>
0020 #include <linux/udp.h>
0021 #include <linux/icmpv6.h>
0022 #include <linux/if_ether.h>
0023 #include <bpf/bpf_helpers.h>
0024 #include <string.h>
0025 
0026 # define printk(fmt, ...)                       \
0027         ({                          \
0028             char ____fmt[] = fmt;               \
0029             bpf_trace_printk(____fmt, sizeof(____fmt),  \
0030                      ##__VA_ARGS__);            \
0031         })
0032 
0033 #define CB_MAGIC 1234
0034 
0035 /* Test: Pass all packets through */
0036 SEC("nop")
0037 int do_nop(struct __sk_buff *skb)
0038 {
0039     return BPF_OK;
0040 }
0041 
0042 /* Test: Verify context information can be accessed */
0043 SEC("test_ctx")
0044 int do_test_ctx(struct __sk_buff *skb)
0045 {
0046     skb->cb[0] = CB_MAGIC;
0047     printk("len %d hash %d protocol %d\n", skb->len, skb->hash,
0048            skb->protocol);
0049     printk("cb %d ingress_ifindex %d ifindex %d\n", skb->cb[0],
0050            skb->ingress_ifindex, skb->ifindex);
0051 
0052     return BPF_OK;
0053 }
0054 
0055 /* Test: Ensure skb->cb[] buffer is cleared */
0056 SEC("test_cb")
0057 int do_test_cb(struct __sk_buff *skb)
0058 {
0059     printk("cb0: %x cb1: %x cb2: %x\n", skb->cb[0], skb->cb[1],
0060            skb->cb[2]);
0061     printk("cb3: %x cb4: %x\n", skb->cb[3], skb->cb[4]);
0062 
0063     return BPF_OK;
0064 }
0065 
0066 /* Test: Verify skb data can be read */
0067 SEC("test_data")
0068 int do_test_data(struct __sk_buff *skb)
0069 {
0070     void *data = (void *)(long)skb->data;
0071     void *data_end = (void *)(long)skb->data_end;
0072     struct iphdr *iph = data;
0073 
0074     if (data + sizeof(*iph) > data_end) {
0075         printk("packet truncated\n");
0076         return BPF_DROP;
0077     }
0078 
0079     printk("src: %x dst: %x\n", iph->saddr, iph->daddr);
0080 
0081     return BPF_OK;
0082 }
0083 
0084 #define IP_CSUM_OFF offsetof(struct iphdr, check)
0085 #define IP_DST_OFF offsetof(struct iphdr, daddr)
0086 #define IP_SRC_OFF offsetof(struct iphdr, saddr)
0087 #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
0088 #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
0089 #define UDP_CSUM_OFF offsetof(struct udphdr, check)
0090 #define IS_PSEUDO 0x10
0091 
0092 static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
0093               uint32_t new_ip, int rw_daddr)
0094 {
0095     int ret, off = 0, flags = IS_PSEUDO;
0096     uint8_t proto;
0097 
0098     ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
0099     if (ret < 0) {
0100         printk("bpf_l4_csum_replace failed: %d\n", ret);
0101         return BPF_DROP;
0102     }
0103 
0104     switch (proto) {
0105     case IPPROTO_TCP:
0106         off = TCP_CSUM_OFF;
0107         break;
0108 
0109     case IPPROTO_UDP:
0110         off = UDP_CSUM_OFF;
0111         flags |= BPF_F_MARK_MANGLED_0;
0112         break;
0113 
0114     case IPPROTO_ICMPV6:
0115         off = offsetof(struct icmp6hdr, icmp6_cksum);
0116         break;
0117     }
0118 
0119     if (off) {
0120         ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
0121                       flags | sizeof(new_ip));
0122         if (ret < 0) {
0123             printk("bpf_l4_csum_replace failed: %d\n");
0124             return BPF_DROP;
0125         }
0126     }
0127 
0128     ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
0129     if (ret < 0) {
0130         printk("bpf_l3_csum_replace failed: %d\n", ret);
0131         return BPF_DROP;
0132     }
0133 
0134     if (rw_daddr)
0135         ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
0136     else
0137         ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
0138 
0139     if (ret < 0) {
0140         printk("bpf_skb_store_bytes() failed: %d\n", ret);
0141         return BPF_DROP;
0142     }
0143 
0144     return BPF_OK;
0145 }
0146 
0147 /* Test: Verify skb data can be modified */
0148 SEC("test_rewrite")
0149 int do_test_rewrite(struct __sk_buff *skb)
0150 {
0151     uint32_t old_ip, new_ip = 0x3fea8c0;
0152     int ret;
0153 
0154     ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
0155     if (ret < 0) {
0156         printk("bpf_skb_load_bytes failed: %d\n", ret);
0157         return BPF_DROP;
0158     }
0159 
0160     if (old_ip == 0x2fea8c0) {
0161         printk("out: rewriting from %x to %x\n", old_ip, new_ip);
0162         return rewrite(skb, old_ip, new_ip, 1);
0163     }
0164 
0165     return BPF_OK;
0166 }
0167 
0168 static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
0169 {
0170     uint64_t smac = SRC_MAC, dmac = DST_MAC;
0171     int ret, ifindex = DST_IFINDEX;
0172     struct ethhdr ehdr;
0173 
0174     ret = bpf_skb_change_head(skb, 14, 0);
0175     if (ret < 0) {
0176         printk("skb_change_head() failed: %d\n", ret);
0177     }
0178 
0179     ehdr.h_proto = __constant_htons(ETH_P_IP);
0180     memcpy(&ehdr.h_source, &smac, 6);
0181     memcpy(&ehdr.h_dest, &dmac, 6);
0182 
0183     ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
0184     if (ret < 0) {
0185         printk("skb_store_bytes() failed: %d\n", ret);
0186         return BPF_DROP;
0187     }
0188 
0189     return bpf_redirect(ifindex, 0);
0190 }
0191 
0192 SEC("push_ll_and_redirect_silent")
0193 int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
0194 {
0195     return __do_push_ll_and_redirect(skb);
0196 }
0197 
0198 SEC("push_ll_and_redirect")
0199 int do_push_ll_and_redirect(struct __sk_buff *skb)
0200 {
0201     int ret, ifindex = DST_IFINDEX;
0202 
0203     ret = __do_push_ll_and_redirect(skb);
0204     if (ret >= 0)
0205         printk("redirected to %d\n", ifindex);
0206 
0207     return ret;
0208 }
0209 
0210 static inline void __fill_garbage(struct __sk_buff *skb)
0211 {
0212     uint64_t f = 0xFFFFFFFFFFFFFFFF;
0213 
0214     bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
0215     bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
0216     bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
0217     bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
0218     bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
0219     bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
0220     bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
0221     bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
0222     bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
0223     bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
0224     bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
0225     bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
0226 }
0227 
0228 SEC("fill_garbage")
0229 int do_fill_garbage(struct __sk_buff *skb)
0230 {
0231     __fill_garbage(skb);
0232     printk("Set initial 96 bytes of header to FF\n");
0233     return BPF_OK;
0234 }
0235 
0236 SEC("fill_garbage_and_redirect")
0237 int do_fill_garbage_and_redirect(struct __sk_buff *skb)
0238 {
0239     int ifindex = DST_IFINDEX;
0240     __fill_garbage(skb);
0241     printk("redirected to %d\n", ifindex);
0242     return bpf_redirect(ifindex, 0);
0243 }
0244 
0245 /* Drop all packets */
0246 SEC("drop_all")
0247 int do_drop_all(struct __sk_buff *skb)
0248 {
0249     printk("dropping with: %d\n", BPF_DROP);
0250     return BPF_DROP;
0251 }
0252 
0253 char _license[] SEC("license") = "GPL";