aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-4.14
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2018-03-15 18:03:22 +0100
committerFelix Fietkau <nbd@nbd.name>2018-03-23 20:56:34 +0100
commitc89e338fe68fd5af61b80ef37c55a657721c6542 (patch)
tree713bf76b8bfe0bfc7548979bf4932aff68049b30 /target/linux/generic/backport-4.14
parentdb108cdf14129698cb0740efe72f37f816d40267 (diff)
downloadupstream-c89e338fe68fd5af61b80ef37c55a657721c6542.tar.gz
upstream-c89e338fe68fd5af61b80ef37c55a657721c6542.tar.bz2
upstream-c89e338fe68fd5af61b80ef37c55a657721c6542.zip
kernel: netfilter: fix dst entries in flowtable offload
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'target/linux/generic/backport-4.14')
-rw-r--r--target/linux/generic/backport-4.14/366-netfilter-nf_flow_table-clean-up-and-fix-dst-handlin.patch89
1 files changed, 89 insertions, 0 deletions
diff --git a/target/linux/generic/backport-4.14/366-netfilter-nf_flow_table-clean-up-and-fix-dst-handlin.patch b/target/linux/generic/backport-4.14/366-netfilter-nf_flow_table-clean-up-and-fix-dst-handlin.patch
new file mode 100644
index 0000000000..491f057858
--- /dev/null
+++ b/target/linux/generic/backport-4.14/366-netfilter-nf_flow_table-clean-up-and-fix-dst-handlin.patch
@@ -0,0 +1,89 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 15 Mar 2018 18:21:43 +0100
+Subject: [PATCH] netfilter: nf_flow_table: clean up and fix dst handling
+
+dst handling in the code is inconsistent and possibly wrong. In my test,
+skb_dst(skb) holds the dst entry after routing but before NAT, so the
+code could possibly return the same dst entry for both directions of a
+connection.
+Additionally, there was some confusion over the dst entry vs the address
+passed as parameter to rt_nexthop/rt6_nexthop.
+
+Do an explicit dst lookup for both ends of the connection and always use
+the source address for it. When running the IP hook, use the dst entry
+for the opposite direction for determining the route.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -238,7 +238,7 @@ nf_flow_offload_ip_hook(void *priv, stru
+
+ dir = tuplehash->tuple.dir;
+ flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+- rt = (const struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
++ rt = (const struct rtable *)flow->tuplehash[!dir].tuple.dst_cache;
+
+ if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)) &&
+ (ip_hdr(skb)->frag_off & htons(IP_DF)) != 0)
+@@ -455,7 +455,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
+
+ dir = tuplehash->tuple.dir;
+ flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+- rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
++ rt = (struct rt6_info *)flow->tuplehash[!dir].tuple.dst_cache;
+
+ if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
+ return NF_ACCEPT;
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -17,27 +17,38 @@ struct nft_flow_offload {
+ struct nft_flowtable *flowtable;
+ };
+
+-static int nft_flow_route(const struct nft_pktinfo *pkt,
+- const struct nf_conn *ct,
+- struct nf_flow_route *route,
+- enum ip_conntrack_dir dir)
++static struct dst_entry *
++nft_flow_dst(const struct nf_conn *ct, enum ip_conntrack_dir dir,
++ const struct nft_pktinfo *pkt)
+ {
+- struct dst_entry *this_dst = skb_dst(pkt->skb);
+- struct dst_entry *other_dst = NULL;
++ struct dst_entry *dst;
+ struct flowi fl;
+
+ memset(&fl, 0, sizeof(fl));
+ switch (nft_pf(pkt)) {
+ case NFPROTO_IPV4:
+- fl.u.ip4.daddr = ct->tuplehash[!dir].tuple.dst.u3.ip;
++ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
+ break;
+ case NFPROTO_IPV6:
+- fl.u.ip6.daddr = ct->tuplehash[!dir].tuple.dst.u3.in6;
++ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
+ break;
+ }
+
+- nf_route(nft_net(pkt), &other_dst, &fl, false, nft_pf(pkt));
+- if (!other_dst)
++ nf_route(nft_net(pkt), &dst, &fl, false, nft_pf(pkt));
++
++ return dst;
++}
++
++static int nft_flow_route(const struct nft_pktinfo *pkt,
++ const struct nf_conn *ct,
++ struct nf_flow_route *route,
++ enum ip_conntrack_dir dir)
++{
++ struct dst_entry *this_dst, *other_dst;
++
++ this_dst = nft_flow_dst(ct, dir, pkt);
++ other_dst = nft_flow_dst(ct, !dir, pkt);
++ if (!this_dst || !other_dst)
+ return -ENOENT;
+
+ route->tuple[dir].dst = this_dst;