]>
Commit | Line | Data |
---|---|---|
90e02896 MKL |
1 | /* Copyright (c) 2016 Facebook |
2 | * | |
3 | * This program is free software; you can redistribute it and/or | |
4 | * modify it under the terms of version 2 of the GNU General Public | |
5 | * License as published by the Free Software Foundation. | |
6 | */ | |
cdb749ce | 7 | #define KBUILD_MODNAME "foo" |
90e02896 MKL |
8 | #include <uapi/linux/bpf.h> |
9 | #include <uapi/linux/if_ether.h> | |
10 | #include <uapi/linux/if_packet.h> | |
11 | #include <uapi/linux/ip.h> | |
12 | #include <uapi/linux/ipv6.h> | |
13 | #include <uapi/linux/in.h> | |
14 | #include <uapi/linux/tcp.h> | |
15 | #include <uapi/linux/filter.h> | |
16 | #include <uapi/linux/pkt_cls.h> | |
17 | #include <net/ipv6.h> | |
18 | #include "bpf_helpers.h" | |
19 | ||
20 | #define _htonl __builtin_bswap32 | |
21 | ||
22 | #define PIN_GLOBAL_NS 2 | |
23 | struct bpf_elf_map { | |
24 | __u32 type; | |
25 | __u32 size_key; | |
26 | __u32 size_value; | |
27 | __u32 max_elem; | |
28 | __u32 flags; | |
29 | __u32 id; | |
30 | __u32 pinning; | |
31 | }; | |
32 | ||
33 | /* copy of 'struct ethhdr' without __packed */ | |
34 | struct eth_hdr { | |
35 | unsigned char h_dest[ETH_ALEN]; | |
36 | unsigned char h_source[ETH_ALEN]; | |
37 | unsigned short h_proto; | |
38 | }; | |
39 | ||
40 | struct bpf_elf_map SEC("maps") tun_iface = { | |
41 | .type = BPF_MAP_TYPE_ARRAY, | |
42 | .size_key = sizeof(int), | |
43 | .size_value = sizeof(int), | |
44 | .pinning = PIN_GLOBAL_NS, | |
45 | .max_elem = 1, | |
46 | }; | |
47 | ||
48 | static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr) | |
49 | { | |
50 | if (eth_proto == htons(ETH_P_IP)) | |
51 | return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100); | |
52 | else if (eth_proto == htons(ETH_P_IPV6)) | |
53 | return (daddr == _htonl(0x2401face)); | |
54 | ||
55 | return false; | |
56 | } | |
57 | ||
58 | SEC("l2_to_iptun_ingress_forward") | |
59 | int _l2_to_iptun_ingress_forward(struct __sk_buff *skb) | |
60 | { | |
61 | struct bpf_tunnel_key tkey = {}; | |
62 | void *data = (void *)(long)skb->data; | |
63 | struct eth_hdr *eth = data; | |
64 | void *data_end = (void *)(long)skb->data_end; | |
65 | int key = 0, *ifindex; | |
66 | ||
67 | int ret; | |
68 | ||
69 | if (data + sizeof(*eth) > data_end) | |
70 | return TC_ACT_OK; | |
71 | ||
72 | ifindex = bpf_map_lookup_elem(&tun_iface, &key); | |
73 | if (!ifindex) | |
74 | return TC_ACT_OK; | |
75 | ||
76 | if (eth->h_proto == htons(ETH_P_IP)) { | |
77 | char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n"; | |
78 | struct iphdr *iph = data + sizeof(*eth); | |
79 | ||
80 | if (data + sizeof(*eth) + sizeof(*iph) > data_end) | |
81 | return TC_ACT_OK; | |
82 | ||
83 | if (iph->protocol != IPPROTO_IPIP) | |
84 | return TC_ACT_OK; | |
85 | ||
86 | bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex, | |
87 | _htonl(iph->daddr)); | |
88 | return bpf_redirect(*ifindex, BPF_F_INGRESS); | |
89 | } else if (eth->h_proto == htons(ETH_P_IPV6)) { | |
90 | char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n"; | |
91 | struct ipv6hdr *ip6h = data + sizeof(*eth); | |
92 | ||
93 | if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) | |
94 | return TC_ACT_OK; | |
95 | ||
96 | if (ip6h->nexthdr != IPPROTO_IPIP && | |
97 | ip6h->nexthdr != IPPROTO_IPV6) | |
98 | return TC_ACT_OK; | |
99 | ||
100 | bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex, | |
101 | _htonl(ip6h->daddr.s6_addr32[0]), | |
102 | _htonl(ip6h->daddr.s6_addr32[3])); | |
103 | return bpf_redirect(*ifindex, BPF_F_INGRESS); | |
104 | } | |
105 | ||
106 | return TC_ACT_OK; | |
107 | } | |
108 | ||
109 | SEC("l2_to_iptun_ingress_redirect") | |
110 | int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb) | |
111 | { | |
112 | struct bpf_tunnel_key tkey = {}; | |
113 | void *data = (void *)(long)skb->data; | |
114 | struct eth_hdr *eth = data; | |
115 | void *data_end = (void *)(long)skb->data_end; | |
116 | int key = 0, *ifindex; | |
117 | ||
118 | int ret; | |
119 | ||
120 | if (data + sizeof(*eth) > data_end) | |
121 | return TC_ACT_OK; | |
122 | ||
123 | ifindex = bpf_map_lookup_elem(&tun_iface, &key); | |
124 | if (!ifindex) | |
125 | return TC_ACT_OK; | |
126 | ||
127 | if (eth->h_proto == htons(ETH_P_IP)) { | |
128 | char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n"; | |
129 | struct iphdr *iph = data + sizeof(*eth); | |
130 | __be32 daddr = iph->daddr; | |
131 | ||
132 | if (data + sizeof(*eth) + sizeof(*iph) > data_end) | |
133 | return TC_ACT_OK; | |
134 | ||
135 | if (!is_vip_addr(eth->h_proto, daddr)) | |
136 | return TC_ACT_OK; | |
137 | ||
138 | bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex); | |
139 | } else { | |
140 | return TC_ACT_OK; | |
141 | } | |
142 | ||
143 | tkey.tunnel_id = 10000; | |
144 | tkey.tunnel_ttl = 64; | |
145 | tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */ | |
146 | bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0); | |
147 | return bpf_redirect(*ifindex, 0); | |
148 | } | |
149 | ||
150 | SEC("l2_to_ip6tun_ingress_redirect") | |
151 | int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb) | |
152 | { | |
153 | struct bpf_tunnel_key tkey = {}; | |
154 | void *data = (void *)(long)skb->data; | |
155 | struct eth_hdr *eth = data; | |
156 | void *data_end = (void *)(long)skb->data_end; | |
157 | int key = 0, *ifindex; | |
158 | ||
159 | if (data + sizeof(*eth) > data_end) | |
160 | return TC_ACT_OK; | |
161 | ||
162 | ifindex = bpf_map_lookup_elem(&tun_iface, &key); | |
163 | if (!ifindex) | |
164 | return TC_ACT_OK; | |
165 | ||
166 | if (eth->h_proto == htons(ETH_P_IP)) { | |
167 | char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n"; | |
168 | struct iphdr *iph = data + sizeof(*eth); | |
169 | ||
170 | if (data + sizeof(*eth) + sizeof(*iph) > data_end) | |
171 | return TC_ACT_OK; | |
172 | ||
173 | if (!is_vip_addr(eth->h_proto, iph->daddr)) | |
174 | return TC_ACT_OK; | |
175 | ||
176 | bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr), | |
177 | *ifindex); | |
178 | } else if (eth->h_proto == htons(ETH_P_IPV6)) { | |
179 | char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n"; | |
180 | struct ipv6hdr *ip6h = data + sizeof(*eth); | |
181 | ||
182 | if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) | |
183 | return TC_ACT_OK; | |
184 | ||
185 | if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0])) | |
186 | return TC_ACT_OK; | |
187 | ||
188 | bpf_trace_printk(fmt6, sizeof(fmt6), | |
189 | _htonl(ip6h->daddr.s6_addr32[0]), *ifindex); | |
190 | } else { | |
191 | return TC_ACT_OK; | |
192 | } | |
193 | ||
194 | tkey.tunnel_id = 10000; | |
195 | tkey.tunnel_ttl = 64; | |
196 | /* 2401:db02:0:0:0:0:0:66 */ | |
197 | tkey.remote_ipv6[0] = _htonl(0x2401db02); | |
198 | tkey.remote_ipv6[1] = 0; | |
199 | tkey.remote_ipv6[2] = 0; | |
200 | tkey.remote_ipv6[3] = _htonl(0x00000066); | |
201 | bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6); | |
202 | return bpf_redirect(*ifindex, 0); | |
203 | } | |
204 | ||
205 | SEC("drop_non_tun_vip") | |
206 | int _drop_non_tun_vip(struct __sk_buff *skb) | |
207 | { | |
208 | struct bpf_tunnel_key tkey = {}; | |
209 | void *data = (void *)(long)skb->data; | |
210 | struct eth_hdr *eth = data; | |
211 | void *data_end = (void *)(long)skb->data_end; | |
212 | ||
213 | if (data + sizeof(*eth) > data_end) | |
214 | return TC_ACT_OK; | |
215 | ||
216 | if (eth->h_proto == htons(ETH_P_IP)) { | |
217 | struct iphdr *iph = data + sizeof(*eth); | |
218 | ||
219 | if (data + sizeof(*eth) + sizeof(*iph) > data_end) | |
220 | return TC_ACT_OK; | |
221 | ||
222 | if (is_vip_addr(eth->h_proto, iph->daddr)) | |
223 | return TC_ACT_SHOT; | |
224 | } else if (eth->h_proto == htons(ETH_P_IPV6)) { | |
225 | struct ipv6hdr *ip6h = data + sizeof(*eth); | |
226 | ||
227 | if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) | |
228 | return TC_ACT_OK; | |
229 | ||
230 | if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0])) | |
231 | return TC_ACT_SHOT; | |
232 | } | |
233 | ||
234 | return TC_ACT_OK; | |
235 | } | |
236 | ||
237 | char _license[] SEC("license") = "GPL"; |