]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: add nfnetlink/nftables type system
authorFlorian Westphal <fw@strlen.de>
Fri, 19 Jun 2020 12:03:03 +0000 (14:03 +0200)
committerFlorian Westphal <fw@strlen.de>
Tue, 15 Dec 2020 23:35:56 +0000 (00:35 +0100)
Will be used by upcoming nftables support -- it will use the netlink
interface directly rather than add another library dependency.

src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h

index 6fb6c147d95fbdd57a1dc7a6233694df77d13e9e..167433337f7edafa9589a7eaa7e39b35896d67ac 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/if_macsec.h>
 #include <linux/if_tunnel.h>
 #include <linux/l2tp.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nfnetlink.h>
 #include <linux/nexthop.h>
 #include <linux/nl80211.h>
 #include <linux/pkt_sched.h>
@@ -1312,6 +1314,243 @@ static const NLType genl_families[] = {
         [SD_GENL_NL80211]   = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system },
 };
 
+static const NLType nfnl_nft_table_types[] = {
+        [NFTA_TABLE_NAME]  = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem nfnl_nft_table_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_table_types),
+        .types = nfnl_nft_table_types,
+};
+
+static const NLType nfnl_nft_chain_hook_types[] = {
+        [NFTA_HOOK_HOOKNUM]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_HOOK_DEV]      = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
+};
+
+static const NLTypeSystem nfnl_nft_chain_hook_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_chain_hook_types),
+        .types = nfnl_nft_chain_hook_types,
+};
+
+static const NLType nfnl_nft_chain_types[] = {
+        [NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_CHAIN_NAME]  = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_CHAIN_HOOK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system },
+        [NFTA_CHAIN_TYPE]  = { .type = NETLINK_TYPE_STRING, .size = 16 },
+        [NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem nfnl_nft_chain_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_chain_types),
+        .types = nfnl_nft_chain_types,
+};
+
+static const NLType nfnl_nft_expr_meta_types[] = {
+        [NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_META_KEY]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLType nfnl_nft_expr_payload_types[] = {
+        [NFTA_PAYLOAD_DREG]   = { .type = NETLINK_TYPE_U32 },
+        [NFTA_PAYLOAD_BASE]   = { .type = NETLINK_TYPE_U32 },
+        [NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_PAYLOAD_LEN]    = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLType nfnl_nft_expr_nat_types[] = {
+        [NFTA_NAT_TYPE]          = { .type = NETLINK_TYPE_U32 },
+        [NFTA_NAT_FAMILY]        = { .type = NETLINK_TYPE_U32 },
+        [NFTA_NAT_REG_ADDR_MIN]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_NAT_REG_ADDR_MAX]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_NAT_FLAGS]         = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLType nfnl_nft_data_types[] = {
+        [NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY },
+};
+
+static const NLTypeSystem nfnl_nft_data_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_data_types),
+        .types = nfnl_nft_data_types,
+};
+
+static const NLType nfnl_nft_expr_bitwise_types[] = {
+        [NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_BITWISE_LEN]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
+        [NFTA_BITWISE_XOR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
+};
+
+static const NLType nfnl_nft_expr_cmp_types[] = {
+        [NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_CMP_OP]   = { .type = NETLINK_TYPE_U32 },
+        [NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
+};
+
+static const NLType nfnl_nft_expr_fib_types[] = {
+        [NFTA_FIB_DREG]   = { .type = NETLINK_TYPE_U32 },
+        [NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_FIB_FLAGS]  = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLType nfnl_nft_expr_lookup_types[] = {
+        [NFTA_LOOKUP_SET]   = { .type = NETLINK_TYPE_STRING },
+        [NFTA_LOOKUP_SREG]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_LOOKUP_DREG]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLType nfnl_nft_expr_masq_types[] = {
+        [NFTA_MASQ_FLAGS]         = { .type = NETLINK_TYPE_U32 },
+        [NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
+        [NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem nfnl_expr_data_type_systems[] = {
+        [NL_UNION_NFT_EXPR_DATA_BITWISE]   =  { .count = ELEMENTSOF(nfnl_nft_expr_bitwise_types),
+                                                .types = nfnl_nft_expr_bitwise_types },
+        [NL_UNION_NFT_EXPR_DATA_CMP]       =  { .count = ELEMENTSOF(nfnl_nft_expr_cmp_types),
+                                                .types = nfnl_nft_expr_cmp_types },
+        [NL_UNION_NFT_EXPR_DATA_FIB]       =  { .count = ELEMENTSOF(nfnl_nft_expr_fib_types),
+                                                .types = nfnl_nft_expr_fib_types },
+        [NL_UNION_NFT_EXPR_DATA_LOOKUP]    =  { .count = ELEMENTSOF(nfnl_nft_expr_lookup_types),
+                                                .types = nfnl_nft_expr_lookup_types },
+        [NL_UNION_NFT_EXPR_DATA_MASQ]      =  { .count = ELEMENTSOF(nfnl_nft_expr_masq_types),
+                                                .types = nfnl_nft_expr_masq_types },
+        [NL_UNION_NFT_EXPR_DATA_META]      =  { .count = ELEMENTSOF(nfnl_nft_expr_meta_types),
+                                                .types = nfnl_nft_expr_meta_types },
+        [NL_UNION_NFT_EXPR_DATA_NAT]       =  { .count = ELEMENTSOF(nfnl_nft_expr_nat_types),
+                                                .types = nfnl_nft_expr_nat_types },
+        [NL_UNION_NFT_EXPR_DATA_PAYLOAD]   =  { .count = ELEMENTSOF(nfnl_nft_expr_payload_types),
+                                                .types = nfnl_nft_expr_payload_types },
+};
+
+static const char* const nl_union_nft_expr_data_table[] = {
+        [NL_UNION_NFT_EXPR_DATA_BITWISE] = "bitwise",
+        [NL_UNION_NFT_EXPR_DATA_CMP]     = "cmp",
+        [NL_UNION_NFT_EXPR_DATA_LOOKUP]  = "lookup",
+        [NL_UNION_NFT_EXPR_DATA_META]    = "meta",
+        [NL_UNION_NFT_EXPR_DATA_FIB]     = "fib",
+        [NL_UNION_NFT_EXPR_DATA_MASQ]    = "masq",
+        [NL_UNION_NFT_EXPR_DATA_NAT]     = "nat",
+        [NL_UNION_NFT_EXPR_DATA_PAYLOAD] = "payload",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(nl_union_nft_expr_data, NLUnionNFTExprData);
+
+static const NLTypeSystemUnion nfnl_nft_data_expr_type_system_union = {
+        .num = _NL_UNION_NFT_EXPR_DATA_MAX,
+        .lookup = nl_union_nft_expr_data_from_string,
+        .type_systems = nfnl_expr_data_type_systems,
+        .match_type = NL_MATCH_SIBLING,
+        .match = NFTA_EXPR_NAME,
+};
+
+static const NLType nfnl_nft_rule_expr_types[] = {
+        [NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 },
+        [NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION,
+                             .type_system_union = &nfnl_nft_data_expr_type_system_union },
+};
+
+static const NLTypeSystem nfnl_nft_rule_expr_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_rule_expr_types),
+        .types = nfnl_nft_rule_expr_types,
+};
+
+static const NLType nfnl_nft_rule_types[] = {
+        [NFTA_RULE_TABLE]       = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_RULE_CHAIN]       = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_RULE_EXPRESSIONS]        = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system }
+};
+
+static const NLTypeSystem nfnl_nft_rule_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_rule_types),
+        .types = nfnl_nft_rule_types,
+};
+
+static const NLType nfnl_nft_set_types[] = {
+        [NFTA_SET_TABLE]      = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_SET_NAME]       = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_SET_FLAGS]      = { .type = NETLINK_TYPE_U32 },
+        [NFTA_SET_KEY_TYPE]   = { .type = NETLINK_TYPE_U32 },
+        [NFTA_SET_KEY_LEN]    = { .type = NETLINK_TYPE_U32 },
+        [NFTA_SET_DATA_TYPE]  = { .type = NETLINK_TYPE_U32 },
+        [NFTA_SET_DATA_LEN]   = { .type = NETLINK_TYPE_U32 },
+        [NFTA_SET_POLICY]     = { .type = NETLINK_TYPE_U32 },
+        [NFTA_SET_ID]         = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem nfnl_nft_set_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_set_types),
+        .types = nfnl_nft_set_types,
+};
+
+static const NLType nfnl_nft_setelem_types[] = {
+        [NFTA_SET_ELEM_KEY]   = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
+        [NFTA_SET_ELEM_DATA]  = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
+        [NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem nfnl_nft_setelem_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_setelem_types),
+        .types = nfnl_nft_setelem_types,
+};
+
+static const NLType nfnl_nft_setelem_list_types[] = {
+        [NFTA_SET_ELEM_LIST_TABLE]    = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_SET_ELEM_LIST_SET]      = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
+        [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system },
+};
+
+static const NLTypeSystem nfnl_nft_setelem_list_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_setelem_list_types),
+        .types = nfnl_nft_setelem_list_types,
+};
+
+static const NLType nfnl_nft_msg_types [] = {
+        [NFT_MSG_DELTABLE]   = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFT_MSG_NEWTABLE]   = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFT_MSG_NEWCHAIN]   = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFT_MSG_NEWRULE]    = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFT_MSG_NEWSET]     = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
+};
+
+static const NLTypeSystem nfnl_nft_msg_type_system = {
+        .count = ELEMENTSOF(nfnl_nft_msg_types),
+        .types = nfnl_nft_msg_types,
+};
+
+static const NLType nfnl_msg_batch_types [] = {
+        [NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 }
+};
+
+static const NLTypeSystem nfnl_msg_batch_type_system = {
+        .count = ELEMENTSOF(nfnl_msg_batch_types),
+        .types = nfnl_msg_batch_types,
+};
+
+static const NLType nfnl_types[] = {
+        [NLMSG_DONE]           = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
+        [NLMSG_ERROR]          = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) },
+        [NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFNL_MSG_BATCH_END]   = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
+        [NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_msg_type_system, .size = sizeof(struct nfgenmsg) },
+};
+
+const NLTypeSystem nfnl_type_system_root = {
+        .count = ELEMENTSOF(nfnl_types),
+        .types = nfnl_types,
+};
+
 /* Mainly used when sending message */
 const NLTypeSystem genl_family_type_system_root = {
         .count = ELEMENTSOF(genl_families),
@@ -1368,6 +1607,8 @@ const NLTypeSystem *type_system_get_root(int protocol) {
         switch (protocol) {
                 case NETLINK_GENERIC:
                         return &genl_type_system_root;
+                case NETLINK_NETFILTER:
+                        return &nfnl_type_system_root;
                 default: /* NETLINK_ROUTE: */
                         return &rtnl_type_system_root;
         }
@@ -1378,9 +1619,12 @@ int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type)
         const NLType *nl_type;
         int r;
 
-        if (!nl || nl->protocol != NETLINK_GENERIC)
+        if (!nl)
                 return type_system_get_type(&rtnl_type_system_root, ret, type);
 
+        if (nl->protocol != NETLINK_GENERIC)
+                return type_system_get_type(type_system_get_root(nl->protocol), ret, type);
+
         r = nlmsg_type_to_genl_family(nl, type, &family);
         if (r < 0)
                 return r;
index b14e66fbb11e34f638da2d379dfc6130d422a337..1e93ed78cf8f49b5f7ce39d0ce1529fa131ae21b 100644 (file)
@@ -21,6 +21,7 @@ enum {
         NETLINK_TYPE_NESTED,                    /* NLA_NESTED */
         NETLINK_TYPE_UNION,
         NETLINK_TYPE_SOCKADDR,
+        NETLINK_TYPE_BINARY,
 };
 
 typedef enum NLMatchType {
@@ -117,3 +118,19 @@ typedef enum NLUnionTCAOptionData {
 
 const char *nl_union_tca_option_data_to_string(NLUnionTCAOptionData p) _const_;
 NLUnionTCAOptionData nl_union_tca_option_data_from_string(const char *p) _pure_;
+
+typedef enum NLUnionNFTExprData {
+        NL_UNION_NFT_EXPR_DATA_BITWISE,
+        NL_UNION_NFT_EXPR_DATA_CMP,
+        NL_UNION_NFT_EXPR_DATA_FIB,
+        NL_UNION_NFT_EXPR_DATA_LOOKUP,
+        NL_UNION_NFT_EXPR_DATA_PAYLOAD,
+        NL_UNION_NFT_EXPR_DATA_MASQ,
+        NL_UNION_NFT_EXPR_DATA_META,
+        NL_UNION_NFT_EXPR_DATA_NAT,
+        _NL_UNION_NFT_EXPR_DATA_MAX,
+        _NL_UNION_NFT_EXPR_DATA_INVALID = -1,
+} NLUnionNFTExprData;
+
+const char *nl_union_nft_expr_data_to_string(NLUnionNFTExprData p) _const_;
+NLUnionNFTExprData nl_union_nft_expr_data_from_string(const char *p) _pure_;