Back to home page

OSCL-LXR

 
 

    


0001 /* Copyright (c) 2016 Facebook
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 #define KBUILD_MODNAME "foo"
0008 #include <uapi/linux/bpf.h>
0009 #include <uapi/linux/if_ether.h>
0010 #include <uapi/linux/if_packet.h>
0011 #include <uapi/linux/ip.h>
0012 #include <uapi/linux/ipv6.h>
0013 #include <uapi/linux/in.h>
0014 #include <uapi/linux/tcp.h>
0015 #include <uapi/linux/filter.h>
0016 #include <uapi/linux/pkt_cls.h>
0017 #include <net/ipv6.h>
0018 #include <bpf/bpf_helpers.h>
0019 
0020 #define _htonl __builtin_bswap32
0021 
0022 #define PIN_GLOBAL_NS       2
0023 struct bpf_elf_map {
0024     __u32 type;
0025     __u32 size_key;
0026     __u32 size_value;
0027     __u32 max_elem;
0028     __u32 flags;
0029     __u32 id;
0030     __u32 pinning;
0031 };
0032 
0033 /* copy of 'struct ethhdr' without __packed */
0034 struct eth_hdr {
0035     unsigned char   h_dest[ETH_ALEN];
0036     unsigned char   h_source[ETH_ALEN];
0037     unsigned short  h_proto;
0038 };
0039 
0040 struct bpf_elf_map SEC("maps") tun_iface = {
0041     .type = BPF_MAP_TYPE_ARRAY,
0042     .size_key = sizeof(int),
0043     .size_value = sizeof(int),
0044     .pinning = PIN_GLOBAL_NS,
0045     .max_elem = 1,
0046 };
0047 
0048 static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr)
0049 {
0050     if (eth_proto == htons(ETH_P_IP))
0051         return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100);
0052     else if (eth_proto == htons(ETH_P_IPV6))
0053         return (daddr == _htonl(0x2401face));
0054 
0055     return false;
0056 }
0057 
0058 SEC("l2_to_iptun_ingress_forward")
0059 int _l2_to_iptun_ingress_forward(struct __sk_buff *skb)
0060 {
0061     struct bpf_tunnel_key tkey = {};
0062     void *data = (void *)(long)skb->data;
0063     struct eth_hdr *eth = data;
0064     void *data_end = (void *)(long)skb->data_end;
0065     int key = 0, *ifindex;
0066 
0067     int ret;
0068 
0069     if (data + sizeof(*eth) > data_end)
0070         return TC_ACT_OK;
0071 
0072     ifindex = bpf_map_lookup_elem(&tun_iface, &key);
0073     if (!ifindex)
0074         return TC_ACT_OK;
0075 
0076     if (eth->h_proto == htons(ETH_P_IP)) {
0077         char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n";
0078         struct iphdr *iph = data + sizeof(*eth);
0079 
0080         if (data + sizeof(*eth) + sizeof(*iph) > data_end)
0081             return TC_ACT_OK;
0082 
0083         if (iph->protocol != IPPROTO_IPIP)
0084             return TC_ACT_OK;
0085 
0086         bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex,
0087                  _htonl(iph->daddr));
0088         return bpf_redirect(*ifindex, BPF_F_INGRESS);
0089     } else if (eth->h_proto == htons(ETH_P_IPV6)) {
0090         char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
0091         struct ipv6hdr *ip6h = data + sizeof(*eth);
0092 
0093         if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
0094             return TC_ACT_OK;
0095 
0096         if (ip6h->nexthdr != IPPROTO_IPIP &&
0097             ip6h->nexthdr != IPPROTO_IPV6)
0098             return TC_ACT_OK;
0099 
0100         bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex,
0101                  _htonl(ip6h->daddr.s6_addr32[0]),
0102                  _htonl(ip6h->daddr.s6_addr32[3]));
0103         return bpf_redirect(*ifindex, BPF_F_INGRESS);
0104     }
0105 
0106     return TC_ACT_OK;
0107 }
0108 
0109 SEC("l2_to_iptun_ingress_redirect")
0110 int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb)
0111 {
0112     struct bpf_tunnel_key tkey = {};
0113     void *data = (void *)(long)skb->data;
0114     struct eth_hdr *eth = data;
0115     void *data_end = (void *)(long)skb->data_end;
0116     int key = 0, *ifindex;
0117 
0118     int ret;
0119 
0120     if (data + sizeof(*eth) > data_end)
0121         return TC_ACT_OK;
0122 
0123     ifindex = bpf_map_lookup_elem(&tun_iface, &key);
0124     if (!ifindex)
0125         return TC_ACT_OK;
0126 
0127     if (eth->h_proto == htons(ETH_P_IP)) {
0128         char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
0129         struct iphdr *iph = data + sizeof(*eth);
0130         __be32 daddr = iph->daddr;
0131 
0132         if (data + sizeof(*eth) + sizeof(*iph) > data_end)
0133             return TC_ACT_OK;
0134 
0135         if (!is_vip_addr(eth->h_proto, daddr))
0136             return TC_ACT_OK;
0137 
0138         bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex);
0139     } else {
0140         return TC_ACT_OK;
0141     }
0142 
0143     tkey.tunnel_id = 10000;
0144     tkey.tunnel_ttl = 64;
0145     tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */
0146     bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0);
0147     return bpf_redirect(*ifindex, 0);
0148 }
0149 
0150 SEC("l2_to_ip6tun_ingress_redirect")
0151 int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb)
0152 {
0153     struct bpf_tunnel_key tkey = {};
0154     void *data = (void *)(long)skb->data;
0155     struct eth_hdr *eth = data;
0156     void *data_end = (void *)(long)skb->data_end;
0157     int key = 0, *ifindex;
0158 
0159     if (data + sizeof(*eth) > data_end)
0160         return TC_ACT_OK;
0161 
0162     ifindex = bpf_map_lookup_elem(&tun_iface, &key);
0163     if (!ifindex)
0164         return TC_ACT_OK;
0165 
0166     if (eth->h_proto == htons(ETH_P_IP)) {
0167         char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
0168         struct iphdr *iph = data + sizeof(*eth);
0169 
0170         if (data + sizeof(*eth) + sizeof(*iph) > data_end)
0171             return TC_ACT_OK;
0172 
0173         if (!is_vip_addr(eth->h_proto, iph->daddr))
0174             return TC_ACT_OK;
0175 
0176         bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr),
0177                  *ifindex);
0178     } else if (eth->h_proto == htons(ETH_P_IPV6)) {
0179         char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
0180         struct ipv6hdr *ip6h = data + sizeof(*eth);
0181 
0182         if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
0183             return TC_ACT_OK;
0184 
0185         if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
0186             return TC_ACT_OK;
0187 
0188         bpf_trace_printk(fmt6, sizeof(fmt6),
0189                  _htonl(ip6h->daddr.s6_addr32[0]), *ifindex);
0190     } else {
0191         return TC_ACT_OK;
0192     }
0193 
0194     tkey.tunnel_id = 10000;
0195     tkey.tunnel_ttl = 64;
0196     /* 2401:db02:0:0:0:0:0:66 */
0197     tkey.remote_ipv6[0] = _htonl(0x2401db02);
0198     tkey.remote_ipv6[1] = 0;
0199     tkey.remote_ipv6[2] = 0;
0200     tkey.remote_ipv6[3] = _htonl(0x00000066);
0201     bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6);
0202     return bpf_redirect(*ifindex, 0);
0203 }
0204 
0205 SEC("drop_non_tun_vip")
0206 int _drop_non_tun_vip(struct __sk_buff *skb)
0207 {
0208     struct bpf_tunnel_key tkey = {};
0209     void *data = (void *)(long)skb->data;
0210     struct eth_hdr *eth = data;
0211     void *data_end = (void *)(long)skb->data_end;
0212 
0213     if (data + sizeof(*eth) > data_end)
0214         return TC_ACT_OK;
0215 
0216     if (eth->h_proto == htons(ETH_P_IP)) {
0217         struct iphdr *iph = data + sizeof(*eth);
0218 
0219         if (data + sizeof(*eth) + sizeof(*iph) > data_end)
0220             return TC_ACT_OK;
0221 
0222         if (is_vip_addr(eth->h_proto, iph->daddr))
0223             return TC_ACT_SHOT;
0224     } else if (eth->h_proto == htons(ETH_P_IPV6)) {
0225         struct ipv6hdr *ip6h = data + sizeof(*eth);
0226 
0227         if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
0228             return TC_ACT_OK;
0229 
0230         if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
0231             return TC_ACT_SHOT;
0232     }
0233 
0234     return TC_ACT_OK;
0235 }
0236 
0237 char _license[] SEC("license") = "GPL";