LCOV - code coverage report
Current view: top level - bpfilter/xlate/nft - nfmsg.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 86.1 % 108 93
Test Date: 2025-02-26 17:59:59 Functions: 83.3 % 18 15

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/xlate/nft/nfmsg.h"
       7              : 
       8              : #include <linux/netfilter/nf_tables.h>
       9              : #include <linux/netfilter/nfnetlink.h>
      10              : #include <linux/netlink.h>
      11              : 
      12              : #include <errno.h>
      13              : #include <libnl3/netlink/attr.h>
      14              : #include <limits.h>
      15              : #include <netlink/msg.h>
      16              : #include <stdbool.h>
      17              : #include <stddef.h>
      18              : #include <stdint.h>
      19              : #include <stdlib.h>
      20              : #include <sys/socket.h>
      21              : 
      22              : #include "core/helper.h"
      23              : #include "core/logger.h"
      24              : 
      25              : struct bf_nfmsg
      26              : {
      27              :     struct nl_msg *msg;
      28              : };
      29              : 
      30              : static const struct nla_policy _bf_nf_table_policy[__NFTA_TABLE_MAX] = {
      31              :     [NFTA_TABLE_NAME] = {.type = NLA_STRING},
      32              :     [NFTA_TABLE_FLAGS] = {.type = NLA_U32},
      33              :     [NFTA_TABLE_HANDLE] = {.type = NLA_U64},
      34              :     [NFTA_TABLE_USERDATA] = {.type = NLA_BINARY},
      35              : };
      36              : const bf_nfpolicy *bf_nf_table_policy = _bf_nf_table_policy;
      37              : 
      38              : static const struct nla_policy _bf_nf_chain_policy[__NFTA_CHAIN_MAX] = {
      39              :     [NFTA_CHAIN_TABLE] = {.type = NLA_STRING},
      40              :     [NFTA_CHAIN_HANDLE] = {.type = NLA_U64},
      41              :     [NFTA_CHAIN_NAME] = {.type = NLA_STRING},
      42              :     [NFTA_CHAIN_HOOK] = {.type = NLA_NESTED},
      43              :     [NFTA_CHAIN_POLICY] = {.type = NLA_U32},
      44              :     [NFTA_CHAIN_TYPE] = {.type = NLA_STRING},
      45              :     [NFTA_CHAIN_COUNTERS] = {.type = NLA_NESTED},
      46              :     [NFTA_CHAIN_FLAGS] = {.type = NLA_U32},
      47              :     [NFTA_CHAIN_ID] = {.type = NLA_U32},
      48              :     [NFTA_CHAIN_USERDATA] = {.type = NLA_BINARY},
      49              : };
      50              : const bf_nfpolicy *bf_nf_chain_policy = _bf_nf_chain_policy;
      51              : 
      52              : static const struct nla_policy _bf_nf_hook_policy[__NFTA_HOOK_MAX] = {
      53              :     [NFTA_HOOK_HOOKNUM] = {.type = NLA_U32},
      54              :     [NFTA_HOOK_PRIORITY] = {.type = NLA_U32},
      55              :     [NFTA_HOOK_DEV] = {.type = NLA_STRING},
      56              : };
      57              : const bf_nfpolicy *bf_nf_hook_policy = _bf_nf_hook_policy;
      58              : 
      59              : static const struct nla_policy _bf_nf_rule_policy[__NFTA_RULE_MAX] = {
      60              :     [NFTA_RULE_TABLE] = {.type = NLA_STRING},
      61              :     [NFTA_RULE_CHAIN] = {.type = NLA_STRING},
      62              :     [NFTA_RULE_HANDLE] = {.type = NLA_U64},
      63              :     [NFTA_RULE_EXPRESSIONS] = {.type = NLA_NESTED},
      64              :     [NFTA_RULE_COMPAT] = {.type = NLA_NESTED},
      65              :     [NFTA_RULE_POSITION] = {.type = NLA_U64},
      66              :     [NFTA_RULE_USERDATA] = {.type = NLA_BINARY},
      67              :     [NFTA_RULE_ID] = {.type = NLA_U32},
      68              :     [NFTA_RULE_POSITION_ID] = {.type = NLA_U32},
      69              :     [NFTA_RULE_CHAIN_ID] = {.type = NLA_U32},
      70              : };
      71              : const bf_nfpolicy *bf_nf_rule_policy = _bf_nf_rule_policy;
      72              : 
      73              : static const struct nla_policy _bf_nf_expr_policy[__NFTA_EXPR_MAX] = {
      74              :     [NFTA_EXPR_NAME] = {.type = NLA_STRING},
      75              :     [NFTA_EXPR_DATA] = {.type = NLA_NESTED},
      76              : };
      77              : const bf_nfpolicy *bf_nf_expr_policy = _bf_nf_expr_policy;
      78              : 
      79              : static const struct nla_policy _bf_nf_counter_policy[NFTA_COUNTER_MAX + 1] = {
      80              :     [NFTA_COUNTER_PACKETS] = {.type = NLA_U64},
      81              :     [NFTA_COUNTER_BYTES] = {.type = NLA_U64},
      82              : };
      83              : const bf_nfpolicy *bf_nf_counter_policy = _bf_nf_counter_policy;
      84              : 
      85              : static const struct nla_policy _bf_nf_payload_policy[__NFTA_PAYLOAD_MAX] = {
      86              :     [NFTA_PAYLOAD_SREG] = {.type = NLA_U32},
      87              :     [NFTA_PAYLOAD_DREG] = {.type = NLA_U32},
      88              :     [NFTA_PAYLOAD_BASE] = {.type = NLA_U32},
      89              :     [NFTA_PAYLOAD_OFFSET] = {.type = NLA_U32},
      90              :     [NFTA_PAYLOAD_LEN] = {.type = NLA_U32},
      91              :     [NFTA_PAYLOAD_CSUM_TYPE] = {.type = NLA_U32},
      92              :     [NFTA_PAYLOAD_CSUM_OFFSET] = {.type = NLA_U32},
      93              :     [NFTA_PAYLOAD_CSUM_FLAGS] = {.type = NLA_U32},
      94              : };
      95              : const bf_nfpolicy *bf_nf_payload_policy = _bf_nf_payload_policy;
      96              : 
      97              : static const struct nla_policy _bf_nf_cmp_policy[__NFTA_CMP_MAX] = {
      98              :     [NFTA_CMP_SREG] = {.type = NLA_U32},
      99              :     [NFTA_CMP_OP] = {.type = NLA_U32},
     100              :     [NFTA_CMP_DATA] = {.type = NLA_NESTED},
     101              : };
     102              : const bf_nfpolicy *bf_nf_cmp_policy = _bf_nf_cmp_policy;
     103              : 
     104              : static const struct nla_policy _bf_nf_immediate_policy[__NFTA_IMMEDIATE_MAX] = {
     105              :     [NFTA_IMMEDIATE_DREG] = {.type = NLA_U32},
     106              :     [NFTA_IMMEDIATE_DATA] = {.type = NLA_NESTED},
     107              : };
     108              : const bf_nfpolicy *bf_nf_immediate_policy = _bf_nf_immediate_policy;
     109              : 
     110              : static const struct nla_policy _bf_nf_data_policy[__NFTA_DATA_MAX] = {
     111              :     [NFTA_DATA_VALUE] = {.type = NLA_BINARY},
     112              :     [NFTA_DATA_VERDICT] = {.type = NLA_NESTED},
     113              : };
     114              : const bf_nfpolicy *bf_nf_data_policy = _bf_nf_data_policy;
     115              : 
     116              : static const struct nla_policy _bf_nf_verdict_policy[__NFTA_VERDICT_MAX] = {
     117              :     [NFTA_VERDICT_CODE] = {.type = NLA_U32},
     118              :     [NFTA_VERDICT_CHAIN] = {.type = NLA_STRING},
     119              :     [NFTA_VERDICT_CHAIN_ID] = {.type = NLA_U32},
     120              : };
     121              : const bf_nfpolicy *bf_nf_verdict_policy = _bf_nf_verdict_policy;
     122              : 
     123           32 : int bf_nfmsg_new(struct bf_nfmsg **msg, uint8_t command, uint32_t seqnr)
     124              : {
     125           32 :     bf_assert(msg);
     126              : 
     127           31 :     _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
     128              :     struct nlmsghdr *nlh;
     129           31 :     struct nfgenmsg extra_hdr = {
     130              :         .nfgen_family = AF_INET,
     131              :         .version = NFNETLINK_V0,
     132              :         .res_id = 0,
     133              :     };
     134              :     int r;
     135              : 
     136           31 :     _msg = calloc(1, sizeof(*_msg));
     137           31 :     if (!_msg)
     138              :         return -ENOMEM;
     139              : 
     140           30 :     _msg->msg = nlmsg_alloc();
     141           30 :     if (!_msg->msg)
     142              :         return -ENOMEM;
     143              : 
     144           29 :     nlh = nlmsg_put(_msg->msg, 0, seqnr, NFNL_SUBSYS_NFTABLES << 8 | command, 0,
     145              :                     0);
     146           29 :     if (!nlh)
     147            1 :         return bf_err_r(-ENOMEM, "failed to insert Netlink header");
     148              : 
     149           28 :     r = nlmsg_append(_msg->msg, &extra_hdr, sizeof(extra_hdr), NLMSG_ALIGNTO);
     150           28 :     if (r)
     151            1 :         return bf_err_r(r, "failed to insert Netfilter extra header");
     152              : 
     153           27 :     *msg = TAKE_PTR(_msg);
     154              : 
     155           27 :     return 0;
     156              : }
     157              : 
     158            8 : int bf_nfmsg_new_done(struct bf_nfmsg **msg)
     159              : {
     160            8 :     bf_assert(msg);
     161              : 
     162            7 :     _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
     163              :     struct nlmsghdr *nlh;
     164            7 :     struct nfgenmsg extra_hdr = {
     165              :         .nfgen_family = AF_INET,
     166              :         .version = NFNETLINK_V0,
     167              :         .res_id = 0,
     168              :     };
     169              :     int r;
     170              : 
     171            7 :     _msg = calloc(1, sizeof(*_msg));
     172            7 :     if (!_msg)
     173              :         return -ENOMEM;
     174              : 
     175            6 :     _msg->msg = nlmsg_alloc();
     176            6 :     if (!_msg->msg)
     177              :         return -ENOMEM;
     178              : 
     179            5 :     nlh = nlmsg_put(_msg->msg, 0, 0, NLMSG_DONE, 0, NLM_F_MULTI);
     180            5 :     if (!nlh)
     181            1 :         return bf_err_r(-ENOMEM, "failed to insert Netlink header");
     182              : 
     183            4 :     r = nlmsg_append(_msg->msg, &extra_hdr, sizeof(extra_hdr), NLMSG_ALIGNTO);
     184            4 :     if (r)
     185            1 :         return bf_err_r(r, "failed to insert Netfilter extra header");
     186              : 
     187            3 :     *msg = TAKE_PTR(_msg);
     188              : 
     189            3 :     return 0;
     190              : }
     191              : 
     192           64 : int bf_nfmsg_new_from_nlmsghdr(struct bf_nfmsg **msg, struct nlmsghdr *nlh)
     193              : {
     194           64 :     bf_assert(msg);
     195           63 :     bf_assert(nlh);
     196              : 
     197           62 :     _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
     198              : 
     199           62 :     if (nlh->nlmsg_type >> 8 != NFNL_SUBSYS_NFTABLES) {
     200            1 :         return bf_err_r(-EINVAL, "invalid Netlink message type: %u",
     201              :                         nlh->nlmsg_type);
     202              :     }
     203              : 
     204           61 :     if ((size_t)nlmsg_datalen(nlh) < sizeof(struct nfgenmsg)) {
     205            0 :         return bf_err_r(-EINVAL, "invalid Netlink message payload size: %d",
     206              :                         nlmsg_datalen(nlh));
     207              :     }
     208              : 
     209           61 :     _msg = calloc(1, sizeof(*_msg));
     210           61 :     if (!_msg)
     211              :         return -ENOMEM;
     212              : 
     213           60 :     _msg->msg = nlmsg_convert(nlh);
     214           60 :     if (!_msg->msg)
     215              :         return -ENOMEM;
     216              : 
     217           59 :     *msg = TAKE_PTR(_msg);
     218              : 
     219           59 :     return 0;
     220              : }
     221              : 
     222          279 : void bf_nfmsg_free(struct bf_nfmsg **msg)
     223              : {
     224          279 :     bf_assert(msg);
     225              : 
     226          278 :     if (!*msg)
     227              :         return;
     228              : 
     229           96 :     nlmsg_free((*msg)->msg);
     230           96 :     free(*msg);
     231           96 :     *msg = NULL;
     232              : }
     233              : 
     234          110 : struct nlmsghdr *bf_nfmsg_hdr(const struct bf_nfmsg *msg)
     235              : {
     236          110 :     bf_assert(msg);
     237              : 
     238          109 :     return nlmsg_hdr(msg->msg);
     239              : }
     240              : 
     241           83 : size_t bf_nfmsg_data_len(const struct bf_nfmsg *msg)
     242              : {
     243           83 :     bf_assert(msg);
     244              : 
     245           83 :     return nlmsg_datalen(bf_nfmsg_hdr(msg));
     246              : }
     247              : 
     248           79 : size_t bf_nfmsg_len(const struct bf_nfmsg *msg)
     249              : {
     250           79 :     bf_assert(msg);
     251              : 
     252           79 :     return nlmsg_total_size((int)bf_nfmsg_data_len(msg));
     253              : }
     254              : 
     255            5 : uint8_t bf_nfmsg_command(const struct bf_nfmsg *msg)
     256              : {
     257            5 :     bf_assert(msg);
     258              : 
     259            4 :     return bf_nfmsg_hdr(msg)->nlmsg_type & 0xff;
     260              : }
     261              : 
     262            5 : uint32_t bf_nfmsg_seqnr(const struct bf_nfmsg *msg)
     263              : {
     264            5 :     bf_assert(msg);
     265              : 
     266            4 :     return bf_nfmsg_hdr(msg)->nlmsg_seq;
     267              : }
     268              : 
     269           12 : int bf_nfmsg_attr_push(struct bf_nfmsg *msg, uint16_t type, const void *data,
     270              :                        size_t len)
     271              : {
     272           12 :     bf_assert(msg);
     273           11 :     bf_assert(data);
     274              : 
     275           10 :     return nla_put(msg->msg, type, (int)len, data);
     276              : }
     277              : 
     278            1 : int bf_nfmsg_parse(const struct bf_nfmsg *msg, bf_nfattr **attrs, int maxtype,
     279              :                    const bf_nfpolicy *policy)
     280              : {
     281            1 :     bf_assert(msg);
     282            1 :     bf_assert(attrs);
     283              : 
     284            1 :     return nlmsg_parse(bf_nfmsg_hdr(msg), sizeof(struct nfgenmsg), attrs,
     285              :                        maxtype - 1, policy);
     286              : }
     287              : 
     288            1 : int bf_nfattr_parse(bf_nfattr *attr, bf_nfattr **attrs, int maxtype,
     289              :                     const bf_nfpolicy *policy)
     290              : {
     291            1 :     bf_assert(attr);
     292            1 :     bf_assert(attrs);
     293              : 
     294            1 :     return nla_parse_nested(attrs, maxtype - 1, attr, policy);
     295              : }
     296              : 
     297           10 : void *bf_nfattr_data(bf_nfattr *attr)
     298              : {
     299           10 :     bf_assert(attr);
     300              : 
     301           10 :     return nla_data(attr);
     302              : }
     303              : 
     304            0 : size_t bf_nfattr_data_len(bf_nfattr *attr)
     305              : {
     306            0 :     bf_assert(attr);
     307              : 
     308            0 :     return (size_t)nla_len(attr);
     309              : }
     310              : 
     311            0 : bool bf_nfattr_is_ok(bf_nfattr *attr, size_t remaining)
     312              : {
     313            0 :     bf_assert(attr);
     314            0 :     bf_assert(remaining < INT_MAX);
     315              : 
     316            0 :     return nla_ok(attr, (int)remaining);
     317              : }
     318              : 
     319            0 : bf_nfattr *bf_nfattr_next(bf_nfattr *attr, size_t *remaining)
     320              : {
     321            0 :     bf_assert(attr);
     322            0 :     bf_assert(remaining && *remaining < INT_MAX);
     323              : 
     324            0 :     int _remaining = (int)*remaining;
     325              : 
     326            0 :     attr = nla_next(attr, &_remaining);
     327            0 :     *remaining = (size_t)_remaining;
     328              : 
     329            0 :     return attr;
     330              : }
     331              : 
     332            3 : int bf_nfmsg_nest_init(struct bf_nfnest *nest, struct bf_nfmsg *parent,
     333              :                        uint16_t type)
     334              : {
     335            3 :     bf_assert(nest);
     336            2 :     bf_assert(parent);
     337              : 
     338              :     bf_nfattr *attr;
     339              : 
     340            1 :     attr = nla_nest_start(parent->msg, type);
     341            1 :     if (!attr)
     342              :         return -ENOMEM;
     343              : 
     344            1 :     nest->attr = attr;
     345            1 :     nest->parent = parent;
     346              : 
     347            1 :     return 0;
     348              : }
     349              : 
     350            1 : void bf_nfnest_cleanup(struct bf_nfnest *nest)
     351              : {
     352            1 :     bf_assert(nest);
     353              : 
     354            1 :     nla_nest_end(nest->parent->msg, nest->attr);
     355            1 : }
        

Generated by: LCOV version 2.0-1