This patch adds kernel support for the meta_target expression. This expression indicates that a given packet has to be set with a property, currently one of mark, priority, nftrace or secmark. Most of the previous code was invalid, with lots of compilation errors and warnings. In case of nftrace, the value is always 1. Such a behaviour is copied from net/netfilter/xt_TRACE.c In case of secmark, the intention is to make the translation between the security_ctx and security_id outside this module, maybe in userspace. Otherwise, a string is needed to be passed from the userpsace to kernel as part of the attribute set, breaking the main KEY,VALUE pair approach. This is different from net/netfilter/xt_SECMARK.c. There, the context is translated in kernel side. Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx> --- include/uapi/linux/netfilter/nf_tables.h | 30 ++++++++ net/netfilter/Kconfig | 4 + net/netfilter/Makefile | 2 - net/netfilter/nft_meta_target.c | 114 +++++++++++++++++------------- 4 files changed, 100 insertions(+), 50 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index fbfd229..d9f5784 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -563,6 +563,36 @@ enum nft_meta_attributes { #define NFTA_META_MAX (__NFTA_META_MAX - 1) /** + * enum nft_meta_target_keys - nf_tables meta_target expression keys + * + * @NFT_META_TARGET_MARK: to stablish packet mark (skb->mark) + * @NFT_META_TARGET_PRIORITY: to fix packet priority (skb->priority) + * @NFT_META_TARGET_NFTRACE: to put the packet nftrace bit (skb->nf_trace) + * @NFT_META_TARGET_SECMARK: to set packet secmark (skb->secmark) + */ +enum nft_meta_target_keys { + NFT_META_TARGET_MARK, + NFT_META_TARGET_PRIORITY, + NFT_META_TARGET_NFTRACE, + NFT_META_TARGET_SECMARK, +}; + +/** + * enum nft_meta_target_attributes - nf_tables meta_target expression netlink + * attributes + * + * @NFTA_META_TARGET_KEY: meta_target item to be set (NLA_U32: nft_meta_target_keys) + * @NFTA_META_TARGET_VALUE: value for the key (NLA_U32) + */ +enum nft_meta_target_attributes { + NFTA_META_TARGET_UNSPEC, + NFTA_META_TARGET_KEY, + NFTA_META_TARGET_VALUE, + __NFTA_META_TARGET_MAX +}; +#define NFTA_META_TARGET_MAX (__NFTA_META_TARGET_MAX - 1) + +/** * enum nft_ct_keys - nf_tables ct expression keys * * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 48acec1..187ceff 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -425,6 +425,10 @@ config NFT_META depends on NF_TABLES tristate "Netfilter nf_tables meta module" +config NFT_META_TARGET + depends on NF_TABLES + tristate "Netfilter nf_tables meta target module" + config NFT_CT depends on NF_TABLES depends on NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 394483b..32da2c0 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -76,7 +76,7 @@ obj-$(CONFIG_NFT_META) += nft_meta.o obj-$(CONFIG_NFT_CT) += nft_ct.o obj-$(CONFIG_NFT_LIMIT) += nft_limit.o obj-$(CONFIG_NFT_NAT) += nft_nat.o -#nf_tables-objs += nft_meta_target.o +obj-$(CONFIG_NFT_META_TARGET) += nft_meta_target.o obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o obj-$(CONFIG_NFT_HASH) += nft_hash.o obj-$(CONFIG_NFT_COUNTER) += nft_counter.o diff --git a/net/netfilter/nft_meta_target.c b/net/netfilter/nft_meta_target.c index 71177df..cfcec1c 100644 --- a/net/netfilter/nft_meta_target.c +++ b/net/netfilter/nft_meta_target.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/list.h> #include <linux/rbtree.h> #include <linux/netlink.h> @@ -17,32 +18,31 @@ #include <linux/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h> -struct nft_meta { - enum nft_meta_keys key; +struct nft_meta_target { + enum nft_meta_target_keys key:8; + u32 value; }; -static void nft_meta_eval(const struct nft_expr *expr, - struct nft_data *nfres, - struct nft_data *data, - const struct nft_pktinfo *pkt) +static void nft_meta_target_eval(const struct nft_expr *expr, + struct nft_data data[NFT_REG_MAX + 1], + const struct nft_pktinfo *pkt) { - const struct nft_meta *meta = nft_expr_priv(expr); + const struct nft_meta_target *meta_target = nft_expr_priv(expr); struct sk_buff *skb = pkt->skb; - u32 val = data->data[0]; - switch (meta->key) { - case NFT_META_MARK: - skb->mark = val; + switch (meta_target->key) { + case NFT_META_TARGET_MARK: + skb->mark = meta_target->value; break; - case NFT_META_PRIORITY: - skb->priority = val; + case NFT_META_TARGET_PRIORITY: + skb->priority = meta_target->value; break; - case NFT_META_NFTRACE: - skb->nf_trace = val; + case NFT_META_TARGET_NFTRACE: + skb->nf_trace = 1; break; #ifdef CONFIG_NETWORK_SECMARK - case NFT_META_SECMARK: - skb->secmark = val; + case NFT_META_TARGET_SECMARK: + skb->secmark = meta_target->value; break; #endif default: @@ -50,68 +50,84 @@ static void nft_meta_eval(const struct nft_expr *expr, } } -static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { - [NFTA_META_KEY] = { .type = NLA_U32 }, +static const struct nla_policy nft_meta_target_policy[NFTA_META_TARGET_MAX + 1] = { + [NFTA_META_TARGET_KEY] = { .type = NLA_U32 }, + [NFTA_META_TARGET_VALUE] = { .type = NLA_U32 }, }; -static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[]) +static int nft_meta_target_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]) { - struct nft_meta *meta = nft_expr_priv(expr); + struct nft_meta_target *meta_target = nft_expr_priv(expr); - if (tb[NFTA_META_KEY] == NULL) + if (tb[NFTA_META_TARGET_KEY] == NULL) return -EINVAL; - meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); - switch (meta->key) { - case NFT_META_MARK: - case NFT_META_PRIORITY: - case NFT_META_NFTRACE: + meta_target->key = ntohl(nla_get_be32(tb[NFTA_META_TARGET_KEY])); + switch (meta_target->key) { + case NFT_META_TARGET_MARK: + case NFT_META_TARGET_PRIORITY: + case NFT_META_TARGET_NFTRACE: #ifdef CONFIG_NETWORK_SECMARK - case NFT_META_SECMARK: + case NFT_META_TARGET_SECMARK: #endif break; default: return -EINVAL; } + if (tb[NFTA_META_TARGET_VALUE] == NULL) + return -EINVAL; + + meta_target->value = ntohl(nla_get_be32(tb[NFTA_META_TARGET_VALUE])); + return 0; } -static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) +static int nft_meta_target_dump(struct sk_buff *skb, const struct nft_expr *expr) { - struct nft_meta *meta = nft_expr_priv(expr); + struct nft_meta_target *meta_target = nft_expr_priv(expr); - NLA_PUT_BE32(skb, NFTA_META_KEY, htonl(meta->key)); - return 0; + if (nla_put_be32(skb, NFTA_META_TARGET_KEY, htonl(meta_target->key))) + return -1; -nla_put_failure: - return -1; + if (nla_put_be32(skb, NFTA_META_TARGET_VALUE, htonl(meta_target->value))) + return -1; + + return 0; } -static struct nft_expr_ops meta_target __read_mostly = { - .name = "meta", - .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), +static struct nft_expr_type nft_meta_target_type; +static const struct nft_expr_ops nft_meta_target_ops = { + .type = &nft_meta_target_type, + .size = NFT_EXPR_SIZE(sizeof(struct nft_meta_target)), + .eval = nft_meta_target_eval, + .init = nft_meta_target_init, + .dump = nft_meta_target_dump, +}; + +static struct nft_expr_type nft_meta_target_type __read_mostly = { + .name = "meta_target", + .ops = &nft_meta_target_ops, + .policy = nft_meta_target_policy, + .maxattr = NFTA_META_TARGET_MAX, .owner = THIS_MODULE, - .eval = nft_meta_eval, - .init = nft_meta_init, - .dump = nft_meta_dump, - .policy = nft_meta_policy, - .maxattr = NFTA_META_MAX, }; -static int __init nft_meta_target_init(void) +static int __init nft_meta_target_module_init(void) { - return nft_register_expr(&meta_target); + return nft_register_expr(&nft_meta_target_type); } -static void __exit nft_meta_target_exit(void) +static void __exit nft_meta_target_module_exit(void) { - nft_unregister_expr(&meta_target); + nft_unregister_expr(&nft_meta_target_type); } -module_init(nft_meta_target_init); -module_exit(nft_meta_target_exit); +module_init(nft_meta_target_module_init); +module_exit(nft_meta_target_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Patrick McHardy <kaber@xxxxxxxxx>"); -MODULE_ALIAS_NFT_EXPR("meta"); +MODULE_ALIAS_NFT_EXPR("meta_target"); -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html