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