LCOV - code coverage report
Current view: top level - core - matcher.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 20.5 % 395 81
Test Date: 2025-08-19 17:27:08 Functions: 24.0 % 50 12

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

Generated by: LCOV version 2.0-1