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