Warning: That file was not part of the compilation database. It may have many parsing errors.

1// SPDX-License-Identifier: GPL-2.0
2#include <limits.h>
3#include <stddef.h>
4#include <stdbool.h>
5#include <string.h>
6#include <linux/pkt_cls.h>
7#include <linux/bpf.h>
8#include <linux/in.h>
9#include <linux/if_ether.h>
10#include <linux/icmp.h>
11#include <linux/ip.h>
12#include <linux/ipv6.h>
13#include <linux/tcp.h>
14#include <linux/udp.h>
15#include <linux/if_packet.h>
16#include <sys/socket.h>
17#include <linux/if_tunnel.h>
18#include <linux/mpls.h>
19#include "bpf_helpers.h"
20#include "bpf_endian.h"
21
22int _version SEC("version") = 1;
23#define PROG(F) SEC(#F) int bpf_func_##F
24
25/* These are the identifiers of the BPF programs that will be used in tail
26 * calls. Name is limited to 16 characters, with the terminating character and
27 * bpf_func_ above, we have only 6 to work with, anything after will be cropped.
28 */
29enum {
30 IP,
31 IPV6,
32 IPV6OP, /* Destination/Hop-by-Hop Options IPv6 Extension header */
33 IPV6FR, /* Fragmentation IPv6 Extension Header */
34 MPLS,
35 VLAN,
36};
37
38#define IP_MF 0x2000
39#define IP_OFFSET 0x1FFF
40#define IP6_MF 0x0001
41#define IP6_OFFSET 0xFFF8
42
43struct vlan_hdr {
44 __be16 h_vlan_TCI;
45 __be16 h_vlan_encapsulated_proto;
46};
47
48struct gre_hdr {
49 __be16 flags;
50 __be16 proto;
51};
52
53struct frag_hdr {
54 __u8 nexthdr;
55 __u8 reserved;
56 __be16 frag_off;
57 __be32 identification;
58};
59
60struct bpf_map_def SEC("maps") jmp_table = {
61 .type = BPF_MAP_TYPE_PROG_ARRAY,
62 .key_size = sizeof(__u32),
63 .value_size = sizeof(__u32),
64 .max_entries = 8
65};
66
67static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
68 __u16 hdr_size,
69 void *buffer)
70{
71 void *data_end = (void *)(long)skb->data_end;
72 void *data = (void *)(long)skb->data;
73 __u16 thoff = skb->flow_keys->thoff;
74 __u8 *hdr;
75
76 /* Verifies this variable offset does not overflow */
77 if (thoff > (USHRT_MAX - hdr_size))
78 return NULL;
79
80 hdr = data + thoff;
81 if (hdr + hdr_size <= data_end)
82 return hdr;
83
84 if (bpf_skb_load_bytes(skb, thoff, buffer, hdr_size))
85 return NULL;
86
87 return buffer;
88}
89
90/* Dispatches on ETHERTYPE */
91static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto)
92{
93 struct bpf_flow_keys *keys = skb->flow_keys;
94
95 keys->n_proto = proto;
96 switch (proto) {
97 case bpf_htons(ETH_P_IP):
98 bpf_tail_call(skb, &jmp_table, IP);
99 break;
100 case bpf_htons(ETH_P_IPV6):
101 bpf_tail_call(skb, &jmp_table, IPV6);
102 break;
103 case bpf_htons(ETH_P_MPLS_MC):
104 case bpf_htons(ETH_P_MPLS_UC):
105 bpf_tail_call(skb, &jmp_table, MPLS);
106 break;
107 case bpf_htons(ETH_P_8021Q):
108 case bpf_htons(ETH_P_8021AD):
109 bpf_tail_call(skb, &jmp_table, VLAN);
110 break;
111 default:
112 /* Protocol not supported */
113 return BPF_DROP;
114 }
115
116 return BPF_DROP;
117}
118
119SEC("flow_dissector")
120int _dissect(struct __sk_buff *skb)
121{
122 if (!skb->vlan_present)
123 return parse_eth_proto(skb, skb->protocol);
124 else
125 return parse_eth_proto(skb, skb->vlan_proto);
126}
127
128/* Parses on IPPROTO_* */
129static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
130{
131 struct bpf_flow_keys *keys = skb->flow_keys;
132 void *data_end = (void *)(long)skb->data_end;
133 struct icmphdr *icmp, _icmp;
134 struct gre_hdr *gre, _gre;
135 struct ethhdr *eth, _eth;
136 struct tcphdr *tcp, _tcp;
137 struct udphdr *udp, _udp;
138
139 keys->ip_proto = proto;
140 switch (proto) {
141 case IPPROTO_ICMP:
142 icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp);
143 if (!icmp)
144 return BPF_DROP;
145 return BPF_OK;
146 case IPPROTO_IPIP:
147 keys->is_encap = true;
148 return parse_eth_proto(skb, bpf_htons(ETH_P_IP));
149 case IPPROTO_IPV6:
150 keys->is_encap = true;
151 return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6));
152 case IPPROTO_GRE:
153 gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre);
154 if (!gre)
155 return BPF_DROP;
156
157 if (bpf_htons(gre->flags & GRE_VERSION))
158 /* Only inspect standard GRE packets with version 0 */
159 return BPF_OK;
160
161 keys->thoff += sizeof(*gre); /* Step over GRE Flags and Proto */
162 if (GRE_IS_CSUM(gre->flags))
163 keys->thoff += 4; /* Step over chksum and Padding */
164 if (GRE_IS_KEY(gre->flags))
165 keys->thoff += 4; /* Step over key */
166 if (GRE_IS_SEQ(gre->flags))
167 keys->thoff += 4; /* Step over sequence number */
168
169 keys->is_encap = true;
170
171 if (gre->proto == bpf_htons(ETH_P_TEB)) {
172 eth = bpf_flow_dissect_get_header(skb, sizeof(*eth),
173 &_eth);
174 if (!eth)
175 return BPF_DROP;
176
177 keys->thoff += sizeof(*eth);
178
179 return parse_eth_proto(skb, eth->h_proto);
180 } else {
181 return parse_eth_proto(skb, gre->proto);
182 }
183 case IPPROTO_TCP:
184 tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp);
185 if (!tcp)
186 return BPF_DROP;
187
188 if (tcp->doff < 5)
189 return BPF_DROP;
190
191 if ((__u8 *)tcp + (tcp->doff << 2) > data_end)
192 return BPF_DROP;
193
194 keys->sport = tcp->source;
195 keys->dport = tcp->dest;
196 return BPF_OK;
197 case IPPROTO_UDP:
198 case IPPROTO_UDPLITE:
199 udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp);
200 if (!udp)
201 return BPF_DROP;
202
203 keys->sport = udp->source;
204 keys->dport = udp->dest;
205 return BPF_OK;
206 default:
207 return BPF_DROP;
208 }
209
210 return BPF_DROP;
211}
212
213static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr)
214{
215 struct bpf_flow_keys *keys = skb->flow_keys;
216
217 keys->ip_proto = nexthdr;
218 switch (nexthdr) {
219 case IPPROTO_HOPOPTS:
220 case IPPROTO_DSTOPTS:
221 bpf_tail_call(skb, &jmp_table, IPV6OP);
222 break;
223 case IPPROTO_FRAGMENT:
224 bpf_tail_call(skb, &jmp_table, IPV6FR);
225 break;
226 default:
227 return parse_ip_proto(skb, nexthdr);
228 }
229
230 return BPF_DROP;
231}
232
233PROG(IP)(struct __sk_buff *skb)
234{
235 void *data_end = (void *)(long)skb->data_end;
236 struct bpf_flow_keys *keys = skb->flow_keys;
237 void *data = (void *)(long)skb->data;
238 struct iphdr *iph, _iph;
239 bool done = false;
240
241 iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph);
242 if (!iph)
243 return BPF_DROP;
244
245 /* IP header cannot be smaller than 20 bytes */
246 if (iph->ihl < 5)
247 return BPF_DROP;
248
249 keys->addr_proto = ETH_P_IP;
250 keys->ipv4_src = iph->saddr;
251 keys->ipv4_dst = iph->daddr;
252
253 keys->thoff += iph->ihl << 2;
254 if (data + keys->thoff > data_end)
255 return BPF_DROP;
256
257 if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) {
258 keys->is_frag = true;
259 if (iph->frag_off & bpf_htons(IP_OFFSET))
260 /* From second fragment on, packets do not have headers
261 * we can parse.
262 */
263 done = true;
264 else
265 keys->is_first_frag = true;
266 }
267
268 if (done)
269 return BPF_OK;
270
271 return parse_ip_proto(skb, iph->protocol);
272}
273
274PROG(IPV6)(struct __sk_buff *skb)
275{
276 struct bpf_flow_keys *keys = skb->flow_keys;
277 struct ipv6hdr *ip6h, _ip6h;
278
279 ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h);
280 if (!ip6h)
281 return BPF_DROP;
282
283 keys->addr_proto = ETH_P_IPV6;
284 memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr));
285
286 keys->thoff += sizeof(struct ipv6hdr);
287
288 return parse_ipv6_proto(skb, ip6h->nexthdr);
289}
290
291PROG(IPV6OP)(struct __sk_buff *skb)
292{
293 struct ipv6_opt_hdr *ip6h, _ip6h;
294
295 ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h);
296 if (!ip6h)
297 return BPF_DROP;
298
299 /* hlen is in 8-octets and does not include the first 8 bytes
300 * of the header
301 */
302 skb->flow_keys->thoff += (1 + ip6h->hdrlen) << 3;
303
304 return parse_ipv6_proto(skb, ip6h->nexthdr);
305}
306
307PROG(IPV6FR)(struct __sk_buff *skb)
308{
309 struct bpf_flow_keys *keys = skb->flow_keys;
310 struct frag_hdr *fragh, _fragh;
311
312 fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh);
313 if (!fragh)
314 return BPF_DROP;
315
316 keys->thoff += sizeof(*fragh);
317 keys->is_frag = true;
318 if (!(fragh->frag_off & bpf_htons(IP6_OFFSET)))
319 keys->is_first_frag = true;
320
321 return parse_ipv6_proto(skb, fragh->nexthdr);
322}
323
324PROG(MPLS)(struct __sk_buff *skb)
325{
326 struct mpls_label *mpls, _mpls;
327
328 mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls);
329 if (!mpls)
330 return BPF_DROP;
331
332 return BPF_OK;
333}
334
335PROG(VLAN)(struct __sk_buff *skb)
336{
337 struct bpf_flow_keys *keys = skb->flow_keys;
338 struct vlan_hdr *vlan, _vlan;
339 __be16 proto;
340
341 /* Peek back to see if single or double-tagging */
342 if (bpf_skb_load_bytes(skb, keys->thoff - sizeof(proto), &proto,
343 sizeof(proto)))
344 return BPF_DROP;
345
346 /* Account for double-tagging */
347 if (proto == bpf_htons(ETH_P_8021AD)) {
348 vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
349 if (!vlan)
350 return BPF_DROP;
351
352 if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q))
353 return BPF_DROP;
354
355 keys->thoff += sizeof(*vlan);
356 }
357
358 vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan);
359 if (!vlan)
360 return BPF_DROP;
361
362 keys->thoff += sizeof(*vlan);
363 /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/
364 if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) ||
365 vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q))
366 return BPF_DROP;
367
368 return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto);
369}
370
371char __license[] SEC("license") = "GPL";
372

Warning: That file was not part of the compilation database. It may have many parsing errors.