Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "bpfilter/matcher.h"
7 :
8 : #include <linux/icmp.h>
9 : #include <linux/icmpv6.h>
10 : #include <linux/if_ether.h>
11 : #include <linux/in.h>
12 : #include <linux/in6.h>
13 : #include <linux/ip.h>
14 : #include <linux/ipv6.h>
15 : #include <linux/tcp.h>
16 : #include <linux/udp.h>
17 :
18 : #include <ctype.h>
19 : #include <endian.h>
20 : #include <errno.h>
21 : #include <inttypes.h>
22 : #include <limits.h>
23 : #include <stdint.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 :
27 : #include "bpfilter/dump.h"
28 : #include "bpfilter/helper.h"
29 : #include "bpfilter/if.h"
30 : #include "bpfilter/logger.h"
31 : #include "bpfilter/pack.h"
32 : #include "bpfilter/runtime.h"
33 :
34 : #define INET4_ADDRSTRLEN 16
35 : #define INET6_ADDRSTRLEN 46
36 :
37 : #define BF_PAYLOAD_OPS(type, size, parser_cb, printer_cb) \
38 : [type] = {size, parser_cb, printer_cb}
39 :
40 : extern int inet_pton(int, const char *, void *);
41 : extern const char *inet_ntop(int, const void *, char *, socklen_t);
42 :
43 : /**
44 : * Matcher definition.
45 : *
46 : * Matchers are criterias to match the packet against. A set of matcher defines
47 : * what a rule should match on.
48 : *
49 : * @todo `bf_matcher`'s payload should be a union of all the possible payload
50 : * types.
51 : */
52 : struct bf_matcher
53 : {
54 : /// Matcher type.
55 : enum bf_matcher_type type;
56 : /// Comparison operator.
57 : enum bf_matcher_op op;
58 : /// Total matcher size (including payload).
59 : size_t len;
60 : /// Payload to match the packet against (if any).
61 : uint8_t payload[];
62 : };
63 :
64 0 : int _bf_parse_iface(enum bf_matcher_type type, enum bf_matcher_op op,
65 : void *payload, const char *raw_payload)
66 : {
67 0 : bf_assert(payload && raw_payload);
68 :
69 : int idx;
70 : unsigned long ifindex;
71 : char *endptr;
72 :
73 0 : idx = bf_if_index_from_name(raw_payload);
74 0 : if (idx > 0) {
75 0 : *(uint32_t *)payload = (uint32_t)idx;
76 0 : return 0;
77 : }
78 :
79 0 : ifindex = strtoul(raw_payload, &endptr, BF_BASE_10);
80 0 : if (*endptr == '\0' && 0 < ifindex && ifindex <= UINT32_MAX) {
81 0 : *(uint32_t *)payload = (uint32_t)ifindex;
82 0 : return 0;
83 : }
84 :
85 0 : bf_err(
86 : "\"%s %s\" expects an interface name (e.g., \"eth0\", \"wlan0\") or a decimal interface index (e.g., \"1\", \"2\"), not '%s'",
87 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
88 :
89 : return -EINVAL;
90 : }
91 :
92 0 : void _bf_print_iface(const void *payload)
93 : {
94 0 : bf_assert(payload);
95 :
96 : const char *ifname;
97 0 : uint32_t ifindex = *(uint32_t *)payload;
98 :
99 0 : ifname = bf_if_name_from_index((int)ifindex);
100 0 : if (ifname)
101 0 : (void)fprintf(stdout, "%s", ifname);
102 : else
103 0 : (void)fprintf(stdout, "%" PRIu32, ifindex);
104 0 : }
105 :
106 0 : int _bf_parse_l3_proto(enum bf_matcher_type type, enum bf_matcher_op op,
107 : void *payload, const char *raw_payload)
108 : {
109 0 : bf_assert(payload && raw_payload);
110 :
111 : unsigned long ethertype;
112 : char *endptr;
113 : int r;
114 :
115 0 : r = bf_ethertype_from_str(raw_payload, payload);
116 0 : if (!r)
117 : return 0;
118 :
119 0 : ethertype = strtoul(raw_payload, &endptr, BF_BASE_10);
120 0 : if (*endptr == '\0' && ethertype <= UINT16_MAX) {
121 0 : *(uint16_t *)payload = (uint16_t)ethertype;
122 0 : return 0;
123 : }
124 :
125 0 : ethertype = strtoul(raw_payload, &endptr, BF_BASE_16);
126 0 : if (*endptr == '\0' && ethertype <= UINT16_MAX) {
127 0 : *(uint16_t *)payload = (uint16_t)ethertype;
128 0 : return 0;
129 : }
130 :
131 0 : bf_err(
132 : "\"%s %s\" expects an internet layer protocol name (e.g. \"IPv6\", case insensitive), or a valid decimal or hexadecimal IEEE 802 number, not '%s'",
133 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
134 :
135 : return -EINVAL;
136 : }
137 :
138 0 : void _bf_print_l3_proto(const void *payload)
139 : {
140 0 : bf_assert(payload);
141 :
142 0 : const char *ethertype = bf_ethertype_to_str(*(uint16_t *)payload);
143 :
144 0 : if (ethertype)
145 0 : (void)fprintf(stdout, "%s", ethertype);
146 : else
147 0 : (void)fprintf(stdout, "0x%04" PRIx16, *(uint16_t *)payload);
148 0 : }
149 :
150 24 : int _bf_parse_l4_proto(enum bf_matcher_type type, enum bf_matcher_op op,
151 : void *payload, const char *raw_payload)
152 : {
153 24 : bf_assert(payload && raw_payload);
154 :
155 : unsigned long ipproto;
156 : char *endptr;
157 : int r;
158 :
159 24 : r = bf_ipproto_from_str(raw_payload, payload);
160 24 : if (!r)
161 : return 0;
162 :
163 0 : ipproto = strtoul(raw_payload, &endptr, BF_BASE_10);
164 0 : if (*endptr == '\0' && ipproto <= UINT8_MAX) {
165 0 : *(uint8_t *)payload = (uint8_t)ipproto;
166 0 : return 0;
167 : }
168 :
169 0 : bf_err(
170 : "\"%s %s\" expects a transport layer protocol name (e.g. \"ICMP\", case insensitive), or a valid decimal internet protocol number, not '%s'",
171 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
172 :
173 : return -EINVAL;
174 : }
175 :
176 0 : void _bf_print_l4_proto(const void *payload)
177 : {
178 0 : bf_assert(payload);
179 :
180 0 : const char *ipproto = bf_ipproto_to_str(*(uint8_t *)payload);
181 :
182 0 : if (ipproto)
183 0 : (void)fprintf(stdout, "%s", ipproto);
184 : else
185 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
186 0 : }
187 :
188 0 : int _bf_parse_l4_port(enum bf_matcher_type type, enum bf_matcher_op op,
189 : void *payload, const char *raw_payload)
190 : {
191 0 : bf_assert(payload && raw_payload);
192 :
193 : unsigned long port;
194 : char *endptr;
195 :
196 0 : port = strtoul(raw_payload, &endptr, BF_BASE_10);
197 0 : if (*endptr == '\0' && port <= UINT16_MAX) {
198 0 : *(uint16_t *)payload = htobe16((uint16_t)port);
199 0 : return 0;
200 : }
201 :
202 0 : bf_err("\"%s %s\" expects a valid decimal port number, not '%s'",
203 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
204 :
205 : return -EINVAL;
206 : }
207 :
208 0 : void _bf_print_l4_port(const void *payload)
209 : {
210 0 : bf_assert(payload);
211 :
212 0 : (void)fprintf(stdout, "%" PRIu16, (uint16_t)be16toh(*(uint16_t *)payload));
213 0 : }
214 :
215 : #define BF_PORT_RANGE_MAX_LEN 16 // 65535-65535, with nul char, round to **2
216 :
217 0 : static int _bf_parse_l4_port_range(enum bf_matcher_type type,
218 : enum bf_matcher_op op, void *payload,
219 : const char *raw_payload)
220 : {
221 0 : bf_assert(payload && raw_payload);
222 :
223 : uint16_t *ports = (uint16_t *)payload;
224 : unsigned long port;
225 : char buf[BF_PORT_RANGE_MAX_LEN];
226 : char *first;
227 : char *second;
228 : char *endptr;
229 :
230 0 : bf_strncpy(buf, BF_PORT_RANGE_MAX_LEN, raw_payload);
231 :
232 0 : if (!isdigit(*raw_payload))
233 0 : goto err;
234 :
235 0 : first = strtok_r(buf, "-", &second);
236 0 : if (!first)
237 0 : goto err;
238 :
239 0 : if (!*second)
240 0 : goto err;
241 :
242 0 : port = strtoul(first, &endptr, BF_BASE_10);
243 0 : if (*endptr != '\0' || port > UINT16_MAX)
244 0 : goto err;
245 0 : ports[0] = (uint16_t)port;
246 :
247 0 : port = strtoul(second, &endptr, BF_BASE_10);
248 0 : if (*endptr != '\0' || port > UINT16_MAX)
249 0 : goto err;
250 0 : ports[1] = (uint16_t)port;
251 :
252 0 : if (ports[1] < ports[0])
253 0 : goto err;
254 :
255 : return 0;
256 :
257 0 : err:
258 0 : bf_err(
259 : "\"%s %s\" expects two positive decimal port numbers as `$START-$END`, with `$START <= $END`, not '%s'",
260 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
261 :
262 : return -EINVAL;
263 : }
264 :
265 0 : void _bf_print_l4_port_range(const void *payload)
266 : {
267 0 : bf_assert(payload);
268 :
269 : uint16_t *ports = (uint16_t *)payload;
270 :
271 0 : (void)fprintf(stdout, "%" PRIu16 "-%" PRIu16, ports[0], ports[1]);
272 0 : }
273 :
274 0 : static int _bf_parse_probability(enum bf_matcher_type type,
275 : enum bf_matcher_op op, void *payload,
276 : const char *raw_payload)
277 : {
278 0 : bf_assert(payload && raw_payload);
279 :
280 : unsigned long proba;
281 : char *endptr;
282 :
283 0 : proba = strtoul(raw_payload, &endptr, BF_BASE_10);
284 0 : if (endptr[0] == '%' && endptr[1] == '\0' && proba <= 100) {
285 0 : *(uint8_t *)payload = (uint8_t)proba;
286 0 : return 0;
287 : }
288 :
289 0 : bf_err(
290 : "\"%s %s\" expects a valid decimal percentage value (i.e., within [0%%, 100%%]), not '%s'",
291 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
292 :
293 : return -EINVAL;
294 : }
295 :
296 0 : void _bf_print_probability(const void *payload)
297 : {
298 0 : bf_assert(payload);
299 :
300 0 : (void)fprintf(stdout, "%" PRIu8 "%%", *(uint8_t *)payload);
301 0 : }
302 :
303 0 : static int _bf_parse_mark(enum bf_matcher_type type, enum bf_matcher_op op,
304 : void *payload, const char *raw_payload)
305 : {
306 : long long mark;
307 : char *endptr;
308 :
309 : UNUSED(type);
310 : UNUSED(op);
311 :
312 0 : bf_assert(payload);
313 0 : bf_assert(raw_payload);
314 :
315 0 : mark = strtoll(raw_payload, &endptr, 0);
316 0 : if (*endptr) {
317 0 : return bf_err_r(-EINVAL,
318 : "mark value '%s' can't be parsed as a positive integer",
319 : raw_payload);
320 : }
321 0 : if (mark < 0) {
322 0 : return bf_err_r(-EINVAL, "mark should be positive, not '%s'",
323 : raw_payload);
324 : }
325 0 : if (mark > UINT32_MAX)
326 0 : return bf_err_r(-EINVAL, "mark should be at most 0x%x", UINT32_MAX);
327 :
328 0 : *(uint32_t *)payload = (uint32_t)mark;
329 :
330 0 : return 0;
331 : }
332 :
333 0 : void _bf_print_mark(const void *payload)
334 : {
335 0 : bf_assert(payload);
336 :
337 0 : (void)fprintf(stdout, "0x%" PRIx32, *(uint32_t *)payload);
338 0 : }
339 :
340 20 : static int _bf_parse_ipv4_addr(enum bf_matcher_type type, enum bf_matcher_op op,
341 : void *payload, const char *raw_payload)
342 : {
343 20 : bf_assert(payload && raw_payload);
344 :
345 : int r;
346 :
347 20 : r = inet_pton(AF_INET, raw_payload, payload);
348 20 : if (r == 1)
349 : return 0;
350 :
351 0 : bf_err(
352 : "\"%s %s\" expects an IPv4 address in dotted-decimal format, \"ddd.ddd.ddd.ddd\", where ddd is a decimal number of up to three digits in the range 0 to 255, not '%s' ",
353 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
354 :
355 : return -EINVAL;
356 : }
357 :
358 0 : void _bf_print_ipv4_addr(const void *payload)
359 : {
360 0 : bf_assert(payload);
361 :
362 : char str[INET4_ADDRSTRLEN];
363 :
364 0 : if (inet_ntop(AF_INET, payload, str, INET4_ADDRSTRLEN))
365 0 : (void)fprintf(stdout, "%s", str);
366 : else
367 0 : (void)fprintf(stdout, "<failed to print IPv4 address>");
368 0 : }
369 :
370 : #define BF_IPV4_NET_MAX_LEN \
371 : 32 // 255.255.255.255/32, with nul char, round to **2
372 :
373 0 : static int _bf_parse_ipv4_net(enum bf_matcher_type type, enum bf_matcher_op op,
374 : void *payload, const char *raw_payload)
375 : {
376 0 : bf_assert(payload && raw_payload);
377 :
378 : struct bf_ip4_lpm_key *addr = payload;
379 : char buf[BF_IPV4_NET_MAX_LEN];
380 : char *strip, *strmask, *endptr;
381 : int r;
382 :
383 0 : bf_strncpy(buf, BF_IPV4_NET_MAX_LEN, raw_payload);
384 :
385 0 : if (!isdigit(*raw_payload))
386 0 : goto err;
387 :
388 0 : strip = strtok_r(buf, "/", &strmask);
389 0 : if (!strip || !*strmask)
390 0 : goto err;
391 :
392 0 : r = inet_pton(AF_INET, strip, &addr->data);
393 0 : if (r != 1)
394 0 : goto err;
395 :
396 0 : addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
397 0 : if (*endptr != '\0' || addr->prefixlen > 32)
398 0 : goto err;
399 :
400 : return 0;
401 :
402 0 : err:
403 0 : bf_err(
404 : "\"%s %s\" expects an IPv4 network address in dotted-decimal format, \"ddd.ddd.ddd.ddd\", where ddd is a decimal number of up to three digits in the range 0 to 255 followed by a subnet mask (e.g., \"124.24.12.5/30\"), not '%s' ",
405 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
406 :
407 : return -EINVAL;
408 : }
409 :
410 0 : void _bf_print_ipv4_net(const void *payload)
411 : {
412 0 : bf_assert(payload);
413 :
414 : char str[INET4_ADDRSTRLEN];
415 : const struct bf_ip4_lpm_key *addr = payload;
416 :
417 0 : if (inet_ntop(AF_INET, &addr->data, str, INET4_ADDRSTRLEN))
418 0 : (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
419 : else
420 0 : (void)fprintf(stdout, "<failed to print IPv4 network>");
421 0 : }
422 :
423 0 : static int _bf_parse_ipv6_addr(enum bf_matcher_type type, enum bf_matcher_op op,
424 : void *payload, const char *raw_payload)
425 : {
426 0 : bf_assert(payload && raw_payload);
427 :
428 : int r;
429 :
430 0 : r = inet_pton(AF_INET6, raw_payload, payload);
431 0 : if (r == 1)
432 : return 0;
433 :
434 0 : bf_err(
435 : "\"%s %s\" expects an IPv6 address composed of 8 hexadecimal numbers (abbreviations are supported), not '%s' ",
436 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
437 :
438 : return -EINVAL;
439 : }
440 :
441 0 : void _bf_print_ipv6_addr(const void *payload)
442 : {
443 0 : bf_assert(payload);
444 :
445 : char str[INET6_ADDRSTRLEN];
446 :
447 0 : if (inet_ntop(AF_INET6, payload, str, INET6_ADDRSTRLEN))
448 0 : (void)fprintf(stdout, "%s", str);
449 : else
450 0 : (void)fprintf(stdout, "<failed to print IPv6 address>");
451 0 : }
452 :
453 : #define BF_IPV6_NET_MAX_LEN (INET6_ADDRSTRLEN + 4)
454 :
455 0 : static int _bf_parse_ipv6_net(enum bf_matcher_type type, enum bf_matcher_op op,
456 : void *payload, const char *raw_payload)
457 : {
458 0 : bf_assert(payload && raw_payload);
459 :
460 : struct bf_ip6_lpm_key *addr = payload;
461 : char buf[BF_IPV6_NET_MAX_LEN];
462 : char *strip, *strmask, *endptr;
463 : int r;
464 :
465 0 : bf_strncpy(buf, BF_IPV6_NET_MAX_LEN, raw_payload);
466 :
467 0 : if (!isalpha(*raw_payload) && !isdigit(*raw_payload) && *raw_payload != ':')
468 0 : goto err;
469 :
470 0 : strip = strtok_r(buf, "/", &strmask);
471 0 : if (!strip || !*strmask)
472 0 : goto err;
473 :
474 0 : r = inet_pton(AF_INET6, strip, &addr->data);
475 0 : if (r != 1)
476 0 : goto err;
477 :
478 0 : addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
479 0 : if (*endptr != '\0' || addr->prefixlen > 128)
480 0 : goto err;
481 :
482 : return 0;
483 :
484 0 : err:
485 0 : bf_err(
486 : "\"%s %s\" expects an IPv6 network address composed of 8 hexadecimal numbers (abbreviations are supported) followed by a subnet mask (e.g., \"2001:db8:85a3::/48\"), not '%s' ",
487 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
488 :
489 : return -EINVAL;
490 : }
491 :
492 0 : void _bf_print_ipv6_net(const void *payload)
493 : {
494 0 : bf_assert(payload);
495 :
496 : const struct bf_ip6_lpm_key *addr = payload;
497 : char str[INET6_ADDRSTRLEN];
498 :
499 0 : if (inet_ntop(AF_INET6, addr->data, str, INET6_ADDRSTRLEN))
500 0 : (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
501 : else
502 0 : (void)fprintf(stdout, "<failed to print IPv6 address>");
503 0 : }
504 :
505 0 : static int _bf_parse_tcp_flags(enum bf_matcher_type type, enum bf_matcher_op op,
506 : void *payload, const char *raw_payload)
507 : {
508 0 : bf_assert(payload && raw_payload);
509 :
510 : _cleanup_free_ char *_raw_payload = NULL;
511 : char *tmp;
512 : char *saveptr;
513 : char *token;
514 : uint8_t *flags = payload;
515 :
516 0 : _raw_payload = strdup(raw_payload);
517 : if (!raw_payload)
518 : goto err;
519 :
520 0 : *flags = 0;
521 : tmp = _raw_payload;
522 :
523 0 : while ((token = strtok_r(tmp, ",", &saveptr))) {
524 : enum bf_tcp_flag new_flag;
525 : int r;
526 :
527 0 : r = bf_tcp_flag_from_str(token, &new_flag);
528 0 : if (r)
529 0 : goto err;
530 :
531 0 : *flags |= (uint8_t)(1 << new_flag);
532 :
533 : tmp = NULL;
534 : }
535 :
536 : return 0;
537 :
538 : err:
539 0 : bf_err(
540 : "\"%s %s\" expects a comma-separated list of one or more TCP flags (fin, syn, rst, psh, ack, urg, ece, or cwr), not '%s' ",
541 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
542 :
543 : return -EINVAL;
544 : }
545 :
546 0 : void _bf_print_tcp_flags(const void *payload)
547 : {
548 0 : bf_assert(payload);
549 :
550 0 : uint8_t flag = *(uint8_t *)payload;
551 :
552 0 : for (uint32_t i = 0; i < _BF_TCP_MAX; ++i) {
553 0 : if (flag & (1 << i)) {
554 0 : flag &= ~(1 << i);
555 0 : (void)fprintf(stdout, "%s%s", bf_tcp_flag_to_str(i),
556 : flag ? "," : "");
557 : }
558 : }
559 0 : }
560 :
561 0 : static int _bf_parse_icmp_type(enum bf_matcher_type type, enum bf_matcher_op op,
562 : void *payload, const char *raw_payload)
563 : {
564 0 : bf_assert(payload && raw_payload);
565 :
566 : unsigned long icmptype;
567 : char *endptr;
568 : int r;
569 :
570 0 : r = bf_icmp_type_from_str(raw_payload, payload);
571 0 : if (!r)
572 : return 0;
573 :
574 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
575 :
576 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
577 0 : *(uint8_t *)payload = (uint8_t)icmptype;
578 0 : return 0;
579 : }
580 :
581 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
582 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
583 0 : *(uint8_t *)payload = (uint8_t)icmptype;
584 0 : return 0;
585 : }
586 :
587 0 : bf_err(
588 : "\"%s %s\" expects an ICMP type name (e.g. \"echo-reply\", case insensitive), or or a decimal or hexadecimal ICMP type value, not '%s'",
589 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
590 :
591 : return -EINVAL;
592 : }
593 :
594 0 : void _bf_print_icmp_type(const void *payload)
595 : {
596 0 : bf_assert(payload);
597 :
598 0 : const char *type = bf_icmp_type_to_str(*(uint8_t *)payload);
599 :
600 0 : if (type)
601 0 : (void)fprintf(stdout, "%s", type);
602 : else
603 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
604 0 : }
605 :
606 0 : static int _bf_parse_icmp_code(enum bf_matcher_type type, enum bf_matcher_op op,
607 : void *payload, const char *raw_payload)
608 : {
609 0 : bf_assert(payload && raw_payload);
610 :
611 : unsigned long code;
612 : char *endptr;
613 :
614 0 : code = strtoul(raw_payload, &endptr, BF_BASE_10);
615 0 : if (*endptr == '\0' && code <= UINT8_MAX) {
616 0 : *(uint8_t *)payload = (uint8_t)code;
617 0 : return 0;
618 : }
619 :
620 0 : code = strtoul(raw_payload, &endptr, BF_BASE_16);
621 0 : if (*endptr == '\0' && code <= UINT8_MAX) {
622 0 : *(uint8_t *)payload = (uint8_t)code;
623 0 : return 0;
624 : }
625 :
626 0 : bf_err(
627 : "\"%s %s\" expects a decimal or hexadecimal ICMP or ICMPv6 code value, not '%s'",
628 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
629 :
630 : return -EINVAL;
631 : }
632 :
633 0 : void _bf_print_icmp_code(const void *payload)
634 : {
635 0 : bf_assert(payload);
636 :
637 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
638 0 : }
639 :
640 0 : static int _bf_parse_icmpv6_type(enum bf_matcher_type type,
641 : enum bf_matcher_op op, void *payload,
642 : const char *raw_payload)
643 : {
644 0 : bf_assert(payload && raw_payload);
645 :
646 : unsigned long icmptype;
647 : char *endptr;
648 : int r;
649 :
650 0 : r = bf_icmpv6_type_from_str(raw_payload, payload);
651 0 : if (!r)
652 : return 0;
653 :
654 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
655 :
656 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
657 0 : *(uint8_t *)payload = (uint8_t)icmptype;
658 0 : return 0;
659 : }
660 :
661 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
662 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
663 0 : *(uint8_t *)payload = (uint8_t)icmptype;
664 0 : return 0;
665 : }
666 :
667 0 : bf_err(
668 : "\"%s %s\" expects an ICMPv6 type name (e.g. \"echo-reply\", case insensitive), or a decimal or hexadecimal ICMPv6 type value, not '%s'",
669 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
670 :
671 : return -EINVAL;
672 : }
673 :
674 0 : void _bf_print_icmpv6_type(const void *payload)
675 : {
676 0 : bf_assert(payload);
677 :
678 0 : const char *type = bf_icmpv6_type_to_str(*(uint8_t *)payload);
679 :
680 0 : if (type)
681 0 : (void)fprintf(stdout, "%s", type);
682 : else
683 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
684 0 : }
685 :
686 : #define BF_MATCHER_OPS(op, payload_size, parse_cb, print_cb) \
687 : [op] = {payload_size, parse_cb, print_cb}
688 :
689 : #define _BF_TCP_FLAGS_OFFSET 13
690 :
691 : static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
692 : [BF_MATCHER_META_IFACE] =
693 : {
694 : .layer = BF_MATCHER_NO_LAYER,
695 : .ops =
696 : {
697 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
698 : _bf_parse_iface, _bf_print_iface),
699 : },
700 : },
701 : [BF_MATCHER_META_L3_PROTO] =
702 : {
703 : .layer = BF_MATCHER_NO_LAYER,
704 : .ops =
705 : {
706 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
707 : _bf_parse_l3_proto, _bf_print_l3_proto),
708 : },
709 : },
710 : [BF_MATCHER_META_L4_PROTO] =
711 : {
712 : .layer = BF_MATCHER_NO_LAYER,
713 : .ops =
714 : {
715 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
716 : _bf_parse_l4_proto, _bf_print_l4_proto),
717 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
718 : _bf_parse_l4_proto, _bf_print_l4_proto),
719 : },
720 : },
721 : [BF_MATCHER_META_SPORT] =
722 : {
723 : .layer = BF_MATCHER_NO_LAYER,
724 : .ops =
725 : {
726 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
727 : _bf_parse_l4_port, _bf_print_l4_port),
728 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
729 : _bf_parse_l4_port, _bf_print_l4_port),
730 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
731 : _bf_parse_l4_port_range,
732 : _bf_print_l4_port_range),
733 : },
734 : },
735 : [BF_MATCHER_META_DPORT] =
736 : {
737 : .layer = BF_MATCHER_NO_LAYER,
738 : .ops =
739 : {
740 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
741 : _bf_parse_l4_port, _bf_print_l4_port),
742 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
743 : _bf_parse_l4_port, _bf_print_l4_port),
744 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
745 : _bf_parse_l4_port_range,
746 : _bf_print_l4_port_range),
747 : },
748 : },
749 : [BF_MATCHER_META_PROBABILITY] =
750 : {
751 : .layer = BF_MATCHER_NO_LAYER,
752 : .ops =
753 : {
754 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
755 : _bf_parse_probability,
756 : _bf_print_probability),
757 : },
758 : },
759 : [BF_MATCHER_META_MARK] =
760 : {
761 : .layer = BF_MATCHER_NO_LAYER,
762 : .ops =
763 : {
764 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
765 : _bf_parse_mark, _bf_print_mark),
766 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
767 : _bf_parse_mark, _bf_print_mark),
768 : },
769 : },
770 : [BF_MATCHER_IP4_SADDR] =
771 : {
772 : .layer = BF_MATCHER_LAYER_3,
773 : .hdr_id = ETH_P_IP,
774 : .hdr_payload_size = sizeof(uint32_t),
775 : .hdr_payload_offset = offsetof(struct iphdr, saddr),
776 : .ops =
777 : {
778 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
779 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
780 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
781 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
782 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
783 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
784 : },
785 : },
786 : [BF_MATCHER_IP4_DADDR] =
787 : {
788 : .layer = BF_MATCHER_LAYER_3,
789 : .hdr_id = ETH_P_IP,
790 : .hdr_payload_size = sizeof(uint32_t),
791 : .hdr_payload_offset = offsetof(struct iphdr, daddr),
792 : .ops =
793 : {
794 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
795 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
796 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
797 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
798 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
799 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
800 : },
801 : },
802 : [BF_MATCHER_IP4_SNET] =
803 : {
804 : .layer = BF_MATCHER_LAYER_3,
805 : .hdr_id = ETH_P_IP,
806 : .hdr_payload_size = sizeof(uint32_t),
807 : .hdr_payload_offset = offsetof(struct iphdr, saddr),
808 : .ops =
809 : {
810 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
811 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
812 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
813 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
814 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
815 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
816 : },
817 : },
818 : [BF_MATCHER_IP4_DNET] =
819 : {
820 : .layer = BF_MATCHER_LAYER_3,
821 : .hdr_id = ETH_P_IP,
822 : .hdr_payload_size = sizeof(uint32_t),
823 : .hdr_payload_offset = offsetof(struct iphdr, daddr),
824 : .ops =
825 : {
826 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
827 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
828 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
829 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
830 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
831 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
832 : },
833 : },
834 : [BF_MATCHER_IP4_PROTO] =
835 : {
836 : .layer = BF_MATCHER_LAYER_3,
837 : .hdr_id = ETH_P_IP,
838 : .hdr_payload_size = sizeof(uint8_t),
839 : .hdr_payload_offset = offsetof(struct iphdr, protocol),
840 : .ops =
841 : {
842 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
843 : _bf_parse_l4_proto, _bf_print_l4_proto),
844 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
845 : _bf_parse_l4_proto, _bf_print_l4_proto),
846 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
847 : _bf_parse_l4_proto, _bf_print_l4_proto),
848 : },
849 : },
850 : [BF_MATCHER_IP6_SADDR] =
851 : {
852 : .layer = BF_MATCHER_LAYER_3,
853 : .hdr_id = ETH_P_IPV6,
854 : .hdr_payload_size = sizeof(struct in6_addr),
855 : .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
856 : .ops =
857 : {
858 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
859 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
860 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
861 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
862 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
863 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
864 : },
865 : },
866 : [BF_MATCHER_IP6_DADDR] =
867 : {
868 : .layer = BF_MATCHER_LAYER_3,
869 : .hdr_id = ETH_P_IPV6,
870 : .hdr_payload_size = sizeof(struct in6_addr),
871 : .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
872 : .ops =
873 : {
874 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
875 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
876 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
877 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
878 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
879 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
880 : },
881 : },
882 : [BF_MATCHER_IP6_SNET] =
883 : {
884 : .layer = BF_MATCHER_LAYER_3,
885 : .hdr_id = ETH_P_IPV6,
886 : .hdr_payload_size = sizeof(struct in6_addr),
887 : .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
888 : .ops =
889 : {
890 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
891 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
892 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
893 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
894 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
895 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
896 : },
897 : },
898 : [BF_MATCHER_IP6_DNET] =
899 : {
900 : .layer = BF_MATCHER_LAYER_3,
901 : .hdr_id = ETH_P_IPV6,
902 : .hdr_payload_size = sizeof(struct in6_addr),
903 : .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
904 : .ops =
905 : {
906 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
907 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
908 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
909 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
910 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
911 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
912 : },
913 : },
914 : [BF_MATCHER_IP6_NEXTHDR] =
915 : {
916 : .layer = BF_MATCHER_LAYER_3,
917 : .hdr_id = ETH_P_IPV6,
918 : .hdr_payload_size = sizeof(uint8_t),
919 : .hdr_payload_offset = offsetof(struct ipv6hdr, nexthdr),
920 : .ops =
921 : {
922 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
923 : _bf_parse_l4_proto, _bf_print_l4_proto),
924 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
925 : _bf_parse_l4_proto, _bf_print_l4_proto),
926 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
927 : _bf_parse_l4_proto, _bf_print_l4_proto),
928 : },
929 : },
930 : [BF_MATCHER_TCP_SPORT] =
931 : {
932 : .layer = BF_MATCHER_LAYER_4,
933 : .hdr_id = IPPROTO_TCP,
934 : .hdr_payload_size = sizeof(uint16_t),
935 : .hdr_payload_offset = offsetof(struct tcphdr, source),
936 : .ops =
937 : {
938 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
939 : _bf_parse_l4_port, _bf_print_l4_port),
940 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
941 : _bf_parse_l4_port, _bf_print_l4_port),
942 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
943 : _bf_parse_l4_port, _bf_print_l4_port),
944 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
945 : _bf_parse_l4_port_range,
946 : _bf_print_l4_port_range),
947 : },
948 : },
949 : [BF_MATCHER_TCP_DPORT] =
950 : {
951 : .layer = BF_MATCHER_LAYER_4,
952 : .hdr_id = IPPROTO_TCP,
953 : .hdr_payload_size = sizeof(uint16_t),
954 : .hdr_payload_offset = offsetof(struct tcphdr, dest),
955 : .ops =
956 : {
957 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
958 : _bf_parse_l4_port, _bf_print_l4_port),
959 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
960 : _bf_parse_l4_port, _bf_print_l4_port),
961 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
962 : _bf_parse_l4_port, _bf_print_l4_port),
963 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
964 : _bf_parse_l4_port_range,
965 : _bf_print_l4_port_range),
966 : },
967 : },
968 : [BF_MATCHER_TCP_FLAGS] =
969 : {
970 : .layer = BF_MATCHER_LAYER_4,
971 : .hdr_id = IPPROTO_TCP,
972 : .hdr_payload_size = sizeof(uint8_t),
973 : .hdr_payload_offset = _BF_TCP_FLAGS_OFFSET,
974 : .ops =
975 : {
976 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
977 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
978 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
979 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
980 : BF_MATCHER_OPS(BF_MATCHER_ANY, sizeof(uint8_t),
981 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
982 : BF_MATCHER_OPS(BF_MATCHER_ALL, sizeof(uint8_t),
983 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
984 : },
985 : },
986 : [BF_MATCHER_UDP_SPORT] =
987 : {
988 : .layer = BF_MATCHER_LAYER_4,
989 : .hdr_id = IPPROTO_UDP,
990 : .hdr_payload_size = sizeof(uint16_t),
991 : .hdr_payload_offset = offsetof(struct udphdr, source),
992 : .ops =
993 : {
994 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
995 : _bf_parse_l4_port, _bf_print_l4_port),
996 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
997 : _bf_parse_l4_port, _bf_print_l4_port),
998 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
999 : _bf_parse_l4_port, _bf_print_l4_port),
1000 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
1001 : _bf_parse_l4_port_range,
1002 : _bf_print_l4_port_range),
1003 : },
1004 : },
1005 : [BF_MATCHER_UDP_DPORT] =
1006 : {
1007 : .layer = BF_MATCHER_LAYER_4,
1008 : .hdr_id = IPPROTO_UDP,
1009 : .hdr_payload_size = sizeof(uint16_t),
1010 : .hdr_payload_offset = offsetof(struct udphdr, dest),
1011 : .ops =
1012 : {
1013 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
1014 : _bf_parse_l4_port, _bf_print_l4_port),
1015 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
1016 : _bf_parse_l4_port, _bf_print_l4_port),
1017 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
1018 : _bf_parse_l4_port, _bf_print_l4_port),
1019 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
1020 : _bf_parse_l4_port_range,
1021 : _bf_print_l4_port_range),
1022 : },
1023 : },
1024 : [BF_MATCHER_ICMP_TYPE] =
1025 : {
1026 : .layer = BF_MATCHER_LAYER_4,
1027 : .hdr_id = IPPROTO_ICMP,
1028 : .hdr_payload_size = sizeof(uint8_t),
1029 : .hdr_payload_offset = offsetof(struct icmphdr, type),
1030 : .ops =
1031 : {
1032 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1033 : _bf_parse_icmp_type, _bf_print_icmp_type),
1034 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1035 : _bf_parse_icmp_type, _bf_print_icmp_type),
1036 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1037 : _bf_parse_icmp_type, _bf_print_icmp_type),
1038 : },
1039 : },
1040 : [BF_MATCHER_ICMP_CODE] =
1041 : {
1042 : .layer = BF_MATCHER_LAYER_4,
1043 : .hdr_id = IPPROTO_ICMP,
1044 : .hdr_payload_size = sizeof(uint8_t),
1045 : .hdr_payload_offset = offsetof(struct icmphdr, code),
1046 : .ops =
1047 : {
1048 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1049 : _bf_parse_icmp_code, _bf_print_icmp_code),
1050 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1051 : _bf_parse_icmp_code, _bf_print_icmp_code),
1052 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1053 : _bf_parse_icmp_code, _bf_print_icmp_code),
1054 : },
1055 : },
1056 : [BF_MATCHER_ICMPV6_TYPE] =
1057 : {
1058 : .layer = BF_MATCHER_LAYER_4,
1059 : .hdr_id = IPPROTO_ICMPV6,
1060 : .hdr_payload_size = sizeof(uint8_t),
1061 : .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_type),
1062 : .ops =
1063 : {
1064 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1065 : _bf_parse_icmpv6_type,
1066 : _bf_print_icmpv6_type),
1067 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1068 : _bf_parse_icmpv6_type,
1069 : _bf_print_icmpv6_type),
1070 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1071 : _bf_parse_icmpv6_type,
1072 : _bf_print_icmpv6_type),
1073 : },
1074 : },
1075 : [BF_MATCHER_ICMPV6_CODE] =
1076 : {
1077 : .layer = BF_MATCHER_LAYER_4,
1078 : .hdr_id = IPPROTO_ICMPV6,
1079 : .hdr_payload_size = sizeof(uint8_t),
1080 : .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_code),
1081 : .ops =
1082 : {
1083 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1084 : _bf_parse_icmp_code, _bf_print_icmp_code),
1085 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1086 : _bf_parse_icmp_code, _bf_print_icmp_code),
1087 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1088 : _bf_parse_icmp_code, _bf_print_icmp_code),
1089 : },
1090 : },
1091 : };
1092 :
1093 76 : const struct bf_matcher_meta *bf_matcher_get_meta(enum bf_matcher_type type)
1094 : {
1095 76 : if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
1096 : return NULL;
1097 :
1098 75 : return _bf_matcher_metas[type].layer == _BF_MATCHER_LAYER_UNDEFINED ?
1099 75 : NULL :
1100 : &_bf_matcher_metas[type];
1101 : }
1102 :
1103 76 : const struct bf_matcher_ops *bf_matcher_get_ops(enum bf_matcher_type type,
1104 : enum bf_matcher_op op)
1105 : {
1106 76 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
1107 :
1108 76 : if (!meta)
1109 : return NULL;
1110 :
1111 75 : return meta->ops[op].ref_payload_size ? &meta->ops[op] : NULL;
1112 : }
1113 :
1114 58 : int bf_matcher_new(struct bf_matcher **matcher, enum bf_matcher_type type,
1115 : enum bf_matcher_op op, const void *payload,
1116 : size_t payload_len)
1117 : {
1118 56 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
1119 :
1120 58 : bf_assert(matcher);
1121 57 : bf_assert((payload && payload_len) || (!payload && !payload_len));
1122 :
1123 56 : _matcher = malloc(sizeof(struct bf_matcher) + payload_len);
1124 56 : if (!_matcher)
1125 : return -ENOMEM;
1126 :
1127 54 : _matcher->type = type;
1128 54 : _matcher->op = op;
1129 54 : _matcher->len = sizeof(struct bf_matcher) + payload_len;
1130 54 : bf_memcpy(_matcher->payload, payload, payload_len);
1131 :
1132 54 : *matcher = TAKE_PTR(_matcher);
1133 :
1134 54 : return 0;
1135 : }
1136 :
1137 0 : int bf_matcher_new_from_raw(struct bf_matcher **matcher,
1138 : enum bf_matcher_type type, enum bf_matcher_op op,
1139 : const char *payload)
1140 : {
1141 0 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
1142 : const struct bf_matcher_ops *ops;
1143 : int r;
1144 :
1145 0 : bf_assert(matcher && payload);
1146 :
1147 0 : ops = bf_matcher_get_ops(type, op);
1148 0 : if (!ops) {
1149 0 : return bf_err_r(-ENOENT, "payload ops not found for '%s %s'",
1150 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op));
1151 : }
1152 :
1153 0 : _matcher = malloc(sizeof(*_matcher) + ops->ref_payload_size);
1154 0 : if (!_matcher)
1155 : return -ENOMEM;
1156 :
1157 0 : _matcher->type = type;
1158 0 : _matcher->op = op;
1159 0 : _matcher->len = sizeof(*_matcher) + ops->ref_payload_size;
1160 :
1161 0 : r = ops->parse(_matcher->type, _matcher->op, &_matcher->payload, payload);
1162 0 : if (r)
1163 : return r;
1164 :
1165 0 : *matcher = TAKE_PTR(_matcher);
1166 :
1167 0 : return 0;
1168 : }
1169 :
1170 23 : int bf_matcher_new_from_pack(struct bf_matcher **matcher, bf_rpack_node_t node)
1171 : {
1172 23 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
1173 : enum bf_matcher_type type;
1174 : enum bf_matcher_op op;
1175 : const void *payload;
1176 : size_t payload_len;
1177 : int r;
1178 :
1179 23 : bf_assert(matcher);
1180 :
1181 23 : r = bf_rpack_kv_enum(node, "type", &type);
1182 : if (r)
1183 0 : return bf_rpack_key_err(r, "bf_matcher.type");
1184 :
1185 23 : r = bf_rpack_kv_enum(node, "op", &op);
1186 : if (r)
1187 0 : return bf_rpack_key_err(r, "bf_matcher.op");
1188 :
1189 23 : r = bf_rpack_kv_bin(node, "payload", &payload, &payload_len);
1190 23 : if (r)
1191 0 : return bf_rpack_key_err(r, "bf_matcher.payload");
1192 :
1193 23 : r = bf_matcher_new(&_matcher, type, op, payload, payload_len);
1194 23 : if (r)
1195 0 : return bf_err_r(r, "failed to create bf_matcher from pack");
1196 :
1197 23 : *matcher = TAKE_PTR(_matcher);
1198 :
1199 23 : return 0;
1200 : }
1201 :
1202 166 : void bf_matcher_free(struct bf_matcher **matcher)
1203 : {
1204 166 : bf_assert(matcher);
1205 :
1206 165 : if (!*matcher)
1207 : return;
1208 :
1209 54 : free(*matcher);
1210 54 : *matcher = NULL;
1211 : }
1212 :
1213 25 : int bf_matcher_pack(const struct bf_matcher *matcher, bf_wpack_t *pack)
1214 : {
1215 25 : bf_assert(matcher);
1216 24 : bf_assert(pack);
1217 :
1218 23 : bf_wpack_kv_int(pack, "type", matcher->type);
1219 23 : bf_wpack_kv_int(pack, "op", matcher->op);
1220 23 : bf_wpack_kv_bin(pack, "payload", matcher->payload,
1221 23 : matcher->len - sizeof(*matcher));
1222 :
1223 23 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
1224 : }
1225 :
1226 0 : void bf_matcher_dump(const struct bf_matcher *matcher, prefix_t *prefix)
1227 : {
1228 0 : bf_assert(matcher);
1229 0 : bf_assert(prefix);
1230 :
1231 0 : DUMP(prefix, "struct bf_matcher at %p", matcher);
1232 :
1233 0 : bf_dump_prefix_push(prefix);
1234 :
1235 0 : DUMP(prefix, "type: %s", bf_matcher_type_to_str(matcher->type));
1236 0 : DUMP(prefix, "op: %s", bf_matcher_op_to_str(matcher->op));
1237 0 : DUMP(prefix, "len: %ld", matcher->len);
1238 0 : DUMP(bf_dump_prefix_last(prefix), "payload:");
1239 0 : bf_dump_prefix_push(prefix);
1240 0 : bf_dump_hex(prefix, matcher->payload,
1241 0 : matcher->len - sizeof(struct bf_matcher));
1242 0 : bf_dump_prefix_pop(prefix);
1243 :
1244 0 : bf_dump_prefix_pop(prefix);
1245 0 : }
1246 :
1247 60 : enum bf_matcher_type bf_matcher_get_type(const struct bf_matcher *matcher)
1248 : {
1249 60 : bf_assert(matcher);
1250 60 : return matcher->type;
1251 : }
1252 :
1253 0 : enum bf_matcher_op bf_matcher_get_op(const struct bf_matcher *matcher)
1254 : {
1255 0 : bf_assert(matcher);
1256 0 : return matcher->op;
1257 : }
1258 :
1259 0 : const void *bf_matcher_payload(const struct bf_matcher *matcher)
1260 : {
1261 0 : bf_assert(matcher);
1262 0 : return matcher->payload;
1263 : }
1264 :
1265 0 : size_t bf_matcher_payload_len(const struct bf_matcher *matcher)
1266 : {
1267 0 : bf_assert(matcher);
1268 0 : return matcher->len - sizeof(*matcher);
1269 : }
1270 :
1271 0 : size_t bf_matcher_len(const struct bf_matcher *matcher)
1272 : {
1273 0 : bf_assert(matcher);
1274 0 : return matcher->len;
1275 : }
1276 :
1277 : static const char *_bf_matcher_type_strs[] = {
1278 : [BF_MATCHER_META_IFACE] = "meta.iface",
1279 : [BF_MATCHER_META_L3_PROTO] = "meta.l3_proto",
1280 : [BF_MATCHER_META_L4_PROTO] = "meta.l4_proto",
1281 : [BF_MATCHER_META_PROBABILITY] = "meta.probability",
1282 : [BF_MATCHER_META_SPORT] = "meta.sport",
1283 : [BF_MATCHER_META_DPORT] = "meta.dport",
1284 : [BF_MATCHER_META_MARK] = "meta.mark",
1285 : [BF_MATCHER_IP4_SADDR] = "ip4.saddr",
1286 : [BF_MATCHER_IP4_SNET] = "ip4.snet",
1287 : [BF_MATCHER_IP4_DADDR] = "ip4.daddr",
1288 : [BF_MATCHER_IP4_DNET] = "ip4.dnet",
1289 : [BF_MATCHER_IP4_PROTO] = "ip4.proto",
1290 : [BF_MATCHER_IP6_SADDR] = "ip6.saddr",
1291 : [BF_MATCHER_IP6_SNET] = "ip6.snet",
1292 : [BF_MATCHER_IP6_DADDR] = "ip6.daddr",
1293 : [BF_MATCHER_IP6_DNET] = "ip6.dnet",
1294 : [BF_MATCHER_IP6_NEXTHDR] = "ip6.nexthdr",
1295 : [BF_MATCHER_TCP_SPORT] = "tcp.sport",
1296 : [BF_MATCHER_TCP_DPORT] = "tcp.dport",
1297 : [BF_MATCHER_TCP_FLAGS] = "tcp.flags",
1298 : [BF_MATCHER_UDP_SPORT] = "udp.sport",
1299 : [BF_MATCHER_UDP_DPORT] = "udp.dport",
1300 : [BF_MATCHER_ICMP_TYPE] = "icmp.type",
1301 : [BF_MATCHER_ICMP_CODE] = "icmp.code",
1302 : [BF_MATCHER_ICMPV6_TYPE] = "icmpv6.type",
1303 : [BF_MATCHER_ICMPV6_CODE] = "icmpv6.code",
1304 : [BF_MATCHER_SET] = "<set>",
1305 : };
1306 :
1307 : static_assert(ARRAY_SIZE(_bf_matcher_type_strs) == _BF_MATCHER_TYPE_MAX,
1308 : "missing entries in the matcher type array");
1309 :
1310 31 : const char *bf_matcher_type_to_str(enum bf_matcher_type type)
1311 : {
1312 31 : if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
1313 : return "<invalid>";
1314 :
1315 30 : return _bf_matcher_type_strs[type];
1316 : }
1317 :
1318 60 : int bf_matcher_type_from_str(const char *str, enum bf_matcher_type *type)
1319 : {
1320 60 : bf_assert(str);
1321 59 : bf_assert(type);
1322 :
1323 790 : for (size_t i = 0; i < _BF_MATCHER_TYPE_MAX; ++i) {
1324 786 : if (bf_streq(_bf_matcher_type_strs[i], str)) {
1325 54 : *type = i;
1326 54 : return 0;
1327 : }
1328 : }
1329 :
1330 : return -EINVAL;
1331 : }
1332 :
1333 : static const char *_bf_matcher_ops_strs[] = {
1334 : [BF_MATCHER_EQ] = "eq", [BF_MATCHER_NE] = "not",
1335 : [BF_MATCHER_ANY] = "any", [BF_MATCHER_ALL] = "all",
1336 : [BF_MATCHER_IN] = "in", [BF_MATCHER_RANGE] = "range",
1337 : };
1338 :
1339 : static_assert(ARRAY_SIZE(_bf_matcher_ops_strs) == _BF_MATCHER_OP_MAX);
1340 :
1341 8 : const char *bf_matcher_op_to_str(enum bf_matcher_op op)
1342 : {
1343 8 : bf_assert(0 <= op && op < _BF_MATCHER_OP_MAX);
1344 :
1345 6 : return _bf_matcher_ops_strs[op];
1346 : }
1347 :
1348 0 : int bf_matcher_op_from_str(const char *str, enum bf_matcher_op *op)
1349 : {
1350 0 : bf_assert(str);
1351 0 : bf_assert(op);
1352 :
1353 0 : for (size_t i = 0; i < _BF_MATCHER_OP_MAX; ++i) {
1354 0 : if (bf_streq(_bf_matcher_ops_strs[i], str)) {
1355 0 : *op = i;
1356 0 : return 0;
1357 : }
1358 : }
1359 :
1360 : return -EINVAL;
1361 : }
1362 :
1363 : static const char *_bf_tcp_flags_strs[] = {
1364 : [BF_TCP_FIN] = "fin", [BF_TCP_SYN] = "syn", [BF_TCP_RST] = "rst",
1365 : [BF_TCP_PSH] = "psh", [BF_TCP_ACK] = "ack", [BF_TCP_URG] = "urg",
1366 : [BF_TCP_ECE] = "ece", [BF_TCP_CWR] = "cwr",
1367 : };
1368 : static_assert(ARRAY_SIZE(_bf_tcp_flags_strs) == _BF_TCP_MAX);
1369 :
1370 0 : const char *bf_tcp_flag_to_str(enum bf_tcp_flag flag)
1371 : {
1372 0 : bf_assert(0 <= flag && flag < _BF_TCP_MAX);
1373 :
1374 0 : return _bf_tcp_flags_strs[flag];
1375 : }
1376 :
1377 0 : int bf_tcp_flag_from_str(const char *str, enum bf_tcp_flag *flag)
1378 : {
1379 0 : bf_assert(str);
1380 0 : bf_assert(flag);
1381 :
1382 0 : for (size_t i = 0; i < _BF_TCP_MAX; ++i) {
1383 0 : if (bf_streq_i(_bf_tcp_flags_strs[i], str)) {
1384 0 : *flag = i;
1385 0 : return 0;
1386 : }
1387 : }
1388 :
1389 : return -EINVAL;
1390 : }
1391 :
1392 0 : const char *bf_ethertype_to_str(uint16_t ethertype)
1393 : {
1394 0 : switch (ethertype) {
1395 : case ETH_P_IP:
1396 : return "ipv4";
1397 0 : case ETH_P_IPV6:
1398 0 : return "ipv6";
1399 0 : default:
1400 0 : return NULL;
1401 : }
1402 : }
1403 :
1404 0 : int bf_ethertype_from_str(const char *str, uint16_t *ethertype)
1405 : {
1406 0 : bf_assert(str && ethertype);
1407 :
1408 0 : if (bf_streq_i(str, "ipv4")) {
1409 0 : *ethertype = ETH_P_IP;
1410 0 : return 0;
1411 : }
1412 :
1413 0 : if (bf_streq_i(str, "ipv6")) {
1414 0 : *ethertype = ETH_P_IPV6;
1415 0 : return 0;
1416 : }
1417 :
1418 : return -EINVAL;
1419 : }
1420 :
1421 : static const char *_bf_ipproto_strs[UINT8_MAX + 1] = {
1422 : [IPPROTO_HOPOPTS] = "hop", [IPPROTO_ICMP] = "icmp",
1423 : [IPPROTO_IGMP] = "igmp", [IPPROTO_TCP] = "tcp",
1424 : [IPPROTO_UDP] = "udp", [IPPROTO_ROUTING] = "routing",
1425 : [IPPROTO_FRAGMENT] = "frag", [IPPROTO_AH] = "ah",
1426 : [IPPROTO_DSTOPTS] = "dst", [IPPROTO_ICMPV6] = "icmpv6",
1427 : [IPPROTO_MH] = "mh",
1428 : };
1429 : static_assert(ARRAY_SIZE(_bf_ipproto_strs) == (UINT8_MAX + 1),
1430 : "missing entries in IP protocols strings array");
1431 :
1432 0 : const char *bf_ipproto_to_str(uint8_t ipproto)
1433 : {
1434 0 : return _bf_ipproto_strs[ipproto];
1435 : }
1436 :
1437 24 : int bf_ipproto_from_str(const char *str, uint8_t *ipproto)
1438 : {
1439 24 : bf_assert(str && ipproto);
1440 :
1441 236 : for (size_t i = 0; i <= UINT8_MAX; ++i) {
1442 236 : if (bf_streq_i(str, _bf_ipproto_strs[i])) {
1443 24 : *ipproto = (uint8_t)i;
1444 24 : return 0;
1445 : }
1446 : }
1447 :
1448 : return -EINVAL;
1449 : }
1450 :
1451 : #define ICMP_ROUTERADVERT 9
1452 : #define ICMP_ROUTERSOLICIT 10
1453 :
1454 : static const char *_bf_icmp_type_strs[UINT8_MAX + 1] = {
1455 : [ICMP_ECHOREPLY] = "echo-reply",
1456 : [ICMP_DEST_UNREACH] = "destination-unreachable",
1457 : [ICMP_SOURCE_QUENCH] = "source-quench",
1458 : [ICMP_REDIRECT] = "redirect",
1459 : [ICMP_ECHO] = "echo-request",
1460 : [ICMP_ROUTERADVERT] = "router-advertisement",
1461 : [ICMP_ROUTERSOLICIT] = "router-solicitation",
1462 : [ICMP_TIME_EXCEEDED] = "time-exceeded",
1463 : [ICMP_PARAMETERPROB] = "parameter-problem",
1464 : [ICMP_TIMESTAMP] = "timestamp-request",
1465 : [ICMP_TIMESTAMPREPLY] = "timestamp-reply",
1466 : [ICMP_INFO_REQUEST] = "info-request",
1467 : [ICMP_INFO_REPLY] = "info-reply",
1468 : [ICMP_ADDRESS] = "address-mask-request",
1469 : [ICMP_ADDRESSREPLY] = "address-mask-reply",
1470 : };
1471 : static_assert(ARRAY_SIZE(_bf_icmp_type_strs) == (UINT8_MAX + 1),
1472 : "missing entries in ICMP types strings array");
1473 :
1474 0 : const char *bf_icmp_type_to_str(uint8_t type)
1475 : {
1476 0 : return _bf_icmp_type_strs[type];
1477 : }
1478 :
1479 0 : int bf_icmp_type_from_str(const char *str, uint8_t *type)
1480 : {
1481 0 : bf_assert(str && type);
1482 :
1483 0 : for (size_t i = 0; i <= UINT8_MAX; ++i) {
1484 0 : if (bf_streq_i(str, _bf_icmp_type_strs[i])) {
1485 0 : *type = (uint8_t)i;
1486 0 : return 0;
1487 : }
1488 : }
1489 :
1490 : return -EINVAL;
1491 : }
1492 :
1493 : #define ICMPV6_ND_ROUTERSOLICIT 133
1494 : #define ICMPV6_ND_ROUTERADVERT 134
1495 : #define ICMPV6_ND_NEIGHSOLICIT 135
1496 : #define ICMPV6_ND_NEIGHADVERT 136
1497 :
1498 : static const char *_bf_icmpv6_type_strs[UINT8_MAX + 1] = {
1499 : [ICMPV6_DEST_UNREACH] = "destination-unreachable",
1500 : [ICMPV6_PKT_TOOBIG] = "packet-too-big",
1501 : [ICMPV6_TIME_EXCEED] = "time-exceeded",
1502 : [ICMPV6_PARAMPROB] = "parameter-problem",
1503 : [ICMPV6_ECHO_REQUEST] = "echo-request",
1504 : [ICMPV6_ECHO_REPLY] = "echo-reply",
1505 : [ICMPV6_MGM_QUERY] = "mld-listener-query",
1506 : [ICMPV6_MGM_REPORT] = "mld-listener-report",
1507 : [ICMPV6_MGM_REDUCTION] = "mld-listener-reduction",
1508 : [ICMPV6_ND_ROUTERSOLICIT] = "nd-router-solicit",
1509 : [ICMPV6_ND_ROUTERADVERT] = "nd-router-advert",
1510 : [ICMPV6_ND_NEIGHSOLICIT] = "nd-neighbor-solicit",
1511 : [ICMPV6_ND_NEIGHADVERT] = "nd-neighbor-advert",
1512 : [ICMPV6_MLD2_REPORT] = "mld2-listener-report",
1513 : };
1514 : static_assert(ARRAY_SIZE(_bf_icmpv6_type_strs) == (UINT8_MAX + 1),
1515 : "missing entries in ICMPv6 types strings array");
1516 :
1517 0 : const char *bf_icmpv6_type_to_str(uint8_t type)
1518 : {
1519 0 : return _bf_icmpv6_type_strs[type];
1520 : }
1521 :
1522 0 : int bf_icmpv6_type_from_str(const char *str, uint8_t *type)
1523 : {
1524 0 : bf_assert(str && type);
1525 :
1526 0 : for (size_t i = 0; i <= UINT8_MAX; ++i) {
1527 0 : if (bf_streq_i(str, _bf_icmpv6_type_strs[i])) {
1528 0 : *type = (uint8_t)i;
1529 0 : return 0;
1530 : }
1531 : }
1532 :
1533 : return -EINVAL;
1534 : }
|