Permalink
Please
sign in to comment.
Browse files
kernel: netfilter: fix dst entries in flowtable offload
Signed-off-by: Felix Fietkau <nbd@nbd.name>
- Loading branch information...
Showing
with
111 additions
and 11 deletions.
| @@ -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; | |||
0 comments on commit
c89e338