diff options
author | Florian Westphal <fw@strlen.de> | 2018-03-16 17:39:29 +0100 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2018-03-17 00:06:25 +0100 |
commit | 9642a79381793daedc1d58b3ac4c3c61a2ec38f1 (patch) | |
tree | 43ff83214e0fe1ef6c8004c6073022f0c486d82d | |
parent | ca7253263a0158cafd609d924809232b562131b2 (diff) |
src: fix routing header support
We can't use nft_exthdr_op to encode routing header, it breaks
ipv6 extension header support.
When encountering RT header, userspace did now set a new ipv6 exthdr mode,
but old kernel doesn't know about this, so this failed with -EOPNOTSUPP.
Revert that part and use NFT_EXTHDR_OP_IPV6.
When decoding a routing extension header, try the various route
types until we find a match.
Note this patch isn't complete:
'srh tag 127' creates following expressions:
[ exthdr load 2b @ 43 + 6 => reg 1 ]
[ cmp eq reg 1 0x00007f00 ]
It should instead insert a dependency test ("rt type 4"):
[ exthdr load 1b @ 43 + 2 => reg 1 ]
[ cmp eq reg 1 0x00000004 ]
[ exthdr load 2b @ 43 + 6 => reg 1 ]
[ cmp eq reg 1 0x00007e00 ]
nft should then use this to infer the routing header type.
While add it, document the srh option.
Fixes: 1400288f6d39d ("src: handle rt0 and rt2 properly")
Reported-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Ahmed Abdelsalam <amsalam20@gmail.com>
-rw-r--r-- | doc/nft.xml | 13 | ||||
-rw-r--r-- | include/linux/netfilter/nf_tables.h | 3 | ||||
-rw-r--r-- | src/exthdr.c | 55 |
3 files changed, 46 insertions, 25 deletions
diff --git a/doc/nft.xml b/doc/nft.xml index 07f4f277..962e2933 100644 --- a/doc/nft.xml +++ b/doc/nft.xml @@ -4075,6 +4075,15 @@ input meta iifname enp2s0 arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh </group> </cmdsynopsis> <cmdsynopsis> + <command>srh</command> + <group choice="req"> + <arg>flags</arg> + <arg>tag</arg> + <arg>sid</arg> + <arg>seg-left</arg> + </group> + </cmdsynopsis> + <cmdsynopsis> <command>tcp option</command> <group choice="req"> <arg>eol</arg> @@ -4154,6 +4163,10 @@ input meta iifname enp2s0 arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh <entry>mh</entry> <entry>Mobility Header</entry> </row> + <row> + <entry>srh</entry> + <entry>Segment Routing Header</entry> + </row> </tbody> </tgroup> </table> diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 1a98f03a..517a39a0 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -731,9 +731,6 @@ enum nft_exthdr_flags { enum nft_exthdr_op { NFT_EXTHDR_OP_IPV6, NFT_EXTHDR_OP_TCPOPT, - NFT_EXTHDR_OP_RT0, - NFT_EXTHDR_OP_RT2, - NFT_EXTHDR_OP_RT4, __NFT_EXTHDR_OP_MAX }; #define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) diff --git a/src/exthdr.c b/src/exthdr.c index cbe0da86..06a82070 100644 --- a/src/exthdr.c +++ b/src/exthdr.c @@ -93,19 +93,6 @@ struct expr *exthdr_expr_alloc(const struct location *loc, BYTEORDER_BIG_ENDIAN, tmpl->len); expr->exthdr.desc = desc; expr->exthdr.tmpl = tmpl; - if (desc != NULL && desc->proto_key >= 0) { - switch (desc->proto_key) { - case 0: - expr->exthdr.op = NFT_EXTHDR_OP_RT0; - break; - case 2: - expr->exthdr.op = NFT_EXTHDR_OP_RT2; - break; - case 4: - expr->exthdr.op = NFT_EXTHDR_OP_RT4; - break; - } - } return expr; } @@ -148,6 +135,24 @@ const struct exthdr_desc *exthdr_find_proto(uint8_t proto) return exthdr_protocols[proto]; } +static const struct proto_hdr_template * +exthdr_rt_find(struct expr *expr, const struct exthdr_desc *desc) +{ + const struct proto_hdr_template *tmpl; + unsigned int i; + + for (i = 0; i < array_size(desc->templates); i++) { + tmpl = &desc->templates[i]; + if (tmpl->offset == expr->exthdr.offset && + tmpl->len == expr->len) { + expr->exthdr.desc = desc; + return tmpl; + } + } + + return NULL; +} + void exthdr_init_raw(struct expr *expr, uint8_t type, unsigned int offset, unsigned int len, enum nft_exthdr_op op, uint32_t flags) @@ -164,13 +169,7 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, expr->exthdr.offset = offset; expr->exthdr.desc = NULL; - if (op == NFT_EXTHDR_OP_RT0) - expr->exthdr.desc = &exthdr_rt0; - else if (op == NFT_EXTHDR_OP_RT2) - expr->exthdr.desc = &exthdr_rt2; - else if (op == NFT_EXTHDR_OP_RT4) - expr->exthdr.desc = &exthdr_rt4; - else if (type < array_size(exthdr_protocols)) + if (type < array_size(exthdr_protocols)) expr->exthdr.desc = exthdr_protocols[type]; if (expr->exthdr.desc == NULL) @@ -182,6 +181,18 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, goto out; } + if (expr->exthdr.desc == &exthdr_rt) { + tmpl = exthdr_rt_find(expr, &exthdr_rt4); + if (tmpl) + goto out; + tmpl = exthdr_rt_find(expr, &exthdr_rt0); + if (tmpl) + goto out; + tmpl = exthdr_rt_find(expr, &exthdr_rt2); + if (tmpl) + goto out; + } + tmpl = &exthdr_unknown_template; out: expr->exthdr.tmpl = tmpl; @@ -274,7 +285,7 @@ const struct exthdr_desc exthdr_rt0 = { .templates = { [RT0HDR_RESERVED] = RT0_FIELD("reserved", ip6r0_reserved, &integer_type), [RT0HDR_ADDR_1] = RT0_FIELD("addr[1]", ip6r0_addr[0], &ip6addr_type), - [RT0HDR_ADDR_1 + 1] = RT0_FIELD("addr[2]", ip6r0_addr[0], &ip6addr_type), + [RT0HDR_ADDR_1 + 1] = RT0_FIELD("addr[2]", ip6r0_addr[1], &ip6addr_type), // ... }, }; @@ -291,7 +302,7 @@ const struct exthdr_desc exthdr_rt4 = { [RT4HDR_FLAGS] = RT4_FIELD("flags", ip6r4_flags, &integer_type), [RT4HDR_TAG] = RT4_FIELD("tag", ip6r4_tag, &integer_type), [RT4HDR_SID_1] = RT4_FIELD("sid[1]", ip6r4_segments[0], &ip6addr_type), - [RT4HDR_SID_1 + 1] = RT4_FIELD("sid[1]", ip6r4_segments[0], &ip6addr_type), + [RT4HDR_SID_1 + 1] = RT4_FIELD("sid[2]", ip6r4_segments[1], &ip6addr_type), // ... }, }; |