netfilter: Dissect flow after packet mangling
authorIdo Schimmel <idosch@nvidia.com>
Wed, 14 Apr 2021 08:20:32 +0000 (11:20 +0300)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 18 Apr 2021 20:04:16 +0000 (22:04 +0200)
Netfilter tries to reroute mangled packets as a different route might
need to be used following the mangling. When this happens, netfilter
does not populate the IP protocol, the source port and the destination
port in the flow key. Therefore, FIB rules that match on these fields
are ignored and packets can be misrouted.

Solve this by dissecting the outer flow and populating the flow key
before rerouting the packet. Note that flow dissection only happens when
FIB rules that match on these fields are installed, so in the common
case there should not be a penalty.

Reported-by: Michal Soltys <msoltyspl@yandex.pl>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/ipv4/netfilter.c
net/ipv6/netfilter.c

index 7c841037c53349855f9711a70bd0ac333b8bd716..aff707988e23b0ce6952d25b5c5aaf0b5623c262 100644 (file)
@@ -25,6 +25,7 @@ int ip_route_me_harder(struct net *net, struct sock *sk, struct sk_buff *skb, un
        __be32 saddr = iph->saddr;
        __u8 flags;
        struct net_device *dev = skb_dst(skb)->dev;
+       struct flow_keys flkeys;
        unsigned int hh_len;
 
        sk = sk_to_full_sk(sk);
@@ -48,6 +49,7 @@ int ip_route_me_harder(struct net *net, struct sock *sk, struct sk_buff *skb, un
                fl4.flowi4_oif = l3mdev_master_ifindex(dev);
        fl4.flowi4_mark = skb->mark;
        fl4.flowi4_flags = flags;
+       fib4_rules_early_flow_dissect(net, skb, &fl4, &flkeys);
        rt = ip_route_output_key(net, &fl4);
        if (IS_ERR(rt))
                return PTR_ERR(rt);
index ab9a279dd6d47d34a3ad68e7cb88d588f2c6eaef..6ab710b5a1a828d331bba862b4e31ea553a501fa 100644 (file)
@@ -24,6 +24,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
 {
        const struct ipv6hdr *iph = ipv6_hdr(skb);
        struct sock *sk = sk_to_full_sk(sk_partial);
+       struct flow_keys flkeys;
        unsigned int hh_len;
        struct dst_entry *dst;
        int strict = (ipv6_addr_type(&iph->daddr) &
@@ -38,6 +39,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
        };
        int err;
 
+       fib6_rules_early_flow_dissect(net, skb, &fl6, &flkeys);
        dst = ip6_route_output(net, sk, &fl6);
        err = dst->error;
        if (err) {