]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
exthdr: support ip/tcp options and sctp chunks in typeof expressions
authorFlorian Westphal <fw@strlen.de>
Fri, 3 Dec 2021 16:07:54 +0000 (17:07 +0100)
committerFlorian Westphal <fw@strlen.de>
Tue, 7 Dec 2021 11:23:21 +0000 (12:23 +0100)
This did not store the 'op' member and listing always treated this as ipv6
extension header.

Add test cases for this.

Signed-off-by: Florian Westphal <fw@strlen.de>
src/exthdr.c
tests/shell/testcases/sets/dumps/typeof_sets_0.nft
tests/shell/testcases/sets/typeof_sets_0

index 2357ab60648d58e97f4ae6a94b98c45594bd775f..3e5f5cd8b73e13af3a8586b4c2e4148e22b324be 100644 (file)
@@ -115,7 +115,8 @@ static void exthdr_expr_clone(struct expr *new, const struct expr *expr)
 
 #define NFTNL_UDATA_EXTHDR_DESC 0
 #define NFTNL_UDATA_EXTHDR_TYPE 1
-#define NFTNL_UDATA_EXTHDR_MAX 2
+#define NFTNL_UDATA_EXTHDR_OP  2
+#define NFTNL_UDATA_EXTHDR_MAX 3
 
 static int exthdr_parse_udata(const struct nftnl_udata *attr, void *data)
 {
@@ -126,6 +127,7 @@ static int exthdr_parse_udata(const struct nftnl_udata *attr, void *data)
        switch (type) {
        case NFTNL_UDATA_EXTHDR_DESC:
        case NFTNL_UDATA_EXTHDR_TYPE:
+       case NFTNL_UDATA_EXTHDR_OP:
                if (len != sizeof(uint32_t))
                        return -1;
                break;
@@ -140,6 +142,7 @@ static int exthdr_parse_udata(const struct nftnl_udata *attr, void *data)
 static struct expr *exthdr_expr_parse_udata(const struct nftnl_udata *attr)
 {
        const struct nftnl_udata *ud[NFTNL_UDATA_EXTHDR_MAX + 1] = {};
+       enum nft_exthdr_op op = NFT_EXTHDR_OP_IPV6;
        const struct exthdr_desc *desc;
        unsigned int type;
        uint32_t desc_id;
@@ -154,14 +157,31 @@ static struct expr *exthdr_expr_parse_udata(const struct nftnl_udata *attr)
            !ud[NFTNL_UDATA_EXTHDR_TYPE])
                return NULL;
 
-       desc_id = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_DESC]);
-       desc = exthdr_find_desc(desc_id);
-       if (!desc)
-               return NULL;
+       if (ud[NFTNL_UDATA_EXTHDR_OP])
+               op = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_OP]);
 
+       desc_id = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_DESC]);
        type = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_TYPE]);
 
-       return exthdr_expr_alloc(&internal_location, desc, type);
+       switch (op) {
+       case NFT_EXTHDR_OP_IPV6:
+               desc = exthdr_find_desc(desc_id);
+
+               return exthdr_expr_alloc(&internal_location, desc, type);
+       case NFT_EXTHDR_OP_TCPOPT:
+               return tcpopt_expr_alloc(&internal_location,
+                                        desc_id, type);
+       case NFT_EXTHDR_OP_IPV4:
+               return ipopt_expr_alloc(&internal_location,
+                                        desc_id, type);
+       case NFT_EXTHDR_OP_SCTP:
+               return sctp_chunk_expr_alloc(&internal_location,
+                                            desc_id, type);
+       case __NFT_EXTHDR_OP_MAX:
+               return NULL;
+       }
+
+       return NULL;
 }
 
 static unsigned int expr_exthdr_type(const struct exthdr_desc *desc,
@@ -176,9 +196,22 @@ static int exthdr_expr_build_udata(struct nftnl_udata_buf *udbuf,
        const struct proto_hdr_template *tmpl = expr->exthdr.tmpl;
        const struct exthdr_desc *desc = expr->exthdr.desc;
        unsigned int type = expr_exthdr_type(desc, tmpl);
+       enum nft_exthdr_op op = expr->exthdr.op;
 
-       nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, desc->id);
        nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_TYPE, type);
+       switch (op) {
+       case NFT_EXTHDR_OP_IPV6:
+               nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, desc->id);
+               break;
+       case NFT_EXTHDR_OP_TCPOPT:
+       case NFT_EXTHDR_OP_IPV4:
+       case NFT_EXTHDR_OP_SCTP:
+               nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_OP, op);
+               nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, expr->exthdr.raw_type);
+               break;
+       default:
+               return -1;
+       }
 
        return 0;
 }
index 06d891e682b743941375f86597c4f137234d839b..8f11b110552c0fa2220f53503badee5d70381942 100644 (file)
@@ -19,6 +19,21 @@ table inet t {
                elements = { 1, 1024 }
        }
 
+       set s5 {
+               typeof ip option ra value
+               elements = { 1, 1024 }
+       }
+
+       set s6 {
+               typeof tcp option maxseg size
+               elements = { 1, 1024 }
+       }
+
+       set s7 {
+               typeof sctp chunk init num-inbound-streams
+               elements = { 1, 4 }
+       }
+
        chain c1 {
                osf name @s1 accept
        }
@@ -26,4 +41,16 @@ table inet t {
        chain c2 {
                vlan id @s2 accept
        }
+
+       chain c5 {
+               ip option ra value @s5 accept
+       }
+
+       chain c6 {
+               tcp option maxseg size @s6 accept
+       }
+
+       chain c7 {
+               sctp chunk init num-inbound-streams @s7 accept
+       }
 }
index a6ff8ca772e255fd7dfd6c875b6f4d48f668f450..1e99e298773357f59a8743105437aea6d628063e 100755 (executable)
@@ -25,6 +25,21 @@ EXPECTED="table inet t {
                elements = { 1, 1024 }
        }
 
+       set s5 {
+               typeof ip option ra value
+               elements = { 1, 1024 }
+       }
+
+       set s6 {
+               typeof tcp option maxseg size
+               elements = { 1, 1024 }
+       }
+
+       set s7 {
+               typeof sctp chunk init num-inbound-streams
+               elements = { 1, 4 }
+       }
+
        chain c1 {
                osf name @s1 accept
        }
@@ -32,6 +47,18 @@ EXPECTED="table inet t {
        chain c2 {
                ether type vlan vlan id @s2 accept
        }
+
+       chain c5 {
+               ip option ra value @s5 accept
+       }
+
+       chain c6 {
+               tcp option maxseg size @s6 accept
+       }
+
+       chain c7 {
+               sctp chunk init num-inbound-streams @s7 accept
+       }
 }"
 
 set -e