aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@nvidia.com>2021-04-14 11:20:32 +0300
committerPablo Neira Ayuso <pablo@netfilter.org>2021-04-18 22:04:16 +0200
commit812fa71f0d967dea7616810f27e98135d410b27e (patch)
tree5c7385ce12cf10921f289c7e65ca809904208f99
parentnetfilter: nftables_offload: special ethertype handling for VLAN (diff)
downloadwireguard-linux-812fa71f0d967dea7616810f27e98135d410b27e.tar.xz
wireguard-linux-812fa71f0d967dea7616810f27e98135d410b27e.zip
netfilter: Dissect flow after packet mangling
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>
-rw-r--r--net/ipv4/netfilter.c2
-rw-r--r--net/ipv6/netfilter.c2
2 files changed, 4 insertions, 0 deletions
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 7c841037c533..aff707988e23 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -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);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index ab9a279dd6d4..6ab710b5a1a8 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -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) {