From 8c61fa70f3cebed06b23292a3467f1dbc1b96ce9 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Gonzalez Date: Sun, 25 Feb 2018 18:30:24 +0100 Subject: meta: introduce datatype ifname_type This new datatype is a string subtype. It will allow us to build named maps/sets using meta keys like 'iifname', 'oifname', 'ibriport' or 'obriport'. Example: table inet t { set s { type ifname elements = { "eth0", "eth1" } } chain c { iifname @s accept oifname @s accept } } Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- doc/nft.xml | 8 ++--- include/datatype.h | 2 ++ include/meta.h | 1 + src/datatype.c | 1 + src/evaluate.c | 9 +++--- src/meta.c | 17 ++++++++--- src/netlink_delinearize.c | 13 ++++---- src/netlink_linearize.c | 2 +- .../shell/testcases/maps/0007named_ifname_dtype_0 | 35 ++++++++++++++++++++++ .../shell/testcases/sets/0029named_ifname_dtype_0 | 35 ++++++++++++++++++++++ 10 files changed, 103 insertions(+), 20 deletions(-) create mode 100755 tests/shell/testcases/maps/0007named_ifname_dtype_0 create mode 100755 tests/shell/testcases/sets/0029named_ifname_dtype_0 diff --git a/doc/nft.xml b/doc/nft.xml index 9d21e9a1..6748265c 100644 --- a/doc/nft.xml +++ b/doc/nft.xml @@ -2572,7 +2572,7 @@ filter output icmpv6 type { echo-request, echo-reply } iifname Input interface name - string + ifname iiftype @@ -2587,7 +2587,7 @@ filter output icmpv6 type { echo-request, echo-reply } oifname Output interface name - string + ifname oiftype @@ -2612,12 +2612,12 @@ filter output icmpv6 type { echo-request, echo-reply } ibriport Input bridge interface name - string + ifname obriport Output bridge interface name - string + ifname pkttype diff --git a/include/datatype.h b/include/datatype.h index cc4cb078..3f612e52 100644 --- a/include/datatype.h +++ b/include/datatype.h @@ -41,6 +41,7 @@ * @TYPE_ICMPX_CODE: icmpx code (integer subtype) * @TYPE_DEVGROUP: devgroup code (integer subtype) * @TYPE_DSCP: Differentiated Services Code Point (integer subtype) + * @TYPE_IFNAME: interface name (string subtype) */ enum datatypes { TYPE_INVALID, @@ -84,6 +85,7 @@ enum datatypes { TYPE_FIB_ADDR, TYPE_BOOLEAN, TYPE_CT_EVENTBIT, + TYPE_IFNAME, __TYPE_MAX }; #define TYPE_MAX (__TYPE_MAX - 1) diff --git a/include/meta.h b/include/meta.h index 47b16c4b..6086a71c 100644 --- a/include/meta.h +++ b/include/meta.h @@ -38,5 +38,6 @@ extern const struct datatype gid_type; extern const struct datatype uid_type; extern const struct datatype devgroup_type; extern const struct datatype pkttype_type; +extern const struct datatype ifname_type; #endif /* NFTABLES_META_H */ diff --git a/src/datatype.c b/src/datatype.c index 93726caf..324ac802 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -68,6 +68,7 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = { [TYPE_ECN] = &ecn_type, [TYPE_FIB_ADDR] = &fib_addr_type, [TYPE_BOOLEAN] = &boolean_type, + [TYPE_IFNAME] = &ifname_type, }; const struct datatype *datatype_lookup(enum datatypes type) diff --git a/src/evaluate.c b/src/evaluate.c index e5ad1044..c98749d9 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -245,7 +245,7 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp) /* We need to reallocate the constant expression with the right * expression length to avoid problems on big endian. */ - value = constant_expr_alloc(&expr->location, &string_type, + value = constant_expr_alloc(&expr->location, ctx->ectx.dtype, BYTEORDER_HOST_ENDIAN, expr->len, data); expr_free(expr); @@ -260,20 +260,20 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp) memset(unescaped_str, 0, sizeof(unescaped_str)); xstrunescape(data, unescaped_str); - value = constant_expr_alloc(&expr->location, &string_type, + value = constant_expr_alloc(&expr->location, ctx->ectx.dtype, BYTEORDER_HOST_ENDIAN, expr->len, unescaped_str); expr_free(expr); *exprp = value; return 0; } - value = constant_expr_alloc(&expr->location, &string_type, + value = constant_expr_alloc(&expr->location, ctx->ectx.dtype, BYTEORDER_HOST_ENDIAN, datalen * BITS_PER_BYTE, data); prefix = prefix_expr_alloc(&expr->location, value, datalen * BITS_PER_BYTE); - prefix->dtype = &string_type; + prefix->dtype = ctx->ectx.dtype; prefix->flags |= EXPR_F_CONSTANT; prefix->byteorder = BYTEORDER_HOST_ENDIAN; @@ -1769,6 +1769,7 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp) meta->meta.key == NFT_META_NFPROTO) return expr_error(ctx->msgs, meta, "meta nfproto is only useful in the inet family"); + return expr_evaluate_primary(ctx, exprp); } diff --git a/src/meta.c b/src/meta.c index 8c2eca27..11de2dab 100644 --- a/src/meta.c +++ b/src/meta.c @@ -369,6 +369,15 @@ const struct datatype devgroup_type = { .flags = DTYPE_F_PREFIX, }; +const struct datatype ifname_type = { + .type = TYPE_IFNAME, + .name = "ifname", + .desc = "network interface name", + .byteorder = BYTEORDER_HOST_ENDIAN, + .size = IFNAMSIZ * BITS_PER_BYTE, + .basetype = &string_type, +}; + static const struct meta_template meta_templates[] = { [NFT_META_LEN] = META_TEMPLATE("length", &integer_type, 4 * 8, BYTEORDER_HOST_ENDIAN), @@ -384,14 +393,14 @@ static const struct meta_template meta_templates[] = { 4 * 8, BYTEORDER_HOST_ENDIAN), [NFT_META_IIF] = META_TEMPLATE("iif", &ifindex_type, 4 * 8, BYTEORDER_HOST_ENDIAN), - [NFT_META_IIFNAME] = META_TEMPLATE("iifname", &string_type, + [NFT_META_IIFNAME] = META_TEMPLATE("iifname", &ifname_type, IFNAMSIZ * BITS_PER_BYTE, BYTEORDER_HOST_ENDIAN), [NFT_META_IIFTYPE] = META_TEMPLATE("iiftype", &arphrd_type, 2 * 8, BYTEORDER_HOST_ENDIAN), [NFT_META_OIF] = META_TEMPLATE("oif", &ifindex_type, 4 * 8, BYTEORDER_HOST_ENDIAN), - [NFT_META_OIFNAME] = META_TEMPLATE("oifname", &string_type, + [NFT_META_OIFNAME] = META_TEMPLATE("oifname", &ifname_type, IFNAMSIZ * BITS_PER_BYTE, BYTEORDER_HOST_ENDIAN), [NFT_META_OIFTYPE] = META_TEMPLATE("oiftype", &arphrd_type, @@ -404,10 +413,10 @@ static const struct meta_template meta_templates[] = { 1 , BYTEORDER_HOST_ENDIAN), [NFT_META_RTCLASSID] = META_TEMPLATE("rtclassid", &realm_type, 4 * 8, BYTEORDER_HOST_ENDIAN), - [NFT_META_BRI_IIFNAME] = META_TEMPLATE("ibriport", &string_type, + [NFT_META_BRI_IIFNAME] = META_TEMPLATE("ibriport", &ifname_type, IFNAMSIZ * BITS_PER_BYTE, BYTEORDER_HOST_ENDIAN), - [NFT_META_BRI_OIFNAME] = META_TEMPLATE("obriport", &string_type, + [NFT_META_BRI_OIFNAME] = META_TEMPLATE("obriport", &ifname_type, IFNAMSIZ * BITS_PER_BYTE, BYTEORDER_HOST_ENDIAN), [NFT_META_PKTTYPE] = META_TEMPLATE("pkttype", &pkttype_type, diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 622425ee..a1f0e923 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -271,9 +271,8 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx, right = netlink_alloc_value(loc, &nld); if (left->len > right->len && - left->dtype != &string_type) { - return netlink_error(ctx, loc, - "Relational expression size mismatch"); + expr_basetype(left) != &string_type) { + return netlink_error(ctx, loc, "Relational expression size mismatch"); } else if (left->len > 0 && left->len < right->len) { left = netlink_parse_concat_expr(ctx, loc, sreg, right->len); if (left == NULL) @@ -1728,7 +1727,7 @@ static struct expr *string_wildcard_expr_alloc(struct location *loc, data[pos] = '*'; data[pos + 1] = '\0'; - return constant_expr_alloc(loc, &string_type, BYTEORDER_HOST_ENDIAN, + return constant_expr_alloc(loc, expr->dtype, BYTEORDER_HOST_ENDIAN, expr->len + BITS_PER_BYTE, data); } @@ -1744,7 +1743,7 @@ static void escaped_string_wildcard_expr_alloc(struct expr **exprp, data[pos - 1] = '\\'; data[pos] = '*'; - tmp = constant_expr_alloc(&expr->location, &string_type, + tmp = constant_expr_alloc(&expr->location, expr->dtype, BYTEORDER_HOST_ENDIAN, expr->len + BITS_PER_BYTE, data); expr_free(expr); @@ -1789,7 +1788,7 @@ static struct expr *expr_postprocess_string(struct expr *expr) { struct expr *mask; - assert(expr->dtype->type == TYPE_STRING); + assert(expr_basetype(expr)->type == TYPE_STRING); if (__expr_postprocess_string(&expr)) return expr; @@ -1893,7 +1892,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) if (expr->byteorder == BYTEORDER_HOST_ENDIAN) mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); - if (expr->dtype->type == TYPE_STRING) + if (expr_basetype(expr)->type == TYPE_STRING) *exprp = expr_postprocess_string(expr); if (expr->dtype->basetype != NULL && diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 99a4dde2..77abdcb8 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -364,7 +364,7 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx, return netlink_gen_lookup(ctx, expr, dreg); case EXPR_PREFIX: sreg = get_register(ctx, expr->left); - if (expr->left->dtype->type != TYPE_STRING) { + if (expr_basetype(expr->left)->type != TYPE_STRING) { len = div_round_up(expr->right->len, BITS_PER_BYTE); netlink_gen_expr(ctx, expr->left, sreg); right = netlink_gen_prefix(ctx, expr, sreg); diff --git a/tests/shell/testcases/maps/0007named_ifname_dtype_0 b/tests/shell/testcases/maps/0007named_ifname_dtype_0 new file mode 100755 index 00000000..dcbcf2f0 --- /dev/null +++ b/tests/shell/testcases/maps/0007named_ifname_dtype_0 @@ -0,0 +1,35 @@ +#!/bin/bash + +# support for ifname in named maps + +tmpfile=$(mktemp) +if [ ! -w $tmpfile ] ; then + echo "Failed to create tmp file" >&2 + exit 0 +fi + +trap "rm -rf $tmpfile" EXIT # cleanup if aborted + +EXPECTED="table inet t { + map m1 { + type ifname : ipv4_addr + elements = { \"eth0\" : 1.1.1.1 } + } + + chain c { + ip daddr set iifname map @m1 + ip daddr set oifname map @m1 + } +}" + +set -e +echo "$EXPECTED" > $tmpfile +$NFT -f $tmpfile + +GET="$($NFT list ruleset)" +if [ "$EXPECTED" != "$GET" ] ; then + DIFF="$(which diff)" + [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET") + exit 1 +fi + diff --git a/tests/shell/testcases/sets/0029named_ifname_dtype_0 b/tests/shell/testcases/sets/0029named_ifname_dtype_0 new file mode 100755 index 00000000..8b7ab982 --- /dev/null +++ b/tests/shell/testcases/sets/0029named_ifname_dtype_0 @@ -0,0 +1,35 @@ +#!/bin/bash + +# support for ifname in named sets + +tmpfile=$(mktemp) +if [ ! -w $tmpfile ] ; then + echo "Failed to create tmp file" >&2 + exit 0 +fi + +trap "rm -rf $tmpfile" EXIT # cleanup if aborted + +EXPECTED="table inet t { + set s { + type ifname + elements = { \"eth0\" } + } + + chain c { + iifname @s accept + oifname @s accept + } +}" + +set -e +echo "$EXPECTED" > $tmpfile +$NFT -f $tmpfile + +GET="$($NFT list ruleset)" +if [ "$EXPECTED" != "$GET" ] ; then + DIFF="$(which diff)" + [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET") + exit 1 +fi + -- cgit v1.2.3