This patch adds userspace support for the meta_target expression. This expression indicates that the packet has to be set with a property, currently one of mark, priority, nftrace or secmark. Tests files will be provided in a separated patch. Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx> --- 0 files changed diff --git a/include/libnftables/expr.h b/include/libnftables/expr.h index 54de186..0a9a334 100644 --- a/include/libnftables/expr.h +++ b/include/libnftables/expr.h @@ -53,6 +53,11 @@ enum { }; enum { + NFT_EXPR_META_TARGET_KEY = NFT_RULE_EXPR_ATTR_BASE, + NFT_EXPR_META_TARGET_VALUE, +}; + +enum { NFT_EXPR_CMP_SREG = NFT_RULE_EXPR_ATTR_BASE, NFT_EXPR_CMP_OP, NFT_EXPR_CMP_DATA, diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 4ec8187..1771791 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -485,6 +485,34 @@ 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: set packet mark (skb->mark) + * @NFT_META_TARGET_PRIORITY: set packet priority (skb->priority) + * @NFT_META_TARGET_NFTRACE: to set packet nftrace bit (skb->nf_trace) + * @NFT_META_TARGET_SECMARK: 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 of the item to be set with (NLA_U32) + */ +enum nft_meta_target_attributes { + 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/src/Makefile.am b/src/Makefile.am index 83ab658..96f1174 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,6 +29,7 @@ libnftables_la_SOURCES = utils.c \ expr/immediate.c \ expr/match.c \ expr/meta.c \ + expr/meta_target.c \ expr/nat.c \ expr/payload.c \ expr/reject.c \ diff --git a/src/expr/meta_target.c b/src/expr/meta_target.c new file mode 100644 index 0000000..fdfddca --- /dev/null +++ b/src/expr/meta_target.c @@ -0,0 +1,266 @@ +/* + * (C) 2013 by Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <arpa/inet.h> +#include <errno.h> +#include <linux/netfilter/nf_tables.h> + +#include "internal.h" +#include <libmnl/libmnl.h> +#include <libnftables/expr.h> +#include <libnftables/rule.h> +#include "expr_ops.h" + +#ifndef NFT_META_TARGET_MAX +#define NFT_META_TARGET_MAX (NFT_META_TARGET_SECMARK + 1) +#endif + +struct nft_expr_meta_target { + uint32_t key; /* enum nft_meta_target_keys */ + uint32_t value; +}; + +static int +nft_rule_expr_meta_target_set(struct nft_rule_expr *e, uint16_t type, + const void *data, uint32_t data_len) +{ + struct nft_expr_meta_target *meta_target = nft_expr_data(e); + + switch (type) { + case NFT_EXPR_META_TARGET_KEY: + meta_target->key = *((uint32_t *)data); + break; + case NFT_EXPR_META_TARGET_VALUE: + meta_target->value = *((uint32_t *)data); + break; + default: + return -1; + } + return 0; +} + +static const void * +nft_rule_expr_meta_target_get(const struct nft_rule_expr *e, uint16_t type, + uint32_t *data_len) +{ + struct nft_expr_meta_target *meta_target = nft_expr_data(e); + + switch (type) { + case NFT_EXPR_META_TARGET_KEY: + *data_len = sizeof(meta_target->key); + return &meta_target->key; + case NFT_EXPR_META_TARGET_VALUE: + *data_len = sizeof(meta_target->value); + return &meta_target->value; + } + return NULL; +} + +static int nft_rule_expr_meta_target_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, NFTA_META_TARGET_MAX) < 0) + return MNL_CB_OK; + + switch (type) { + case NFTA_META_TARGET_KEY: + case NFTA_META_TARGET_VALUE: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + default: + return MNL_CB_ERROR; + } + + tb[type] = attr; + return MNL_CB_OK; +} + +static void +nft_rule_expr_meta_target_build(struct nlmsghdr *nlh, struct nft_rule_expr *e) +{ + struct nft_expr_meta_target *meta_target = nft_expr_data(e); + + if (e->flags & (1 << NFT_EXPR_META_TARGET_KEY)) + mnl_attr_put_u32(nlh, NFTA_META_TARGET_KEY, + htonl(meta_target->key)); + + if (e->flags & (1 << NFT_EXPR_META_TARGET_VALUE)) + mnl_attr_put_u32(nlh, NFTA_META_TARGET_VALUE, + htonl(meta_target->value)); +} + +static int +nft_rule_expr_meta_target_parse(struct nft_rule_expr *e, struct nlattr *attr) +{ + uint32_t key, value; + struct nft_expr_meta_target *meta_target = nft_expr_data(e); + struct nlattr *tb[NFTA_META_TARGET_MAX+1] = {}; + + if (mnl_attr_parse_nested(attr, nft_rule_expr_meta_target_cb, tb) < 0) + return -1; + + if (tb[NFTA_META_TARGET_KEY]) { + key = ntohl(mnl_attr_get_u32(tb[NFTA_META_TARGET_KEY])); + meta_target->key = key; + e->flags |= (1 << NFT_EXPR_META_TARGET_KEY); + } + + if (tb[NFTA_META_TARGET_VALUE]) { + value = ntohl(mnl_attr_get_u32(tb[NFTA_META_TARGET_VALUE])); + meta_target->value = value; + e->flags |= (1 << NFT_EXPR_META_TARGET_VALUE); + } + + return 0; +} + +const char *meta_target_key2str_array[NFT_META_TARGET_MAX] = { + [NFT_META_TARGET_MARK] = "mark", + [NFT_META_TARGET_PRIORITY] = "priority", + [NFT_META_TARGET_NFTRACE] = "nftrace", + [NFT_META_TARGET_SECMARK] = "secmark", +}; + +static const char *meta_target_key2str(uint8_t key) +{ + if (key < NFT_META_TARGET_MAX) + return meta_target_key2str_array[key]; + + return "unknown"; +} + +static inline int str2meta_target_key(const char *str) +{ + int i; + + for (i = 0; i < NFT_META_TARGET_MAX; i++) { + if (strcmp(str, meta_target_key2str_array[i]) == 0) + return i; + } + + errno = EINVAL; + return -1; +} + +static int nft_rule_expr_meta_target_json_parse(struct nft_rule_expr *e, + json_t *root) +{ +#ifdef JSON_PARSING + const char *key_str; + int key; + uint32_t value; + + key_str = nft_jansson_parse_str(root, "key"); + if (key_str == NULL) + return -1; + + key = str2meta_target_key(key_str); + if (key < 0) + return -1; + + nft_rule_expr_set_u32(e, NFT_EXPR_META_TARGET_KEY, key); + + if (nft_jansson_str2num(root, "value", BASE_HEX, &value, + NFT_TYPE_U32) < 0) + return -1; + + nft_rule_expr_set_u32(e, NFT_EXPR_META_TARGET_VALUE, value); + + return 0; +#else + errno = EOPNOTSUPP; + return -1; +#endif +} + + +static int nft_rule_expr_meta_target_xml_parse(struct nft_rule_expr *e, + mxml_node_t *tree) +{ +#ifdef XML_PARSING + const char *key_str; + int key; + uint32_t value; + + key_str = nft_mxml_str_parse(tree, "key", MXML_DESCEND_FIRST, + NFT_XML_MAND); + if (key_str == NULL) + return -1; + + key = str2meta_target_key(key_str); + if (key < 0) + return -1; + + nft_rule_expr_set_u32(e, NFT_EXPR_META_TARGET_KEY, key); + + if (nft_mxml_num_parse(tree, "value", MXML_DESCEND_FIRST, BASE_HEX, + &value, NFT_TYPE_U32, NFT_XML_MAND) != 0) + return -1; + + nft_rule_expr_set_u32(e, NFT_EXPR_META_TARGET_VALUE, value); + + return 0; +#else + errno = EOPNOTSUPP; + return -1; +#endif +} + +static int +nft_rule_expr_meta_target_snprintf(char *buf, size_t len, uint32_t type, + uint32_t flags, struct nft_rule_expr *e) +{ + struct nft_expr_meta_target *meta_target = nft_expr_data(e); + + switch (type) { + case NFT_OUTPUT_DEFAULT: + return snprintf(buf, len, "set %s to value 0x%.8x ", + meta_target_key2str(meta_target->key), + meta_target->value); + case NFT_OUTPUT_XML: + return snprintf(buf, len, "<key>%s</key><value>0x%.8x</value>", + meta_target_key2str(meta_target->key), + meta_target->value); + case NFT_OUTPUT_JSON: + return snprintf(buf, len, "\"key\":\"%s\"," + "\"value\":\"0x%.8x\"", + meta_target_key2str(meta_target->key), + meta_target->value); + default: + break; + } + return -1; +} + +struct expr_ops expr_ops_meta_target = { + .name = "meta_target", + .alloc_len = sizeof(struct nft_expr_meta_target), + .max_attr = NFTA_META_TARGET_MAX, + .set = nft_rule_expr_meta_target_set, + .get = nft_rule_expr_meta_target_get, + .parse = nft_rule_expr_meta_target_parse, + .build = nft_rule_expr_meta_target_build, + .snprintf = nft_rule_expr_meta_target_snprintf, + .xml_parse = nft_rule_expr_meta_target_xml_parse, + .json_parse = nft_rule_expr_meta_target_json_parse, +}; + +static void __init expr_meta_target_init(void) +{ + nft_expr_ops_register(&expr_ops_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