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 20 : static int _bf_parse_ipv4_addr(enum bf_matcher_type type, enum bf_matcher_op op,
304 : void *payload, const char *raw_payload)
305 : {
306 20 : bf_assert(payload && raw_payload);
307 :
308 : int r;
309 :
310 20 : r = inet_pton(AF_INET, raw_payload, payload);
311 20 : if (r == 1)
312 : return 0;
313 :
314 0 : bf_err(
315 : "\"%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' ",
316 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
317 :
318 : return -EINVAL;
319 : }
320 :
321 0 : void _bf_print_ipv4_addr(const void *payload)
322 : {
323 0 : bf_assert(payload);
324 :
325 : char str[INET4_ADDRSTRLEN];
326 :
327 0 : if (inet_ntop(AF_INET, payload, str, INET4_ADDRSTRLEN))
328 0 : (void)fprintf(stdout, "%s", str);
329 : else
330 0 : (void)fprintf(stdout, "<failed to print IPv4 address>");
331 0 : }
332 :
333 : #define BF_IPV4_NET_MAX_LEN \
334 : 32 // 255.255.255.255/32, with nul char, round to **2
335 :
336 0 : static int _bf_parse_ipv4_net(enum bf_matcher_type type, enum bf_matcher_op op,
337 : void *payload, const char *raw_payload)
338 : {
339 0 : bf_assert(payload && raw_payload);
340 :
341 : struct bf_ip4_lpm_key *addr = payload;
342 : char buf[BF_IPV4_NET_MAX_LEN];
343 : char *strip, *strmask, *endptr;
344 : int r;
345 :
346 0 : bf_strncpy(buf, BF_IPV4_NET_MAX_LEN, raw_payload);
347 :
348 0 : if (!isdigit(*raw_payload))
349 0 : goto err;
350 :
351 0 : strip = strtok_r(buf, "/", &strmask);
352 0 : if (!strip || !*strmask)
353 0 : goto err;
354 :
355 0 : r = inet_pton(AF_INET, strip, &addr->data);
356 0 : if (r != 1)
357 0 : goto err;
358 :
359 0 : addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
360 0 : if (*endptr != '\0' || addr->prefixlen > 32)
361 0 : goto err;
362 :
363 : return 0;
364 :
365 0 : err:
366 0 : bf_err(
367 : "\"%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' ",
368 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
369 :
370 : return -EINVAL;
371 : }
372 :
373 0 : void _bf_print_ipv4_net(const void *payload)
374 : {
375 0 : bf_assert(payload);
376 :
377 : char str[INET4_ADDRSTRLEN];
378 : const struct bf_ip4_lpm_key *addr = payload;
379 :
380 0 : if (inet_ntop(AF_INET, &addr->data, str, INET4_ADDRSTRLEN))
381 0 : (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
382 : else
383 0 : (void)fprintf(stdout, "<failed to print IPv4 network>");
384 0 : }
385 :
386 0 : static int _bf_parse_ipv6_addr(enum bf_matcher_type type, enum bf_matcher_op op,
387 : void *payload, const char *raw_payload)
388 : {
389 0 : bf_assert(payload && raw_payload);
390 :
391 : int r;
392 :
393 0 : r = inet_pton(AF_INET6, raw_payload, payload);
394 0 : if (r == 1)
395 : return 0;
396 :
397 0 : bf_err(
398 : "\"%s %s\" expects an IPv6 address composed of 8 hexadecimal numbers (abbreviations are supported), not '%s' ",
399 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
400 :
401 : return -EINVAL;
402 : }
403 :
404 0 : void _bf_print_ipv6_addr(const void *payload)
405 : {
406 0 : bf_assert(payload);
407 :
408 : char str[INET6_ADDRSTRLEN];
409 :
410 0 : if (inet_ntop(AF_INET6, payload, str, INET6_ADDRSTRLEN))
411 0 : (void)fprintf(stdout, "%s", str);
412 : else
413 0 : (void)fprintf(stdout, "<failed to print IPv6 address>");
414 0 : }
415 :
416 : #define BF_IPV6_NET_MAX_LEN (INET6_ADDRSTRLEN + 4)
417 :
418 0 : static int _bf_parse_ipv6_net(enum bf_matcher_type type, enum bf_matcher_op op,
419 : void *payload, const char *raw_payload)
420 : {
421 0 : bf_assert(payload && raw_payload);
422 :
423 : struct bf_ip6_lpm_key *addr = payload;
424 : char buf[BF_IPV6_NET_MAX_LEN];
425 : char *strip, *strmask, *endptr;
426 : int r;
427 :
428 0 : bf_strncpy(buf, BF_IPV6_NET_MAX_LEN, raw_payload);
429 :
430 0 : if (!isalpha(*raw_payload) && !isdigit(*raw_payload) && *raw_payload != ':')
431 0 : goto err;
432 :
433 0 : strip = strtok_r(buf, "/", &strmask);
434 0 : if (!strip || !*strmask)
435 0 : goto err;
436 :
437 0 : r = inet_pton(AF_INET6, strip, &addr->data);
438 0 : if (r != 1)
439 0 : goto err;
440 :
441 0 : addr->prefixlen = strtoul(strmask, &endptr, BF_BASE_10);
442 0 : if (*endptr != '\0' || addr->prefixlen > 128)
443 0 : goto err;
444 :
445 : return 0;
446 :
447 0 : err:
448 0 : bf_err(
449 : "\"%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' ",
450 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
451 :
452 : return -EINVAL;
453 : }
454 :
455 0 : void _bf_print_ipv6_net(const void *payload)
456 : {
457 0 : bf_assert(payload);
458 :
459 : const struct bf_ip6_lpm_key *addr = payload;
460 : char str[INET6_ADDRSTRLEN];
461 :
462 0 : if (inet_ntop(AF_INET6, addr->data, str, INET6_ADDRSTRLEN))
463 0 : (void)fprintf(stdout, "%s/%u", str, addr->prefixlen);
464 : else
465 0 : (void)fprintf(stdout, "<failed to print IPv6 address>");
466 0 : }
467 :
468 0 : static int _bf_parse_tcp_flags(enum bf_matcher_type type, enum bf_matcher_op op,
469 : void *payload, const char *raw_payload)
470 : {
471 0 : bf_assert(payload && raw_payload);
472 :
473 : _cleanup_free_ char *_raw_payload = NULL;
474 : char *tmp;
475 : char *saveptr;
476 : char *token;
477 : uint8_t *flags = payload;
478 :
479 0 : _raw_payload = strdup(raw_payload);
480 : if (!raw_payload)
481 : goto err;
482 :
483 0 : *flags = 0;
484 : tmp = _raw_payload;
485 :
486 0 : while ((token = strtok_r(tmp, ",", &saveptr))) {
487 : enum bf_tcp_flag new_flag;
488 : int r;
489 :
490 0 : r = bf_tcp_flag_from_str(token, &new_flag);
491 0 : if (r)
492 0 : goto err;
493 :
494 0 : *flags |= (uint8_t)(1 << new_flag);
495 :
496 : tmp = NULL;
497 : }
498 :
499 : return 0;
500 :
501 : err:
502 0 : bf_err(
503 : "\"%s %s\" expects a comma-separated list of one or more TCP flags (fin, syn, rst, psh, ack, urg, ece, or cwr), not '%s' ",
504 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
505 :
506 : return -EINVAL;
507 : }
508 :
509 0 : void _bf_print_tcp_flags(const void *payload)
510 : {
511 0 : bf_assert(payload);
512 :
513 0 : uint8_t flag = *(uint8_t *)payload;
514 :
515 0 : for (uint32_t i = 0; i < _BF_TCP_MAX; ++i) {
516 0 : if (flag & (1 << i)) {
517 0 : flag &= ~(1 << i);
518 0 : (void)fprintf(stdout, "%s%s", bf_tcp_flag_to_str(i),
519 : flag ? "," : "");
520 : }
521 : }
522 0 : }
523 :
524 0 : static int _bf_parse_icmp_type(enum bf_matcher_type type, enum bf_matcher_op op,
525 : void *payload, const char *raw_payload)
526 : {
527 0 : bf_assert(payload && raw_payload);
528 :
529 : unsigned long icmptype;
530 : char *endptr;
531 : int r;
532 :
533 0 : r = bf_icmp_type_from_str(raw_payload, payload);
534 0 : if (!r)
535 : return 0;
536 :
537 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
538 :
539 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
540 0 : *(uint8_t *)payload = (uint8_t)icmptype;
541 0 : return 0;
542 : }
543 :
544 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
545 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
546 0 : *(uint8_t *)payload = (uint8_t)icmptype;
547 0 : return 0;
548 : }
549 :
550 0 : bf_err(
551 : "\"%s %s\" expects an ICMP type name (e.g. \"echo-reply\", case insensitive), or or a decimal or hexadecimal ICMP type value, not '%s'",
552 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
553 :
554 : return -EINVAL;
555 : }
556 :
557 0 : void _bf_print_icmp_type(const void *payload)
558 : {
559 0 : bf_assert(payload);
560 :
561 0 : const char *type = bf_icmp_type_to_str(*(uint8_t *)payload);
562 :
563 0 : if (type)
564 0 : (void)fprintf(stdout, "%s", type);
565 : else
566 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
567 0 : }
568 :
569 0 : static int _bf_parse_icmp_code(enum bf_matcher_type type, enum bf_matcher_op op,
570 : void *payload, const char *raw_payload)
571 : {
572 0 : bf_assert(payload && raw_payload);
573 :
574 : unsigned long code;
575 : char *endptr;
576 :
577 0 : code = strtoul(raw_payload, &endptr, BF_BASE_10);
578 0 : if (*endptr == '\0' && code <= UINT8_MAX) {
579 0 : *(uint8_t *)payload = (uint8_t)code;
580 0 : return 0;
581 : }
582 :
583 0 : code = strtoul(raw_payload, &endptr, BF_BASE_16);
584 0 : if (*endptr == '\0' && code <= UINT8_MAX) {
585 0 : *(uint8_t *)payload = (uint8_t)code;
586 0 : return 0;
587 : }
588 :
589 0 : bf_err(
590 : "\"%s %s\" expects a decimal or hexadecimal ICMP or ICMPv6 code value, not '%s'",
591 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
592 :
593 : return -EINVAL;
594 : }
595 :
596 0 : void _bf_print_icmp_code(const void *payload)
597 : {
598 0 : bf_assert(payload);
599 :
600 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
601 0 : }
602 :
603 0 : static int _bf_parse_icmpv6_type(enum bf_matcher_type type,
604 : enum bf_matcher_op op, void *payload,
605 : const char *raw_payload)
606 : {
607 0 : bf_assert(payload && raw_payload);
608 :
609 : unsigned long icmptype;
610 : char *endptr;
611 : int r;
612 :
613 0 : r = bf_icmpv6_type_from_str(raw_payload, payload);
614 0 : if (!r)
615 : return 0;
616 :
617 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_10);
618 :
619 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
620 0 : *(uint8_t *)payload = (uint8_t)icmptype;
621 0 : return 0;
622 : }
623 :
624 0 : icmptype = strtoul(raw_payload, &endptr, BF_BASE_16);
625 0 : if (*endptr == '\0' && icmptype <= UINT8_MAX) {
626 0 : *(uint8_t *)payload = (uint8_t)icmptype;
627 0 : return 0;
628 : }
629 :
630 0 : bf_err(
631 : "\"%s %s\" expects an ICMPv6 type name (e.g. \"echo-reply\", case insensitive), or a decimal or hexadecimal ICMPv6 type value, not '%s'",
632 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op), raw_payload);
633 :
634 : return -EINVAL;
635 : }
636 :
637 0 : void _bf_print_icmpv6_type(const void *payload)
638 : {
639 0 : bf_assert(payload);
640 :
641 0 : const char *type = bf_icmpv6_type_to_str(*(uint8_t *)payload);
642 :
643 0 : if (type)
644 0 : (void)fprintf(stdout, "%s", type);
645 : else
646 0 : (void)fprintf(stdout, "%" PRIu8, *(uint8_t *)payload);
647 0 : }
648 :
649 : #define BF_MATCHER_OPS(op, payload_size, parse_cb, print_cb) \
650 : [op] = {payload_size, parse_cb, print_cb}
651 :
652 : #define _BF_TCP_FLAGS_OFFSET 13
653 :
654 : static struct bf_matcher_meta _bf_matcher_metas[_BF_MATCHER_TYPE_MAX] = {
655 : [BF_MATCHER_META_IFACE] =
656 : {
657 : .layer = BF_MATCHER_NO_LAYER,
658 : .ops =
659 : {
660 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
661 : _bf_parse_iface, _bf_print_iface),
662 : },
663 : },
664 : [BF_MATCHER_META_L3_PROTO] =
665 : {
666 : .layer = BF_MATCHER_NO_LAYER,
667 : .ops =
668 : {
669 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
670 : _bf_parse_l3_proto, _bf_print_l3_proto),
671 : },
672 : },
673 : [BF_MATCHER_META_L4_PROTO] =
674 : {
675 : .layer = BF_MATCHER_NO_LAYER,
676 : .ops =
677 : {
678 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
679 : _bf_parse_l4_proto, _bf_print_l4_proto),
680 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
681 : _bf_parse_l4_proto, _bf_print_l4_proto),
682 : },
683 : },
684 : [BF_MATCHER_META_SPORT] =
685 : {
686 : .layer = BF_MATCHER_NO_LAYER,
687 : .ops =
688 : {
689 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
690 : _bf_parse_l4_port, _bf_print_l4_port),
691 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
692 : _bf_parse_l4_port, _bf_print_l4_port),
693 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
694 : _bf_parse_l4_port_range,
695 : _bf_print_l4_port_range),
696 : },
697 : },
698 : [BF_MATCHER_META_DPORT] =
699 : {
700 : .layer = BF_MATCHER_NO_LAYER,
701 : .ops =
702 : {
703 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
704 : _bf_parse_l4_port, _bf_print_l4_port),
705 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
706 : _bf_parse_l4_port, _bf_print_l4_port),
707 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
708 : _bf_parse_l4_port_range,
709 : _bf_print_l4_port_range),
710 : },
711 : },
712 : [BF_MATCHER_META_PROBABILITY] =
713 : {
714 : .layer = BF_MATCHER_NO_LAYER,
715 : .ops =
716 : {
717 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
718 : _bf_parse_probability,
719 : _bf_print_probability),
720 : },
721 : },
722 : [BF_MATCHER_IP4_SADDR] =
723 : {
724 : .layer = BF_MATCHER_LAYER_3,
725 : .hdr_id = ETH_P_IP,
726 : .hdr_payload_size = sizeof(uint32_t),
727 : .hdr_payload_offset = offsetof(struct iphdr, saddr),
728 : .ops =
729 : {
730 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
731 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
732 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
733 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
734 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
735 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
736 : },
737 : },
738 : [BF_MATCHER_IP4_DADDR] =
739 : {
740 : .layer = BF_MATCHER_LAYER_3,
741 : .hdr_id = ETH_P_IP,
742 : .hdr_payload_size = sizeof(uint32_t),
743 : .hdr_payload_offset = offsetof(struct iphdr, daddr),
744 : .ops =
745 : {
746 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint32_t),
747 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
748 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint32_t),
749 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
750 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint32_t),
751 : _bf_parse_ipv4_addr, _bf_print_ipv4_addr),
752 : },
753 : },
754 : [BF_MATCHER_IP4_SNET] =
755 : {
756 : .layer = BF_MATCHER_LAYER_3,
757 : .hdr_id = ETH_P_IP,
758 : .hdr_payload_size = sizeof(uint32_t),
759 : .hdr_payload_offset = offsetof(struct iphdr, saddr),
760 : .ops =
761 : {
762 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
763 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
764 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
765 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
766 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
767 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
768 : },
769 : },
770 : [BF_MATCHER_IP4_DNET] =
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, daddr),
776 : .ops =
777 : {
778 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip4_lpm_key),
779 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
780 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip4_lpm_key),
781 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
782 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip4_lpm_key),
783 : _bf_parse_ipv4_net, _bf_print_ipv4_net),
784 : },
785 : },
786 : [BF_MATCHER_IP4_PROTO] =
787 : {
788 : .layer = BF_MATCHER_LAYER_3,
789 : .hdr_id = ETH_P_IP,
790 : .hdr_payload_size = sizeof(uint8_t),
791 : .hdr_payload_offset = offsetof(struct iphdr, protocol),
792 : .ops =
793 : {
794 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
795 : _bf_parse_l4_proto, _bf_print_l4_proto),
796 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
797 : _bf_parse_l4_proto, _bf_print_l4_proto),
798 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
799 : _bf_parse_l4_proto, _bf_print_l4_proto),
800 : },
801 : },
802 : [BF_MATCHER_IP6_SADDR] =
803 : {
804 : .layer = BF_MATCHER_LAYER_3,
805 : .hdr_id = ETH_P_IPV6,
806 : .hdr_payload_size = sizeof(struct in6_addr),
807 : .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
808 : .ops =
809 : {
810 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
811 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
812 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
813 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
814 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
815 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
816 : },
817 : },
818 : [BF_MATCHER_IP6_DADDR] =
819 : {
820 : .layer = BF_MATCHER_LAYER_3,
821 : .hdr_id = ETH_P_IPV6,
822 : .hdr_payload_size = sizeof(struct in6_addr),
823 : .hdr_payload_offset = offsetof(struct ipv6hdr, daddr),
824 : .ops =
825 : {
826 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct in6_addr),
827 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
828 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct in6_addr),
829 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
830 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct in6_addr),
831 : _bf_parse_ipv6_addr, _bf_print_ipv6_addr),
832 : },
833 : },
834 : [BF_MATCHER_IP6_SNET] =
835 : {
836 : .layer = BF_MATCHER_LAYER_3,
837 : .hdr_id = ETH_P_IPV6,
838 : .hdr_payload_size = sizeof(struct in6_addr),
839 : .hdr_payload_offset = offsetof(struct ipv6hdr, saddr),
840 : .ops =
841 : {
842 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
843 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
844 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
845 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
846 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
847 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
848 : },
849 : },
850 : [BF_MATCHER_IP6_DNET] =
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, daddr),
856 : .ops =
857 : {
858 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(struct bf_ip6_lpm_key),
859 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
860 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(struct bf_ip6_lpm_key),
861 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
862 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(struct bf_ip6_lpm_key),
863 : _bf_parse_ipv6_net, _bf_print_ipv6_net),
864 : },
865 : },
866 : [BF_MATCHER_IP6_NEXTHDR] =
867 : {
868 : .layer = BF_MATCHER_LAYER_3,
869 : .hdr_id = ETH_P_IPV6,
870 : .hdr_payload_size = sizeof(uint8_t),
871 : .hdr_payload_offset = offsetof(struct ipv6hdr, nexthdr),
872 : .ops =
873 : {
874 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
875 : _bf_parse_l4_proto, _bf_print_l4_proto),
876 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
877 : _bf_parse_l4_proto, _bf_print_l4_proto),
878 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
879 : _bf_parse_l4_proto, _bf_print_l4_proto),
880 : },
881 : },
882 : [BF_MATCHER_TCP_SPORT] =
883 : {
884 : .layer = BF_MATCHER_LAYER_4,
885 : .hdr_id = IPPROTO_TCP,
886 : .hdr_payload_size = sizeof(uint16_t),
887 : .hdr_payload_offset = offsetof(struct tcphdr, source),
888 : .ops =
889 : {
890 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
891 : _bf_parse_l4_port, _bf_print_l4_port),
892 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
893 : _bf_parse_l4_port, _bf_print_l4_port),
894 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
895 : _bf_parse_l4_port, _bf_print_l4_port),
896 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
897 : _bf_parse_l4_port_range,
898 : _bf_print_l4_port_range),
899 : },
900 : },
901 : [BF_MATCHER_TCP_DPORT] =
902 : {
903 : .layer = BF_MATCHER_LAYER_4,
904 : .hdr_id = IPPROTO_TCP,
905 : .hdr_payload_size = sizeof(uint16_t),
906 : .hdr_payload_offset = offsetof(struct tcphdr, dest),
907 : .ops =
908 : {
909 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
910 : _bf_parse_l4_port, _bf_print_l4_port),
911 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
912 : _bf_parse_l4_port, _bf_print_l4_port),
913 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
914 : _bf_parse_l4_port, _bf_print_l4_port),
915 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
916 : _bf_parse_l4_port_range,
917 : _bf_print_l4_port_range),
918 : },
919 : },
920 : [BF_MATCHER_TCP_FLAGS] =
921 : {
922 : .layer = BF_MATCHER_LAYER_4,
923 : .hdr_id = IPPROTO_TCP,
924 : .hdr_payload_size = sizeof(uint8_t),
925 : .hdr_payload_offset = _BF_TCP_FLAGS_OFFSET,
926 : .ops =
927 : {
928 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
929 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
930 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
931 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
932 : BF_MATCHER_OPS(BF_MATCHER_ANY, sizeof(uint8_t),
933 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
934 : BF_MATCHER_OPS(BF_MATCHER_ALL, sizeof(uint8_t),
935 : _bf_parse_tcp_flags, _bf_print_tcp_flags),
936 : },
937 : },
938 : [BF_MATCHER_UDP_SPORT] =
939 : {
940 : .layer = BF_MATCHER_LAYER_4,
941 : .hdr_id = IPPROTO_UDP,
942 : .hdr_payload_size = sizeof(uint16_t),
943 : .hdr_payload_offset = offsetof(struct udphdr, source),
944 : .ops =
945 : {
946 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
947 : _bf_parse_l4_port, _bf_print_l4_port),
948 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
949 : _bf_parse_l4_port, _bf_print_l4_port),
950 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
951 : _bf_parse_l4_port, _bf_print_l4_port),
952 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
953 : _bf_parse_l4_port_range,
954 : _bf_print_l4_port_range),
955 : },
956 : },
957 : [BF_MATCHER_UDP_DPORT] =
958 : {
959 : .layer = BF_MATCHER_LAYER_4,
960 : .hdr_id = IPPROTO_UDP,
961 : .hdr_payload_size = sizeof(uint16_t),
962 : .hdr_payload_offset = offsetof(struct udphdr, dest),
963 : .ops =
964 : {
965 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint16_t),
966 : _bf_parse_l4_port, _bf_print_l4_port),
967 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint16_t),
968 : _bf_parse_l4_port, _bf_print_l4_port),
969 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint16_t),
970 : _bf_parse_l4_port, _bf_print_l4_port),
971 : BF_MATCHER_OPS(BF_MATCHER_RANGE, 2 * sizeof(uint16_t),
972 : _bf_parse_l4_port_range,
973 : _bf_print_l4_port_range),
974 : },
975 : },
976 : [BF_MATCHER_ICMP_TYPE] =
977 : {
978 : .layer = BF_MATCHER_LAYER_4,
979 : .hdr_id = IPPROTO_ICMP,
980 : .hdr_payload_size = sizeof(uint8_t),
981 : .hdr_payload_offset = offsetof(struct icmphdr, type),
982 : .ops =
983 : {
984 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
985 : _bf_parse_icmp_type, _bf_print_icmp_type),
986 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
987 : _bf_parse_icmp_type, _bf_print_icmp_type),
988 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
989 : _bf_parse_icmp_type, _bf_print_icmp_type),
990 : },
991 : },
992 : [BF_MATCHER_ICMP_CODE] =
993 : {
994 : .layer = BF_MATCHER_LAYER_4,
995 : .hdr_id = IPPROTO_ICMP,
996 : .hdr_payload_size = sizeof(uint8_t),
997 : .hdr_payload_offset = offsetof(struct icmphdr, code),
998 : .ops =
999 : {
1000 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1001 : _bf_parse_icmp_code, _bf_print_icmp_code),
1002 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1003 : _bf_parse_icmp_code, _bf_print_icmp_code),
1004 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1005 : _bf_parse_icmp_code, _bf_print_icmp_code),
1006 : },
1007 : },
1008 : [BF_MATCHER_ICMPV6_TYPE] =
1009 : {
1010 : .layer = BF_MATCHER_LAYER_4,
1011 : .hdr_id = IPPROTO_ICMPV6,
1012 : .hdr_payload_size = sizeof(uint8_t),
1013 : .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_type),
1014 : .ops =
1015 : {
1016 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1017 : _bf_parse_icmpv6_type,
1018 : _bf_print_icmpv6_type),
1019 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1020 : _bf_parse_icmpv6_type,
1021 : _bf_print_icmpv6_type),
1022 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1023 : _bf_parse_icmpv6_type,
1024 : _bf_print_icmpv6_type),
1025 : },
1026 : },
1027 : [BF_MATCHER_ICMPV6_CODE] =
1028 : {
1029 : .layer = BF_MATCHER_LAYER_4,
1030 : .hdr_id = IPPROTO_ICMPV6,
1031 : .hdr_payload_size = sizeof(uint8_t),
1032 : .hdr_payload_offset = offsetof(struct icmp6hdr, icmp6_code),
1033 : .ops =
1034 : {
1035 : BF_MATCHER_OPS(BF_MATCHER_EQ, sizeof(uint8_t),
1036 : _bf_parse_icmp_code, _bf_print_icmp_code),
1037 : BF_MATCHER_OPS(BF_MATCHER_NE, sizeof(uint8_t),
1038 : _bf_parse_icmp_code, _bf_print_icmp_code),
1039 : BF_MATCHER_OPS(BF_MATCHER_IN, sizeof(uint8_t),
1040 : _bf_parse_icmp_code, _bf_print_icmp_code),
1041 : },
1042 : },
1043 : };
1044 :
1045 76 : const struct bf_matcher_meta *bf_matcher_get_meta(enum bf_matcher_type type)
1046 : {
1047 76 : if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
1048 : return NULL;
1049 :
1050 75 : return _bf_matcher_metas[type].layer == _BF_MATCHER_LAYER_UNDEFINED ?
1051 75 : NULL :
1052 : &_bf_matcher_metas[type];
1053 : }
1054 :
1055 76 : const struct bf_matcher_ops *bf_matcher_get_ops(enum bf_matcher_type type,
1056 : enum bf_matcher_op op)
1057 : {
1058 76 : const struct bf_matcher_meta *meta = bf_matcher_get_meta(type);
1059 :
1060 76 : if (!meta)
1061 : return NULL;
1062 :
1063 75 : return meta->ops[op].ref_payload_size ? &meta->ops[op] : NULL;
1064 : }
1065 :
1066 58 : int bf_matcher_new(struct bf_matcher **matcher, enum bf_matcher_type type,
1067 : enum bf_matcher_op op, const void *payload,
1068 : size_t payload_len)
1069 : {
1070 56 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
1071 :
1072 58 : bf_assert(matcher);
1073 57 : bf_assert((payload && payload_len) || (!payload && !payload_len));
1074 :
1075 56 : _matcher = malloc(sizeof(struct bf_matcher) + payload_len);
1076 56 : if (!_matcher)
1077 : return -ENOMEM;
1078 :
1079 54 : _matcher->type = type;
1080 54 : _matcher->op = op;
1081 54 : _matcher->len = sizeof(struct bf_matcher) + payload_len;
1082 54 : bf_memcpy(_matcher->payload, payload, payload_len);
1083 :
1084 54 : *matcher = TAKE_PTR(_matcher);
1085 :
1086 54 : return 0;
1087 : }
1088 :
1089 0 : int bf_matcher_new_from_raw(struct bf_matcher **matcher,
1090 : enum bf_matcher_type type, enum bf_matcher_op op,
1091 : const char *payload)
1092 : {
1093 0 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
1094 : const struct bf_matcher_ops *ops;
1095 : int r;
1096 :
1097 0 : bf_assert(matcher && payload);
1098 :
1099 0 : ops = bf_matcher_get_ops(type, op);
1100 0 : if (!ops) {
1101 0 : return bf_err_r(-ENOENT, "payload ops not found for '%s %s'",
1102 : bf_matcher_type_to_str(type), bf_matcher_op_to_str(op));
1103 : }
1104 :
1105 0 : _matcher = malloc(sizeof(*_matcher) + ops->ref_payload_size);
1106 0 : if (!_matcher)
1107 : return -ENOMEM;
1108 :
1109 0 : _matcher->type = type;
1110 0 : _matcher->op = op;
1111 0 : _matcher->len = sizeof(*_matcher) + ops->ref_payload_size;
1112 :
1113 0 : r = ops->parse(_matcher->type, _matcher->op, &_matcher->payload, payload);
1114 0 : if (r)
1115 : return r;
1116 :
1117 0 : *matcher = TAKE_PTR(_matcher);
1118 :
1119 0 : return 0;
1120 : }
1121 :
1122 23 : int bf_matcher_new_from_pack(struct bf_matcher **matcher, bf_rpack_node_t node)
1123 : {
1124 23 : _free_bf_matcher_ struct bf_matcher *_matcher = NULL;
1125 : enum bf_matcher_type type;
1126 : enum bf_matcher_op op;
1127 : const void *payload;
1128 : size_t payload_len;
1129 : int r;
1130 :
1131 23 : bf_assert(matcher);
1132 :
1133 23 : r = bf_rpack_kv_enum(node, "type", &type);
1134 : if (r)
1135 0 : return bf_rpack_key_err(r, "bf_matcher.type");
1136 :
1137 23 : r = bf_rpack_kv_enum(node, "op", &op);
1138 : if (r)
1139 0 : return bf_rpack_key_err(r, "bf_matcher.op");
1140 :
1141 23 : r = bf_rpack_kv_bin(node, "payload", &payload, &payload_len);
1142 23 : if (r)
1143 0 : return bf_rpack_key_err(r, "bf_matcher.payload");
1144 :
1145 23 : r = bf_matcher_new(&_matcher, type, op, payload, payload_len);
1146 23 : if (r)
1147 0 : return bf_err_r(r, "failed to create bf_matcher from pack");
1148 :
1149 23 : *matcher = TAKE_PTR(_matcher);
1150 :
1151 23 : return 0;
1152 : }
1153 :
1154 166 : void bf_matcher_free(struct bf_matcher **matcher)
1155 : {
1156 166 : bf_assert(matcher);
1157 :
1158 165 : if (!*matcher)
1159 : return;
1160 :
1161 54 : free(*matcher);
1162 54 : *matcher = NULL;
1163 : }
1164 :
1165 25 : int bf_matcher_pack(const struct bf_matcher *matcher, bf_wpack_t *pack)
1166 : {
1167 25 : bf_assert(matcher);
1168 24 : bf_assert(pack);
1169 :
1170 23 : bf_wpack_kv_int(pack, "type", matcher->type);
1171 23 : bf_wpack_kv_int(pack, "op", matcher->op);
1172 23 : bf_wpack_kv_bin(pack, "payload", matcher->payload,
1173 23 : matcher->len - sizeof(*matcher));
1174 :
1175 23 : return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
1176 : }
1177 :
1178 0 : void bf_matcher_dump(const struct bf_matcher *matcher, prefix_t *prefix)
1179 : {
1180 0 : bf_assert(matcher);
1181 0 : bf_assert(prefix);
1182 :
1183 0 : DUMP(prefix, "struct bf_matcher at %p", matcher);
1184 :
1185 0 : bf_dump_prefix_push(prefix);
1186 :
1187 0 : DUMP(prefix, "type: %s", bf_matcher_type_to_str(matcher->type));
1188 0 : DUMP(prefix, "op: %s", bf_matcher_op_to_str(matcher->op));
1189 0 : DUMP(prefix, "len: %ld", matcher->len);
1190 0 : DUMP(bf_dump_prefix_last(prefix), "payload:");
1191 0 : bf_dump_prefix_push(prefix);
1192 0 : bf_dump_hex(prefix, matcher->payload,
1193 0 : matcher->len - sizeof(struct bf_matcher));
1194 0 : bf_dump_prefix_pop(prefix);
1195 :
1196 0 : bf_dump_prefix_pop(prefix);
1197 0 : }
1198 :
1199 30 : enum bf_matcher_type bf_matcher_get_type(const struct bf_matcher *matcher)
1200 : {
1201 30 : bf_assert(matcher);
1202 30 : return matcher->type;
1203 : }
1204 :
1205 0 : enum bf_matcher_op bf_matcher_get_op(const struct bf_matcher *matcher)
1206 : {
1207 0 : bf_assert(matcher);
1208 0 : return matcher->op;
1209 : }
1210 :
1211 0 : const void *bf_matcher_payload(const struct bf_matcher *matcher)
1212 : {
1213 0 : bf_assert(matcher);
1214 0 : return matcher->payload;
1215 : }
1216 :
1217 0 : size_t bf_matcher_payload_len(const struct bf_matcher *matcher)
1218 : {
1219 0 : bf_assert(matcher);
1220 0 : return matcher->len - sizeof(*matcher);
1221 : }
1222 :
1223 0 : size_t bf_matcher_len(const struct bf_matcher *matcher)
1224 : {
1225 0 : bf_assert(matcher);
1226 0 : return matcher->len;
1227 : }
1228 :
1229 : static const char *_bf_matcher_type_strs[] = {
1230 : [BF_MATCHER_META_IFACE] = "meta.iface",
1231 : [BF_MATCHER_META_L3_PROTO] = "meta.l3_proto",
1232 : [BF_MATCHER_META_L4_PROTO] = "meta.l4_proto",
1233 : [BF_MATCHER_META_PROBABILITY] = "meta.probability",
1234 : [BF_MATCHER_META_SPORT] = "meta.sport",
1235 : [BF_MATCHER_META_DPORT] = "meta.dport",
1236 : [BF_MATCHER_IP4_SADDR] = "ip4.saddr",
1237 : [BF_MATCHER_IP4_SNET] = "ip4.snet",
1238 : [BF_MATCHER_IP4_DADDR] = "ip4.daddr",
1239 : [BF_MATCHER_IP4_DNET] = "ip4.dnet",
1240 : [BF_MATCHER_IP4_PROTO] = "ip4.proto",
1241 : [BF_MATCHER_IP6_SADDR] = "ip6.saddr",
1242 : [BF_MATCHER_IP6_SNET] = "ip6.snet",
1243 : [BF_MATCHER_IP6_DADDR] = "ip6.daddr",
1244 : [BF_MATCHER_IP6_DNET] = "ip6.dnet",
1245 : [BF_MATCHER_IP6_NEXTHDR] = "ip6.nexthdr",
1246 : [BF_MATCHER_TCP_SPORT] = "tcp.sport",
1247 : [BF_MATCHER_TCP_DPORT] = "tcp.dport",
1248 : [BF_MATCHER_TCP_FLAGS] = "tcp.flags",
1249 : [BF_MATCHER_UDP_SPORT] = "udp.sport",
1250 : [BF_MATCHER_UDP_DPORT] = "udp.dport",
1251 : [BF_MATCHER_ICMP_TYPE] = "icmp.type",
1252 : [BF_MATCHER_ICMP_CODE] = "icmp.code",
1253 : [BF_MATCHER_ICMPV6_TYPE] = "icmpv6.type",
1254 : [BF_MATCHER_ICMPV6_CODE] = "icmpv6.code",
1255 : [BF_MATCHER_SET] = "<set>",
1256 : };
1257 :
1258 : static_assert(ARRAY_SIZE(_bf_matcher_type_strs) == _BF_MATCHER_TYPE_MAX,
1259 : "missing entries in the matcher type array");
1260 :
1261 30 : const char *bf_matcher_type_to_str(enum bf_matcher_type type)
1262 : {
1263 30 : if (type < 0 || _BF_MATCHER_TYPE_MAX <= type)
1264 : return "<invalid>";
1265 :
1266 29 : return _bf_matcher_type_strs[type];
1267 : }
1268 :
1269 59 : int bf_matcher_type_from_str(const char *str, enum bf_matcher_type *type)
1270 : {
1271 59 : bf_assert(str);
1272 58 : bf_assert(type);
1273 :
1274 732 : for (size_t i = 0; i < _BF_MATCHER_TYPE_MAX; ++i) {
1275 728 : if (bf_streq(_bf_matcher_type_strs[i], str)) {
1276 53 : *type = i;
1277 53 : return 0;
1278 : }
1279 : }
1280 :
1281 : return -EINVAL;
1282 : }
1283 :
1284 : static const char *_bf_matcher_ops_strs[] = {
1285 : [BF_MATCHER_EQ] = "eq", [BF_MATCHER_NE] = "not",
1286 : [BF_MATCHER_ANY] = "any", [BF_MATCHER_ALL] = "all",
1287 : [BF_MATCHER_IN] = "in", [BF_MATCHER_RANGE] = "range",
1288 : };
1289 :
1290 : static_assert(ARRAY_SIZE(_bf_matcher_ops_strs) == _BF_MATCHER_OP_MAX);
1291 :
1292 8 : const char *bf_matcher_op_to_str(enum bf_matcher_op op)
1293 : {
1294 8 : bf_assert(0 <= op && op < _BF_MATCHER_OP_MAX);
1295 :
1296 6 : return _bf_matcher_ops_strs[op];
1297 : }
1298 :
1299 0 : int bf_matcher_op_from_str(const char *str, enum bf_matcher_op *op)
1300 : {
1301 0 : bf_assert(str);
1302 0 : bf_assert(op);
1303 :
1304 0 : for (size_t i = 0; i < _BF_MATCHER_OP_MAX; ++i) {
1305 0 : if (bf_streq(_bf_matcher_ops_strs[i], str)) {
1306 0 : *op = i;
1307 0 : return 0;
1308 : }
1309 : }
1310 :
1311 : return -EINVAL;
1312 : }
1313 :
1314 : static const char *_bf_tcp_flags_strs[] = {
1315 : [BF_TCP_FIN] = "fin", [BF_TCP_SYN] = "syn", [BF_TCP_RST] = "rst",
1316 : [BF_TCP_PSH] = "psh", [BF_TCP_ACK] = "ack", [BF_TCP_URG] = "urg",
1317 : [BF_TCP_ECE] = "ece", [BF_TCP_CWR] = "cwr",
1318 : };
1319 : static_assert(ARRAY_SIZE(_bf_tcp_flags_strs) == _BF_TCP_MAX);
1320 :
1321 0 : const char *bf_tcp_flag_to_str(enum bf_tcp_flag flag)
1322 : {
1323 0 : bf_assert(0 <= flag && flag < _BF_TCP_MAX);
1324 :
1325 0 : return _bf_tcp_flags_strs[flag];
1326 : }
1327 :
1328 0 : int bf_tcp_flag_from_str(const char *str, enum bf_tcp_flag *flag)
1329 : {
1330 0 : bf_assert(str);
1331 0 : bf_assert(flag);
1332 :
1333 0 : for (size_t i = 0; i < _BF_TCP_MAX; ++i) {
1334 0 : if (bf_streq_i(_bf_tcp_flags_strs[i], str)) {
1335 0 : *flag = i;
1336 0 : return 0;
1337 : }
1338 : }
1339 :
1340 : return -EINVAL;
1341 : }
1342 :
1343 0 : const char *bf_ethertype_to_str(uint16_t ethertype)
1344 : {
1345 0 : switch (ethertype) {
1346 : case ETH_P_IP:
1347 : return "ipv4";
1348 0 : case ETH_P_IPV6:
1349 0 : return "ipv6";
1350 0 : default:
1351 0 : return NULL;
1352 : }
1353 : }
1354 :
1355 0 : int bf_ethertype_from_str(const char *str, uint16_t *ethertype)
1356 : {
1357 0 : bf_assert(str && ethertype);
1358 :
1359 0 : if (bf_streq_i(str, "ipv4")) {
1360 0 : *ethertype = ETH_P_IP;
1361 0 : return 0;
1362 : }
1363 :
1364 0 : if (bf_streq_i(str, "ipv6")) {
1365 0 : *ethertype = ETH_P_IPV6;
1366 0 : return 0;
1367 : }
1368 :
1369 : return -EINVAL;
1370 : }
1371 :
1372 : static const char *_bf_ipproto_strs[UINT8_MAX + 1] = {
1373 : [IPPROTO_HOPOPTS] = "hop", [IPPROTO_ICMP] = "icmp",
1374 : [IPPROTO_IGMP] = "igmp", [IPPROTO_TCP] = "tcp",
1375 : [IPPROTO_UDP] = "udp", [IPPROTO_ROUTING] = "routing",
1376 : [IPPROTO_FRAGMENT] = "frag", [IPPROTO_AH] = "ah",
1377 : [IPPROTO_DSTOPTS] = "dst", [IPPROTO_ICMPV6] = "icmpv6",
1378 : [IPPROTO_MH] = "mh",
1379 : };
1380 : static_assert(ARRAY_SIZE(_bf_ipproto_strs) == (UINT8_MAX + 1),
1381 : "missing entries in IP protocols strings array");
1382 :
1383 0 : const char *bf_ipproto_to_str(uint8_t ipproto)
1384 : {
1385 0 : return _bf_ipproto_strs[ipproto];
1386 : }
1387 :
1388 24 : int bf_ipproto_from_str(const char *str, uint8_t *ipproto)
1389 : {
1390 24 : bf_assert(str && ipproto);
1391 :
1392 236 : for (size_t i = 0; i <= UINT8_MAX; ++i) {
1393 236 : if (bf_streq_i(str, _bf_ipproto_strs[i])) {
1394 24 : *ipproto = (uint8_t)i;
1395 24 : return 0;
1396 : }
1397 : }
1398 :
1399 : return -EINVAL;
1400 : }
1401 :
1402 : #define ICMP_ROUTERADVERT 9
1403 : #define ICMP_ROUTERSOLICIT 10
1404 :
1405 : static const char *_bf_icmp_type_strs[UINT8_MAX + 1] = {
1406 : [ICMP_ECHOREPLY] = "echo-reply",
1407 : [ICMP_DEST_UNREACH] = "destination-unreachable",
1408 : [ICMP_SOURCE_QUENCH] = "source-quench",
1409 : [ICMP_REDIRECT] = "redirect",
1410 : [ICMP_ECHO] = "echo-request",
1411 : [ICMP_ROUTERADVERT] = "router-advertisement",
1412 : [ICMP_ROUTERSOLICIT] = "router-solicitation",
1413 : [ICMP_TIME_EXCEEDED] = "time-exceeded",
1414 : [ICMP_PARAMETERPROB] = "parameter-problem",
1415 : [ICMP_TIMESTAMP] = "timestamp-request",
1416 : [ICMP_TIMESTAMPREPLY] = "timestamp-reply",
1417 : [ICMP_INFO_REQUEST] = "info-request",
1418 : [ICMP_INFO_REPLY] = "info-reply",
1419 : [ICMP_ADDRESS] = "address-mask-request",
1420 : [ICMP_ADDRESSREPLY] = "address-mask-reply",
1421 : };
1422 : static_assert(ARRAY_SIZE(_bf_icmp_type_strs) == (UINT8_MAX + 1),
1423 : "missing entries in ICMP types strings array");
1424 :
1425 0 : const char *bf_icmp_type_to_str(uint8_t type)
1426 : {
1427 0 : return _bf_icmp_type_strs[type];
1428 : }
1429 :
1430 0 : int bf_icmp_type_from_str(const char *str, uint8_t *type)
1431 : {
1432 0 : bf_assert(str && type);
1433 :
1434 0 : for (size_t i = 0; i <= UINT8_MAX; ++i) {
1435 0 : if (bf_streq_i(str, _bf_icmp_type_strs[i])) {
1436 0 : *type = (uint8_t)i;
1437 0 : return 0;
1438 : }
1439 : }
1440 :
1441 : return -EINVAL;
1442 : }
1443 :
1444 : #define ICMPV6_ND_ROUTERSOLICIT 133
1445 : #define ICMPV6_ND_ROUTERADVERT 134
1446 : #define ICMPV6_ND_NEIGHSOLICIT 135
1447 : #define ICMPV6_ND_NEIGHADVERT 136
1448 :
1449 : static const char *_bf_icmpv6_type_strs[UINT8_MAX + 1] = {
1450 : [ICMPV6_DEST_UNREACH] = "destination-unreachable",
1451 : [ICMPV6_PKT_TOOBIG] = "packet-too-big",
1452 : [ICMPV6_TIME_EXCEED] = "time-exceeded",
1453 : [ICMPV6_PARAMPROB] = "parameter-problem",
1454 : [ICMPV6_ECHO_REQUEST] = "echo-request",
1455 : [ICMPV6_ECHO_REPLY] = "echo-reply",
1456 : [ICMPV6_MGM_QUERY] = "mld-listener-query",
1457 : [ICMPV6_MGM_REPORT] = "mld-listener-report",
1458 : [ICMPV6_MGM_REDUCTION] = "mld-listener-reduction",
1459 : [ICMPV6_ND_ROUTERSOLICIT] = "nd-router-solicit",
1460 : [ICMPV6_ND_ROUTERADVERT] = "nd-router-advert",
1461 : [ICMPV6_ND_NEIGHSOLICIT] = "nd-neighbor-solicit",
1462 : [ICMPV6_ND_NEIGHADVERT] = "nd-neighbor-advert",
1463 : [ICMPV6_MLD2_REPORT] = "mld2-listener-report",
1464 : };
1465 : static_assert(ARRAY_SIZE(_bf_icmpv6_type_strs) == (UINT8_MAX + 1),
1466 : "missing entries in ICMPv6 types strings array");
1467 :
1468 0 : const char *bf_icmpv6_type_to_str(uint8_t type)
1469 : {
1470 0 : return _bf_icmpv6_type_strs[type];
1471 : }
1472 :
1473 0 : int bf_icmpv6_type_from_str(const char *str, uint8_t *type)
1474 : {
1475 0 : bf_assert(str && type);
1476 :
1477 0 : for (size_t i = 0; i <= UINT8_MAX; ++i) {
1478 0 : if (bf_streq_i(str, _bf_icmpv6_type_strs[i])) {
1479 0 : *type = (uint8_t)i;
1480 0 : return 0;
1481 : }
1482 : }
1483 :
1484 : return -EINVAL;
1485 : }
|