]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
meta: add l4proto support
authorPatrick McHardy <kaber@trash.net>
Wed, 8 Jan 2014 13:02:16 +0000 (13:02 +0000)
committerPatrick McHardy <kaber@trash.net>
Wed, 8 Jan 2014 13:03:19 +0000 (13:03 +0000)
Add support for the meta l4proto type. This is used in the inet table to
match on the transport layer protocol without requiring the network layer
protocol to be known, allowing to use transport header matches that apply
to both IPv4 and IPv6.

Signed-off-by: Patrick McHardy <kaber@trash.net>
include/proto.h
src/meta.c
src/parser.y
src/payload.c
src/proto.c
src/scanner.l

index 772f9ed7429e2bdd9fe2f8cc2c06fdf4219aae2c..bd3701e31fed07a36bfc4a30b3567334a8350cc6 100644 (file)
@@ -291,6 +291,7 @@ extern const struct proto_desc proto_ip;
 extern const struct proto_desc proto_ip6;
 
 extern const struct proto_desc proto_inet;
+extern const struct proto_desc proto_inet_service;
 
 extern const struct proto_desc proto_arp;
 
index 1286569aefb24860025bc18e541b2361ecc47100..d7b024b68cb75ff6e00eb3bf2b5ec88a674b029a 100644 (file)
@@ -303,6 +303,8 @@ static const struct meta_template meta_templates[] = {
                                                2 * 8, BYTEORDER_BIG_ENDIAN),
        [NFT_META_NFPROTO]      = META_TEMPLATE("nfproto",   &nfproto_type,
                                                1 * 8, BYTEORDER_HOST_ENDIAN),
+       [NFT_META_L4PROTO]      = META_TEMPLATE("l4proto",   &inet_protocol_type,
+                                               1 * 8, BYTEORDER_HOST_ENDIAN),
        [NFT_META_PRIORITY]     = META_TEMPLATE("priority",  &tchandle_type,
                                                4 * 8, BYTEORDER_HOST_ENDIAN),
        [NFT_META_MARK]         = META_TEMPLATE("mark",      &mark_type,
@@ -378,6 +380,14 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
 
                proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc);
                break;
+       case NFT_META_L4PROTO:
+               desc = proto_find_upper(&proto_inet_service,
+                                       mpz_get_uint8(right->value));
+               if (desc == NULL)
+                       desc = &proto_unknown;
+
+               proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, desc);
+               break;
        default:
                break;
        }
@@ -408,6 +418,10 @@ struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
                expr->flags |= EXPR_F_PROTOCOL;
                expr->meta.base = PROTO_BASE_LL_HDR;
                break;
+       case NFT_META_L4PROTO:
+               expr->flags |= EXPR_F_PROTOCOL;
+               expr->meta.base = PROTO_BASE_NETWORK_HDR;
+               break;
        default:
                break;
        }
index aed00c7fcd1aaa4544bd09717b9994103baafb96..7c18875dc406ef99bd43f13ba6b63bf8997562be 100644 (file)
@@ -282,6 +282,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %token META                    "meta"
 %token NFPROTO                 "nfproto"
+%token L4PROTO                 "l4proto"
 %token MARK                    "mark"
 %token IIF                     "iif"
 %token IIFNAME                 "iifname"
@@ -1378,6 +1379,7 @@ meta_expr         :       META    meta_key
 
 meta_key               :       LENGTH          { $$ = NFT_META_LEN; }
                        |       NFPROTO         { $$ = NFT_META_NFPROTO; }
+                       |       L4PROTO         { $$ = NFT_META_L4PROTO; }
                        |       PROTOCOL        { $$ = NFT_META_PROTOCOL; }
                        |       PRIORITY        { $$ = NFT_META_PRIORITY; }
                        |       MARK            { $$ = NFT_META_MARK; }
index ac441d4e5795768e7936a28d0b5c2d8c0a40c3df..a312e0796f6237deeefe5c2adc55d673cf026a05 100644 (file)
@@ -174,6 +174,12 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
        }
 
        desc = ctx->pctx.protocol[expr->payload.base - 1].desc;
+       /* Special case for mixed IPv4/IPv6 tables: use meta L4 proto */
+       if (desc == NULL &&
+           ctx->pctx.family == NFPROTO_INET &&
+           expr->payload.base == PROTO_BASE_TRANSPORT_HDR)
+               desc = &proto_inet_service;
+
        if (desc == NULL)
                return expr_error(ctx, expr,
                                  "ambiguous payload specification: "
index 81fe6cfdab0ed67e559067da183800580fb4c792..56fb7930f6e4c1a1531b5773c8fcb96271b7bbe2 100644 (file)
@@ -625,6 +625,31 @@ const struct proto_desc proto_inet = {
        },
 };
 
+/*
+ * Dummy protocol for cases where the network layer protocol isn't known
+ * (IPv4 or IPv6), The higher layer protocols are the protocols common to
+ * both.
+ */
+
+const struct proto_desc proto_inet_service = {
+       .name           = "inet-service",
+       .base           = PROTO_BASE_TRANSPORT_HDR,
+       .protocol_key   = 0,
+       .protocols      = {
+               PROTO_LINK(IPPROTO_ESP,         &proto_esp),
+               PROTO_LINK(IPPROTO_AH,          &proto_ah),
+               PROTO_LINK(IPPROTO_COMP,        &proto_comp),
+               PROTO_LINK(IPPROTO_UDP,         &proto_udp),
+               PROTO_LINK(IPPROTO_UDPLITE,     &proto_udplite),
+               PROTO_LINK(IPPROTO_TCP,         &proto_tcp),
+               PROTO_LINK(IPPROTO_DCCP,        &proto_dccp),
+               PROTO_LINK(IPPROTO_SCTP,        &proto_sctp),
+       },
+       .templates      = {
+               [0]     = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
+       },
+};
+
 /*
  * ARP
  */
index 9541eb0524dd7565c74bdef9c28ac9450de64717..0b8abacbe8a6d84fd9513f354b8b78abf3c0b5d2 100644 (file)
@@ -372,6 +372,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 
 "meta"                 { return META; }
 "nfproto"              { return NFPROTO; }
+"l4proto"              { return L4PROTO; }
 "mark"                 { return MARK; }
 "iif"                  { return IIF; }
 "iifname"              { return IIFNAME; }