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