From 6f00fd9b7c9471e191c3639561072d2bcadd5447 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 19 Jun 2020 14:03:03 +0200 Subject: [PATCH] sd-netlink: add nfnetlink/nftables type system 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 | 246 +++++++++++++++++++++- src/libsystemd/sd-netlink/netlink-types.h | 17 ++ 2 files changed, 262 insertions(+), 1 deletion(-) diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 6fb6c147d9..167433337f 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -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; diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index b14e66fbb1..1e93ed78cf 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -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_;