You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
3.0 KiB
89 lines
3.0 KiB
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;
|
|
|