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