LCOV - code coverage report
Current view: top level - bpfilter/xlate/nft - nft.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 0.0 % 377 0
Test Date: 2025-02-26 17:59:59 Functions: 0.0 % 13 0

            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 <linux/netfilter.h>
       7              : #include <linux/netfilter/nf_tables.h>
       8              : 
       9              : #include <endian.h>
      10              : #include <errno.h>
      11              : #include <stdbool.h>
      12              : #include <stdint.h>
      13              : #include <stdlib.h>
      14              : #include <unistd.h>
      15              : 
      16              : #include "bpfilter/cgen/cgen.h"
      17              : #include "bpfilter/ctx.h"
      18              : #include "bpfilter/xlate/front.h"
      19              : #include "bpfilter/xlate/nft/nfgroup.h"
      20              : #include "bpfilter/xlate/nft/nfmsg.h"
      21              : #include "core/chain.h"
      22              : #include "core/counter.h"
      23              : #include "core/dump.h"
      24              : #include "core/front.h"
      25              : #include "core/helper.h"
      26              : #include "core/hook.h"
      27              : #include "core/list.h"
      28              : #include "core/logger.h"
      29              : #include "core/marsh.h"
      30              : #include "core/matcher.h"
      31              : #include "core/request.h"
      32              : #include "core/response.h"
      33              : #include "core/rule.h"
      34              : #include "core/verdict.h"
      35              : 
      36              : struct bf_marsh;
      37              : 
      38              : enum
      39              : {
      40              :     BF_IP4HDR_PROTO_OFFSET = 9,
      41              :     BF_IP4HDR_SADDR_OFFSET = 12,
      42              :     BF_IP4HDR_DADDR_OFFSET = 16,
      43              : };
      44              : 
      45              : static const char *_bf_table_name = "bpfilter";
      46              : static const char *_bf_chain_name = "prerouting";
      47              : 
      48              : static int _bf_nft_setup(void);
      49              : static int _bf_nft_teardown(void);
      50              : static int _bf_nft_request_handler(struct bf_request *request,
      51              :                                    struct bf_response **response);
      52              : static int _bf_nft_marsh(struct bf_marsh **marsh);
      53              : static int _bf_nft_unmarsh(struct bf_marsh *marsh);
      54              : 
      55              : const struct bf_front_ops nft_front = {
      56              :     .setup = _bf_nft_setup,
      57              :     .teardown = _bf_nft_teardown,
      58              :     .request_handler = _bf_nft_request_handler,
      59              :     .marsh = _bf_nft_marsh,
      60              :     .unmarsh = _bf_nft_unmarsh,
      61              : };
      62              : 
      63              : static bf_list *_bf_nft_rules = NULL;
      64              : 
      65            0 : static int _bf_nft_setup(void)
      66              : {
      67              :     int r;
      68              : 
      69              :     // If the cache has been restored already, skip this.
      70            0 :     if (_bf_nft_rules)
      71              :         return 0;
      72              : 
      73            0 :     r = bf_list_new(
      74              :         &_bf_nft_rules,
      75            0 :         (bf_list_ops[]) {{.free = (bf_list_ops_free)bf_nfmsg_free}});
      76            0 :     if (r < 0)
      77            0 :         return bf_err_r(r, "failed to create bf_list");
      78              : 
      79              :     return 0;
      80              : }
      81              : 
      82            0 : static int _bf_nft_teardown(void)
      83              : {
      84            0 :     bf_list_free(&_bf_nft_rules);
      85              : 
      86            0 :     return 0;
      87              : }
      88              : 
      89            0 : static int _bf_nft_marsh(struct bf_marsh **marsh)
      90              : {
      91            0 :     bf_assert(marsh);
      92              : 
      93              :     int r = 0;
      94              : 
      95            0 :     bf_list_foreach (_bf_nft_rules, rule_node) {
      96            0 :         struct bf_nfmsg *msg = bf_list_node_get_data(rule_node);
      97              : 
      98            0 :         r = bf_marsh_add_child_raw(marsh, bf_nfmsg_hdr(msg), bf_nfmsg_len(msg));
      99            0 :         if (r < 0)
     100            0 :             return bf_err_r(r, "failed to add rule to marsh");
     101              :     }
     102              : 
     103              :     return 0;
     104              : }
     105              : 
     106            0 : static int _bf_nft_unmarsh(struct bf_marsh *marsh)
     107              : {
     108            0 :     bf_assert(marsh);
     109              : 
     110            0 :     _cleanup_bf_list_ bf_list *list = NULL;
     111              :     struct bf_marsh *child = NULL;
     112              :     int r;
     113              : 
     114            0 :     r = bf_list_new(
     115            0 :         &list, (bf_list_ops[]) {{.free = (bf_list_ops_free)bf_nfmsg_free}});
     116            0 :     if (r < 0)
     117            0 :         return bf_err_r(r, "failed to create bf_list");
     118              : 
     119            0 :     while ((child = bf_marsh_next_child(marsh, child))) {
     120            0 :         _cleanup_bf_nfmsg_ struct bf_nfmsg *msg = NULL;
     121            0 :         struct nlmsghdr *nlh = (struct nlmsghdr *)(child->data);
     122              : 
     123            0 :         r = bf_nfmsg_new_from_nlmsghdr(&msg, nlh);
     124            0 :         if (r < 0)
     125            0 :             return bf_err_r(r, "failed to create bf_nfmsg from marsh");
     126              : 
     127            0 :         r = bf_list_add_tail(list, msg);
     128            0 :         if (r < 0)
     129            0 :             return bf_err_r(r, "failed to add bf_nfmsg to bf_list");
     130            0 :         TAKE_PTR(msg);
     131              :     }
     132              : 
     133            0 :     _bf_nft_rules = TAKE_PTR(list);
     134              : 
     135            0 :     return 0;
     136              : }
     137              : 
     138            0 : static int _bf_nft_getgen_cb(const struct bf_nfmsg *req, struct bf_nfgroup *res)
     139              : {
     140            0 :     bf_assert(req);
     141            0 :     bf_assert(res);
     142              : 
     143            0 :     struct bf_nfmsg *msg = NULL;
     144              :     int r;
     145              : 
     146            0 :     r = bf_nfgroup_add_new_message(res, &msg, NFT_MSG_NEWGEN,
     147            0 :                                    bf_nfmsg_seqnr(req));
     148            0 :     if (r < 0)
     149            0 :         return bf_err_r(r, "failed to create bf_nfmsg");
     150              : 
     151            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_GEN_ID, 0);
     152            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_GEN_PROC_PID, getpid());
     153            0 :     bf_nfmsg_push_str_or_jmp(msg, NFTA_GEN_PROC_NAME, "nft");
     154              : 
     155              :     return 0;
     156              : 
     157              : bf_nfmsg_push_failure:
     158              :     return -EINVAL;
     159              : }
     160              : 
     161            0 : static int _bf_nft_gettable_cb(const struct bf_nfmsg *req,
     162              :                                struct bf_nfgroup *res)
     163              : {
     164            0 :     bf_assert(req);
     165            0 :     bf_assert(res);
     166              : 
     167            0 :     struct bf_nfmsg *msg = NULL;
     168              :     int r;
     169              : 
     170            0 :     r = bf_nfgroup_add_new_message(res, &msg, NFT_MSG_NEWTABLE,
     171            0 :                                    bf_nfmsg_seqnr(req));
     172            0 :     if (r < 0)
     173            0 :         return bf_err_r(r, "failed to create bf_nfmsg");
     174              : 
     175            0 :     bf_nfmsg_push_str_or_jmp(msg, NFTA_TABLE_NAME, _bf_table_name);
     176            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_TABLE_FLAGS, 0);
     177            0 :     bf_nfmsg_push_u64_or_jmp(msg, NFTA_TABLE_HANDLE, 0);
     178            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_TABLE_USE, 1);
     179              : 
     180            0 :     return 0;
     181              : 
     182              : bf_nfmsg_push_failure:
     183              :     return -EINVAL;
     184              : }
     185              : 
     186            0 : static int _bf_nft_newtable_cb(const struct bf_nfmsg *req)
     187              : {
     188            0 :     bf_assert(req);
     189              : 
     190            0 :     bf_nfattr *attrs[__NFTA_TABLE_MAX] = {};
     191              :     int r;
     192              : 
     193            0 :     r = bf_nfmsg_parse(req, attrs, __NFTA_TABLE_MAX, bf_nf_table_policy);
     194            0 :     if (r < 0)
     195            0 :         return bf_err_r(r, "failed to parse NFT_MSG_GETTABLE attributes");
     196              : 
     197            0 :     if (!attrs[NFTA_TABLE_NAME])
     198            0 :         return bf_warn_r(-EINVAL, "missing NFTA_TABLE_NAME attribute");
     199              : 
     200            0 :     if (!bf_streq(bf_nfattr_get_str(attrs[NFTA_TABLE_NAME]), _bf_table_name)) {
     201            0 :         return bf_warn_r(-EINVAL, "invalid table name '%s'",
     202              :                          bf_nfattr_get_str(attrs[NFTA_TABLE_NAME]));
     203              :     }
     204              : 
     205              :     return 0;
     206              : }
     207              : 
     208            0 : static int _bf_nft_newchain_cb(const struct bf_nfmsg *req)
     209              : {
     210            0 :     bf_assert(req);
     211              : 
     212            0 :     _cleanup_bf_cgen_ struct bf_cgen *cgen = NULL;
     213            0 :     _cleanup_bf_chain_ struct bf_chain *chain = NULL;
     214            0 :     bf_nfattr *chain_attrs[__NFTA_CHAIN_MAX] = {};
     215            0 :     bf_nfattr *hook_attrs[__NFTA_HOOK_MAX] = {};
     216              :     enum bf_verdict verdict;
     217              :     int r;
     218              : 
     219            0 :     r = bf_nfmsg_parse(req, chain_attrs, __NFTA_CHAIN_MAX, bf_nf_chain_policy);
     220            0 :     if (r < 0)
     221            0 :         return bf_err_r(r, "failed to parse NFT_MSG_NEWCHAIN attributes");
     222              : 
     223            0 :     if (!chain_attrs[NFTA_CHAIN_TABLE] ||
     224            0 :         !bf_streq(bf_nfattr_get_str(chain_attrs[NFTA_CHAIN_TABLE]),
     225              :                   _bf_table_name))
     226            0 :         return bf_err_r(-EINVAL, "invalid table name");
     227              : 
     228            0 :     if (!chain_attrs[NFTA_CHAIN_NAME] ||
     229            0 :         !bf_streq(bf_nfattr_get_str(chain_attrs[NFTA_CHAIN_NAME]),
     230              :                   _bf_chain_name))
     231            0 :         return bf_err_r(-EINVAL, "invalid table name");
     232              : 
     233            0 :     if (!chain_attrs[NFTA_CHAIN_POLICY])
     234            0 :         return bf_err_r(-EINVAL, "missing NFTA_CHAIN_POLICY attribute");
     235              : 
     236            0 :     if (!chain_attrs[NFTA_CHAIN_HOOK])
     237            0 :         return bf_err_r(-EINVAL, "missing NFTA_CHAIN_HOOK attribute");
     238              : 
     239            0 :     r = bf_nfattr_parse(chain_attrs[NFTA_CHAIN_HOOK], hook_attrs,
     240              :                         __NFTA_HOOK_MAX, bf_nf_hook_policy);
     241            0 :     if (r < 0)
     242            0 :         return bf_err_r(r, "failed to parse NFTA_CHAIN_HOOK attributes");
     243              : 
     244            0 :     if (!hook_attrs[NFTA_HOOK_HOOKNUM] ||
     245              :         NF_INET_PRE_ROUTING !=
     246            0 :             bf_nfattr_get_u32(hook_attrs[NFTA_HOOK_HOOKNUM])) {
     247            0 :         return bf_err_r(
     248              :             -EINVAL, "missing or invalid hook (NF_INET_PRE_ROUTING required)");
     249              :     }
     250              : 
     251            0 :     switch (be32toh(bf_nfattr_get_u32(chain_attrs[NFTA_CHAIN_POLICY]))) {
     252              :     case NF_ACCEPT:
     253              :         verdict = BF_VERDICT_ACCEPT;
     254              :         break;
     255            0 :     case NF_DROP:
     256              :         verdict = BF_VERDICT_DROP;
     257            0 :         break;
     258            0 :     default:
     259            0 :         return bf_err_r(
     260              :             -ENOTSUP, "unsupported policy %u",
     261              :             be32toh(bf_nfattr_get_u32(chain_attrs[NFTA_CHAIN_POLICY])));
     262              :     };
     263              : 
     264            0 :     r = bf_chain_new(&chain, BF_HOOK_NF_LOCAL_IN, verdict, NULL, NULL);
     265            0 :     if (r < 0)
     266            0 :         return bf_err_r(r, "failed to create new chain");
     267              : 
     268            0 :     cgen = bf_ctx_get_cgen(BF_HOOK_NF_LOCAL_IN, NULL);
     269            0 :     if (cgen && verdict != cgen->chain->policy) {
     270            0 :         r = bf_cgen_update(cgen, &chain);
     271            0 :         if (r < 0)
     272            0 :             return bf_err_r(r, "failed to update codegen");
     273              : 
     274            0 :         bf_info("existing codegen updated with new policy");
     275            0 :     } else if (!cgen) {
     276            0 :         r = bf_cgen_new(&cgen, BF_FRONT_NFT, &chain);
     277            0 :         if (r < 0)
     278            0 :             return bf_err_r(r, "failed to create bf_cgen");
     279              : 
     280            0 :         r = bf_cgen_up(cgen);
     281            0 :         if (r < 0)
     282            0 :             return bf_err_r(r, "failed to generate codegen");
     283              : 
     284            0 :         r = bf_ctx_set_cgen(cgen);
     285            0 :         if (r < 0) {
     286            0 :             bf_cgen_unload(cgen);
     287            0 :             return r;
     288              :         }
     289              : 
     290            0 :         bf_info("new codegen created and loaded");
     291              :     } else {
     292            0 :         bf_info("codegen already properly configured, skipping generation");
     293              :     }
     294              : 
     295            0 :     TAKE_PTR(cgen);
     296              : 
     297            0 :     return 0;
     298              : }
     299              : 
     300            0 : static int _bf_nft_getchain_cb(const struct bf_nfmsg *req,
     301              :                                struct bf_nfgroup *res)
     302              : {
     303            0 :     bf_assert(req);
     304            0 :     bf_assert(res);
     305              : 
     306              :     struct bf_nfmsg *msg;
     307              :     struct bf_cgen *cgen;
     308              :     uint32_t policy;
     309              :     int r;
     310              : 
     311              :     // Only BF_HOOK_NF_LOCAL_IN is supported.
     312            0 :     cgen = bf_ctx_get_cgen(BF_HOOK_NF_LOCAL_IN, NULL);
     313            0 :     if (!cgen) {
     314              :         /* If no codegen is found, do not fill the messages group and return
     315              :          * success. The response message will then contain only a DONE
     316              :          * message. */
     317              :         return 0;
     318              :     }
     319              : 
     320            0 :     r = bf_nfgroup_add_new_message(res, &msg, NFT_MSG_NEWCHAIN,
     321            0 :                                    bf_nfmsg_seqnr(req));
     322            0 :     if (r < 0)
     323            0 :         return bf_err_r(r, "failed to create bf_nfmsg");
     324              : 
     325            0 :     bf_cgen_dump(cgen, EMPTY_PREFIX);
     326              : 
     327            0 :     switch (cgen->chain->policy) {
     328              :     case BF_VERDICT_ACCEPT:
     329              :         policy = NF_ACCEPT;
     330              :         break;
     331            0 :     case BF_VERDICT_DROP:
     332              :         policy = NF_DROP;
     333            0 :         break;
     334            0 :     default:
     335            0 :         return bf_err_r(-ENOTSUP, "unsupported codegen policy %u",
     336              :                         cgen->chain->policy);
     337              :     };
     338              : 
     339            0 :     bf_nfmsg_push_str_or_jmp(msg, NFTA_CHAIN_TABLE, _bf_table_name);
     340            0 :     bf_nfmsg_push_str_or_jmp(msg, NFTA_CHAIN_NAME, _bf_chain_name);
     341            0 :     bf_nfmsg_push_u64_or_jmp(msg, NFTA_CHAIN_HANDLE, BF_HOOK_NF_LOCAL_IN);
     342            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_CHAIN_POLICY, htobe32(policy));
     343            0 :     bf_nfmsg_push_str_or_jmp(msg, NFTA_CHAIN_TYPE, "filter");
     344            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_CHAIN_FLAGS, NFT_CHAIN_BASE);
     345            0 :     bf_nfmsg_push_u32_or_jmp(msg, NFTA_CHAIN_USE,
     346              :                              htobe32(bf_list_size(&cgen->chain->rules)));
     347              : 
     348              :     {
     349            0 :         _cleanup_bf_nfnest_ struct bf_nfnest _ =
     350            0 :             bf_nfnest_or_jmp(msg, NFTA_CHAIN_HOOK);
     351              : 
     352            0 :         bf_nfmsg_push_u32_or_jmp(msg, NFTA_HOOK_HOOKNUM,
     353              :                                  htobe32(NF_INET_PRE_ROUTING));
     354            0 :         bf_nfmsg_push_u32_or_jmp(msg, NFTA_HOOK_PRIORITY, htobe32(0));
     355              :     }
     356              : 
     357            0 :     return 0;
     358              : 
     359            0 : bf_nfmsg_push_failure:
     360            0 :     return bf_err_r(-EINVAL, "failed to add attribute to Netlink message");
     361              : }
     362              : 
     363            0 : static int _bf_nft_newrule_cb(const struct bf_nfmsg *req)
     364              : {
     365            0 :     bf_assert(req);
     366              : 
     367            0 :     _cleanup_bf_rule_ struct bf_rule *rule = NULL;
     368            0 :     _cleanup_bf_nfmsg_ struct bf_nfmsg *req_copy;
     369              :     struct bf_chain *chain;
     370              :     struct bf_cgen *cgen;
     371            0 :     bf_nfattr *rule_attrs[__NFTA_RULE_MAX] = {};
     372            0 :     bf_nfattr *expr_attrs[__NFTA_EXPR_MAX] = {};
     373            0 :     bf_nfattr *payload_attrs[__NFTA_PAYLOAD_MAX] = {};
     374            0 :     bf_nfattr *cmp_attrs[__NFTA_CMP_MAX] = {};
     375            0 :     bf_nfattr *data_attrs[__NFTA_DATA_MAX] = {};
     376            0 :     bf_nfattr *immediate_attrs[__NFTA_IMMEDIATE_MAX] = {};
     377            0 :     bf_nfattr *verdict_attrs[__NFTA_VERDICT_MAX] = {};
     378              :     bf_nfattr *parent;
     379              :     bf_nfattr *attr;
     380              :     size_t rem;
     381              :     int r;
     382              : 
     383            0 :     r = bf_nfmsg_parse(req, rule_attrs, __NFTA_RULE_MAX, bf_nf_rule_policy);
     384            0 :     if (r < 0)
     385            0 :         return bf_err_r(r, "failed to parse NFT_MSG_NEWRULE attributes");
     386              : 
     387            0 :     if (!rule_attrs[NFTA_RULE_TABLE] ||
     388            0 :         !bf_streq(bf_nfattr_get_str(rule_attrs[NFTA_RULE_TABLE]),
     389              :                   _bf_table_name))
     390            0 :         return bf_err_r(-EINVAL, "invalid table name");
     391              : 
     392            0 :     if (!rule_attrs[NFTA_RULE_CHAIN] ||
     393            0 :         !bf_streq(bf_nfattr_get_str(rule_attrs[NFTA_RULE_CHAIN]),
     394              :                   _bf_chain_name))
     395            0 :         return bf_err_r(-EINVAL, "invalid chain name");
     396              : 
     397            0 :     parent = rule_attrs[NFTA_RULE_EXPRESSIONS];
     398            0 :     if (!parent)
     399            0 :         return bf_err_r(-EINVAL, "missing NFTA_RULE_EXPRESSIONS attribute");
     400            0 :     rem = bf_nfattr_data_len(parent);
     401              : 
     402            0 :     attr = (bf_nfattr *)bf_nfattr_data(parent);
     403            0 :     if (!bf_nfattr_is_ok(attr, rem))
     404            0 :         return bf_err_r(-EINVAL, "invalid NFTA_RULE_EXPRESSIONS attribute");
     405              : 
     406            0 :     r = bf_nfattr_parse(attr, expr_attrs, __NFTA_EXPR_MAX, bf_nf_expr_policy);
     407            0 :     if (r < 0) {
     408            0 :         return bf_err_r(r, "failed to parse NFTA_RULE_EXPRESSIONS attributes");
     409              :     }
     410              : 
     411            0 :     if (!expr_attrs[NFTA_EXPR_NAME] ||
     412            0 :         !bf_streq(bf_nfattr_get_str(expr_attrs[NFTA_EXPR_NAME]), "payload"))
     413            0 :         return bf_err_r(-EINVAL, "expecting rule expression 'payload'");
     414              : 
     415            0 :     r = bf_nfattr_parse(expr_attrs[NFTA_EXPR_DATA], payload_attrs,
     416              :                         __NFTA_PAYLOAD_MAX, bf_nf_payload_policy);
     417            0 :     if (r < 0)
     418            0 :         return bf_err_r(r, "failed to parse NFTA_EXPR_DATA attributes");
     419              : 
     420            0 :     if (!payload_attrs[NFTA_PAYLOAD_BASE] ||
     421            0 :         be32toh(bf_nfattr_get_u32(payload_attrs[NFTA_PAYLOAD_BASE])) !=
     422              :             NFT_PAYLOAD_NETWORK_HEADER) {
     423            0 :         return bf_err_r(-EINVAL,
     424              :                         "expecting payload base NFT_PAYLOAD_NETWORK_HEADER");
     425              :     }
     426              : 
     427            0 :     uint32_t len = be32toh(bf_nfattr_get_u32(payload_attrs[NFTA_PAYLOAD_LEN]));
     428              :     uint32_t off =
     429            0 :         be32toh(bf_nfattr_get_u32(payload_attrs[NFTA_PAYLOAD_OFFSET]));
     430              : 
     431            0 :     attr = bf_nfattr_next(attr, &rem);
     432            0 :     if (!bf_nfattr_is_ok(attr, rem))
     433            0 :         return bf_err_r(-EINVAL, "invalid NFTA_RULE_EXPRESSIONS attribute");
     434              : 
     435            0 :     r = bf_nfattr_parse(attr, expr_attrs, __NFTA_EXPR_MAX, bf_nf_expr_policy);
     436            0 :     if (r < 0) {
     437            0 :         return bf_err_r(r, "failed to parse NFTA_RULE_EXPRESSIONS attributes");
     438              :     }
     439              : 
     440            0 :     if (!expr_attrs[NFTA_EXPR_NAME] ||
     441            0 :         !bf_streq(bf_nfattr_get_str(expr_attrs[NFTA_EXPR_NAME]), "cmp"))
     442            0 :         return bf_err_r(-EINVAL, "expecting rule expression 'cmp'");
     443              : 
     444            0 :     r = bf_nfattr_parse(expr_attrs[NFTA_EXPR_DATA], cmp_attrs, __NFTA_CMP_MAX,
     445              :                         bf_nf_cmp_policy);
     446            0 :     if (r < 0)
     447            0 :         return bf_err_r(r, "failed to parse NFTA_EXPR_DATA attributes");
     448              : 
     449            0 :     uint32_t op = be32toh(bf_nfattr_get_u32(cmp_attrs[NFTA_CMP_OP]));
     450            0 :     if (op != NFT_CMP_EQ)
     451            0 :         return bf_err_r(-EINVAL, "only NFTA_CMP_OP is supported");
     452              : 
     453            0 :     r = bf_nfattr_parse(cmp_attrs[NFTA_CMP_DATA], data_attrs, __NFTA_DATA_MAX,
     454              :                         bf_nf_data_policy);
     455            0 :     if (r < 0)
     456            0 :         return bf_err_r(r, "failed to parse NFTA_CMP_DATA attributes");
     457              : 
     458              :     uint32_t cmp_value =
     459            0 :         be32toh(bf_nfattr_get_u32(data_attrs[NFTA_DATA_VALUE]));
     460              : 
     461            0 :     attr = bf_nfattr_next(attr, &rem);
     462            0 :     if (!bf_nfattr_is_ok(attr, rem))
     463            0 :         return bf_err_r(-EINVAL, "invalid NFTA_RULE_EXPRESSIONS attribute");
     464              : 
     465            0 :     r = bf_nfattr_parse(attr, expr_attrs, __NFTA_EXPR_MAX, bf_nf_expr_policy);
     466            0 :     if (r < 0) {
     467            0 :         return bf_err_r(r, "failed to parse NFTA_RULE_EXPRESSIONS attributes");
     468              :     }
     469              : 
     470              :     bool counter = false;
     471            0 :     if (bf_streq(bf_nfattr_data(expr_attrs[NFTA_EXPR_NAME]), "counter")) {
     472              :         counter = true;
     473              : 
     474            0 :         attr = bf_nfattr_next(attr, &rem);
     475            0 :         if (!bf_nfattr_is_ok(attr, rem))
     476            0 :             return bf_err_r(-EINVAL, "expecting cmp, got invalid attribute");
     477              : 
     478            0 :         r = bf_nfattr_parse(attr, expr_attrs, __NFTA_EXPR_MAX,
     479              :                             bf_nf_expr_policy);
     480            0 :         if (r < 0) {
     481            0 :             return bf_err_r(r,
     482              :                             "failed to parse NFTA_RULE_EXPRESSIONS attributes");
     483              :         }
     484              :     }
     485              : 
     486            0 :     if (!bf_streq(bf_nfattr_data(expr_attrs[NFTA_EXPR_NAME]), "immediate")) {
     487            0 :         return bf_err_r(r,
     488              :                         "expected immediate attribute, but have '%s' instead",
     489              :                         bf_nfattr_get_str(expr_attrs[NFTA_EXPR_NAME]));
     490              :     }
     491              : 
     492            0 :     r = bf_nfattr_parse(expr_attrs[NFTA_EXPR_DATA], immediate_attrs,
     493              :                         __NFTA_IMMEDIATE_MAX, bf_nf_immediate_policy);
     494            0 :     if (r < 0)
     495            0 :         return bf_err_r(r, "failed to parse NFTA_EXPR_DATA attributes");
     496              : 
     497            0 :     r = bf_nfattr_parse(immediate_attrs[NFTA_IMMEDIATE_DATA], data_attrs,
     498              :                         __NFTA_DATA_MAX, bf_nf_data_policy);
     499            0 :     if (r < 0)
     500            0 :         return bf_err_r(r, "failed to parse NFTA_IMMEDIATE_DATA attributes");
     501              : 
     502            0 :     if (!data_attrs[NFTA_DATA_VERDICT])
     503            0 :         return bf_err_r(-EINVAL, "missing NFTA_DATA_VERDICT attribute");
     504              : 
     505            0 :     r = bf_nfattr_parse(data_attrs[NFTA_DATA_VERDICT], verdict_attrs,
     506              :                         __NFTA_VERDICT_MAX, bf_nf_verdict_policy);
     507            0 :     if (r < 0)
     508            0 :         return bf_err_r(r, "failed to parse NFTA_DATA_VERDICT attributes");
     509              : 
     510            0 :     if (!verdict_attrs[NFTA_VERDICT_CODE])
     511            0 :         return bf_err_r(-EINVAL, "missing NFTA_VERDICT_CODE attribute");
     512              : 
     513            0 :     int32_t nf_verdict =
     514            0 :         be32toh(bf_nfattr_get_s32(verdict_attrs[NFTA_VERDICT_CODE]));
     515              : 
     516              :     enum bf_verdict verdict;
     517            0 :     switch (nf_verdict) {
     518              :     case NF_ACCEPT:
     519              :         verdict = BF_VERDICT_ACCEPT;
     520              :         break;
     521              :     case NF_DROP:
     522              :         verdict = BF_VERDICT_DROP;
     523              :         break;
     524              :     case NFT_CONTINUE:
     525              :         verdict = BF_VERDICT_CONTINUE;
     526              :         break;
     527            0 :     default:
     528            0 :         return bf_err_r(
     529              :             -EINVAL, "only ACCEPT, DROP and CONTINUE verdicts are supported");
     530              :     }
     531              : 
     532              :     // Add the rule to the relevant codegen
     533            0 :     cgen = bf_ctx_get_cgen(BF_HOOK_NF_LOCAL_IN, NULL);
     534            0 :     if (!cgen)
     535            0 :         return bf_err_r(-EINVAL, "no codegen found for hook");
     536              : 
     537            0 :     r = bf_rule_new(&rule);
     538            0 :     if (r < 0)
     539            0 :         return bf_err_r(r, "failed to create bf_rule");
     540              : 
     541            0 :     rule->counters = counter;
     542            0 :     switch (off) {
     543              :     case BF_IP4HDR_PROTO_OFFSET:
     544            0 :         r = bf_rule_add_matcher(rule, BF_MATCHER_IP4_PROTO, BF_MATCHER_EQ,
     545            0 :                                 (uint16_t[]) {htobe32(cmp_value)},
     546              :                                 sizeof(uint16_t));
     547            0 :         if (r)
     548            0 :             return r;
     549            0 :         break;
     550              :     case BF_IP4HDR_SADDR_OFFSET:
     551            0 :         r = bf_rule_add_matcher(
     552              :             rule, BF_MATCHER_IP4_SRC_ADDR, BF_MATCHER_EQ,
     553            0 :             (struct bf_matcher_ip4_addr[]) {
     554            0 :                 {.addr = htobe32(cmp_value), .mask = ~0ULL >> (32 - len * 8)}},
     555              :             sizeof(struct bf_matcher_ip4_addr));
     556            0 :         if (r)
     557              :             return r;
     558              :         break;
     559              :     case BF_IP4HDR_DADDR_OFFSET:
     560            0 :         r = bf_rule_add_matcher(
     561              :             rule, BF_MATCHER_IP4_DST_ADDR, BF_MATCHER_EQ,
     562            0 :             (struct bf_matcher_ip4_addr[]) {
     563            0 :                 {.addr = htobe32(cmp_value), .mask = ~0ULL >> (32 - len * 8)}},
     564              :             sizeof(struct bf_matcher_ip4_addr));
     565            0 :         if (r)
     566              :             return r;
     567              :         break;
     568            0 :     default:
     569            0 :         return bf_err_r(-EINVAL, "unknown IP header offset %d", off);
     570              :     };
     571              : 
     572            0 :     chain = cgen->chain;
     573              : 
     574            0 :     rule->verdict = verdict;
     575            0 :     rule->index = bf_list_size(&cgen->chain->rules);
     576            0 :     r = bf_chain_add_rule(chain, rule);
     577            0 :     if (r < 0)
     578            0 :         return bf_err_r(r, "failed to add rule to chain");
     579            0 :     TAKE_PTR(rule);
     580              : 
     581            0 :     r = bf_cgen_update(cgen, &cgen->chain);
     582            0 :     if (r < 0)
     583            0 :         return bf_err_r(r, "failed to update codegen");
     584              : 
     585              :     // Backup the rule in the front-end context
     586            0 :     r = bf_nfmsg_new_from_nlmsghdr(&req_copy, bf_nfmsg_hdr(req));
     587            0 :     if (r < 0)
     588            0 :         return bf_err_r(r, "failed to create bf_nfmsg from nlmsghdr");
     589              : 
     590            0 :     r = bf_list_add_tail(_bf_nft_rules, req_copy);
     591            0 :     if (r < 0)
     592            0 :         return bf_err_r(r, "failed to add rule to bf_list");
     593            0 :     TAKE_PTR(req_copy);
     594              : 
     595            0 :     return 0;
     596              : }
     597              : 
     598            0 : static int _bf_nft_getrule_cb(const struct bf_nfmsg *req,
     599              :                               struct bf_nfgroup *res)
     600              : {
     601            0 :     bf_assert(req);
     602            0 :     bf_assert(res);
     603              : 
     604            0 :     bf_nfattr *rule_attrs[__NFTA_RULE_MAX] = {};
     605              :     int i = 0;
     606              :     int r;
     607              : 
     608            0 :     bf_list_foreach (_bf_nft_rules, rule_node) {
     609            0 :         _cleanup_bf_nfmsg_ struct bf_nfmsg *msg = NULL;
     610            0 :         struct bf_nfmsg *cached_msg = bf_list_node_get_data(rule_node);
     611              : 
     612            0 :         r = bf_nfgroup_add_new_message(res, &msg, NFT_MSG_NEWRULE,
     613            0 :                                        bf_nfmsg_seqnr(req));
     614            0 :         if (r < 0)
     615            0 :             return bf_err_r(r, "failed to create bf_nfmsg");
     616              : 
     617            0 :         bf_nfmsg_push_str_or_jmp(msg, NFTA_RULE_TABLE, _bf_table_name);
     618            0 :         bf_nfmsg_push_str_or_jmp(msg, NFTA_RULE_CHAIN, _bf_chain_name);
     619            0 :         bf_nfmsg_push_u64_or_jmp(msg, NFTA_RULE_HANDLE, i);
     620            0 :         bf_nfmsg_push_u64_or_jmp(msg, NFTA_RULE_POSITION, i);
     621              : 
     622            0 :         r = bf_nfmsg_parse(cached_msg, rule_attrs, __NFTA_RULE_MAX,
     623              :                            bf_nf_rule_policy);
     624            0 :         if (r < 0)
     625            0 :             return bf_err_r(r, "failed to parse NFT_MSG_NEWRULE attributes");
     626              : 
     627              :         {
     628            0 :             _cleanup_bf_nfnest_ struct bf_nfnest _ =
     629            0 :                 bf_nfnest_or_jmp(msg, NFTA_RULE_EXPRESSIONS);
     630            0 :             bf_nfattr *expr_attrs[__NFTA_EXPR_MAX] = {};
     631            0 :             bf_nfattr *expressions = rule_attrs[NFTA_RULE_EXPRESSIONS];
     632              :             bf_nfattr *expression;
     633            0 :             size_t remaining = bf_nfattr_data_len(expressions);
     634              : 
     635            0 :             expression = bf_nfattr_data(expressions);
     636            0 :             while (bf_nfattr_is_ok(expression, remaining)) {
     637            0 :                 _cleanup_bf_nfnest_ struct bf_nfnest _ =
     638            0 :                     bf_nfnest_or_jmp(msg, NFTA_LIST_ELEM);
     639              : 
     640            0 :                 r = bf_nfattr_parse(expression, expr_attrs, __NFTA_EXPR_MAX,
     641              :                                     bf_nf_expr_policy);
     642            0 :                 if (r < 0) {
     643            0 :                     return bf_err_r(r,
     644              :                                     "failed to parse NFTA_EXPR_* attributes");
     645              :                 }
     646              : 
     647            0 :                 bf_nfmsg_push_str_or_jmp(
     648              :                     msg, NFTA_EXPR_NAME,
     649              :                     bf_nfattr_get_str(expr_attrs[NFTA_EXPR_NAME]));
     650            0 :                 if (bf_streq(bf_nfattr_data(expr_attrs[NFTA_EXPR_NAME]),
     651              :                              "counter")) {
     652            0 :                     _cleanup_bf_nfnest_ struct bf_nfnest _ =
     653            0 :                         bf_nfnest_or_jmp(msg, NFTA_EXPR_DATA);
     654              :                     struct bf_counter counter;
     655              : 
     656            0 :                     r = bf_cgen_get_counter(
     657            0 :                         bf_ctx_get_cgen(BF_HOOK_NF_LOCAL_IN, NULL), i,
     658              :                         &counter);
     659            0 :                     if (r < 0)
     660            0 :                         return bf_err_r(r, "failed to get counter");
     661              : 
     662            0 :                     bf_nfmsg_push_u64_or_jmp(msg, NFTA_COUNTER_BYTES,
     663              :                                              be64toh(counter.bytes));
     664            0 :                     bf_nfmsg_push_u64_or_jmp(msg, NFTA_COUNTER_PACKETS,
     665              :                                              be64toh(counter.packets));
     666              :                 } else {
     667            0 :                     bf_nfmsg_attr_push_or_jmp(
     668              :                         msg, NFTA_EXPR_DATA,
     669              :                         bf_nfattr_data(expr_attrs[NFTA_EXPR_DATA]),
     670              :                         bf_nfattr_data_len(expr_attrs[NFTA_EXPR_DATA]));
     671              :                 }
     672              : 
     673            0 :                 expression = bf_nfattr_next(expression, &remaining);
     674              :             }
     675              :         }
     676              : 
     677            0 :         i++;
     678            0 :         TAKE_PTR(msg);
     679              :     }
     680              : 
     681              :     return 0;
     682              : 
     683              : bf_nfmsg_push_failure:
     684            0 :     return bf_err_r(-EINVAL, "failed to add attribute to Netlink message");
     685              : }
     686              : 
     687            0 : static int _bf_nft_request_handle(const struct bf_nfmsg *req,
     688              :                                   struct bf_nfgroup *res)
     689              : {
     690            0 :     bf_assert(req);
     691            0 :     bf_assert(res);
     692              : 
     693              :     int r = 0;
     694              : 
     695            0 :     switch (bf_nfmsg_command(req)) {
     696            0 :     case NFT_MSG_GETGEN:
     697            0 :         r = _bf_nft_getgen_cb(req, res);
     698            0 :         break;
     699            0 :     case NFT_MSG_GETTABLE:
     700            0 :         r = _bf_nft_gettable_cb(req, res);
     701            0 :         break;
     702            0 :     case NFT_MSG_NEWTABLE:
     703            0 :         r = _bf_nft_newtable_cb(req);
     704            0 :         break;
     705            0 :     case NFT_MSG_GETCHAIN:
     706            0 :         r = _bf_nft_getchain_cb(req, res);
     707            0 :         break;
     708            0 :     case NFT_MSG_NEWCHAIN:
     709            0 :         r = _bf_nft_newchain_cb(req);
     710            0 :         break;
     711            0 :     case NFT_MSG_GETRULE:
     712            0 :         r = _bf_nft_getrule_cb(req, res);
     713            0 :         break;
     714            0 :     case NFT_MSG_NEWRULE:
     715            0 :         r = _bf_nft_newrule_cb(req);
     716            0 :         break;
     717              :     case NFT_MSG_GETOBJ:
     718              :     case NFT_MSG_GETFLOWTABLE:
     719              :     case NFT_MSG_GETSET:
     720              :         break;
     721            0 :     default:
     722            0 :         r = bf_warn_r(-ENOTSUP, "unsupported nft command %hu",
     723              :                       bf_nfmsg_command(req));
     724            0 :         break;
     725              :     }
     726              : 
     727            0 :     return r;
     728              : }
     729              : 
     730            0 : static int _bf_nft_request_handler(struct bf_request *request,
     731              :                                    struct bf_response **response)
     732              : {
     733            0 :     bf_assert(request);
     734            0 :     bf_assert(response);
     735              : 
     736            0 :     _cleanup_bf_nfgroup_ struct bf_nfgroup *req = NULL;
     737            0 :     _cleanup_bf_nfgroup_ struct bf_nfgroup *res = NULL;
     738              :     int r;
     739              : 
     740            0 :     r = bf_nfgroup_new_from_stream(&req, (struct nlmsghdr *)request->data,
     741              :                                    request->data_len);
     742            0 :     if (r < 0)
     743            0 :         return bf_err_r(r, "failed to get bf_nfgroup from request");
     744              : 
     745            0 :     r = bf_nfgroup_new(&res);
     746            0 :     if (r < 0)
     747            0 :         return bf_err_r(r, "failed to create bf_nfgroup");
     748              : 
     749            0 :     bf_list_foreach (bf_nfgroup_messages(req), msg_node) {
     750            0 :         struct bf_nfmsg *msg = bf_list_node_get_data(msg_node);
     751            0 :         r = _bf_nft_request_handle(msg, res);
     752            0 :         if (r)
     753            0 :             return bf_err_r(r, "failed to handle nft request");
     754              :     }
     755              : 
     756            0 :     return bf_nfgroup_to_response(res, response);
     757              : }
        

Generated by: LCOV version 2.0-1