netfilter: af_info: add 'strict' parameter to limit lookup to .oif

ipv6 fib lookup can set RT6_LOOKUP_F_IFACE flag to restrict search
to an interface, but this flag cannot be set via struct flowi.

Also, it cannot be set via ip6_route_output: this function uses the
passed sock struct to determine if this flag is required
(by testing for nonzero sk_bound_dev_if).

Work around this by passing in an artificial struct sk in case
'strict' argument is true.

This is required to replace the rt6_lookup call in xt_addrtype.c with
nf_afinfo->route().

Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by Florian Westphal and committed by Patrick McHardy 0fae2e77 31ad3dd6

+17 -9
+1 -1
include/linux/netfilter.h
··· 271 271 unsigned int len, 272 272 u_int8_t protocol); 273 273 int (*route)(struct net *net, struct dst_entry **dst, 274 - struct flowi *fl); 274 + struct flowi *fl, bool strict); 275 275 void (*saveroute)(const struct sk_buff *skb, 276 276 struct nf_queue_entry *entry); 277 277 int (*reroute)(struct sk_buff *skb,
+1 -1
net/ipv4/netfilter.c
··· 222 222 } 223 223 224 224 static int nf_ip_route(struct net *net, struct dst_entry **dst, 225 - struct flowi *fl) 225 + struct flowi *fl, bool strict __always_unused) 226 226 { 227 227 struct rtable *rt = ip_route_output_key(net, &fl->u.ip4); 228 228 if (IS_ERR(rt))
+10 -2
net/ipv6/netfilter.c
··· 91 91 } 92 92 93 93 static int nf_ip6_route(struct net *net, struct dst_entry **dst, 94 - struct flowi *fl) 94 + struct flowi *fl, bool strict) 95 95 { 96 - *dst = ip6_route_output(net, NULL, &fl->u.ip6); 96 + static const struct ipv6_pinfo fake_pinfo; 97 + static const struct inet_sock fake_sk = { 98 + /* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */ 99 + .sk.sk_bound_dev_if = 1, 100 + .pinet6 = (struct ipv6_pinfo *) &fake_pinfo, 101 + }; 102 + const void *sk = strict ? &fake_sk : NULL; 103 + 104 + *dst = ip6_route_output(net, sk, &fl->u.ip6); 97 105 return (*dst)->error; 98 106 } 99 107
+4 -4
net/netfilter/nf_conntrack_h323_main.c
··· 732 732 memset(&fl2, 0, sizeof(fl2)); 733 733 fl2.daddr = dst->ip; 734 734 if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, 735 - flowi4_to_flowi(&fl1))) { 735 + flowi4_to_flowi(&fl1), false)) { 736 736 if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, 737 - flowi4_to_flowi(&fl2))) { 737 + flowi4_to_flowi(&fl2), false)) { 738 738 if (rt1->rt_gateway == rt2->rt_gateway && 739 739 rt1->dst.dev == rt2->dst.dev) 740 740 ret = 1; ··· 756 756 memset(&fl2, 0, sizeof(fl2)); 757 757 ipv6_addr_copy(&fl2.daddr, &dst->in6); 758 758 if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, 759 - flowi6_to_flowi(&fl1))) { 759 + flowi6_to_flowi(&fl1), false)) { 760 760 if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, 761 - flowi6_to_flowi(&fl2))) { 761 + flowi6_to_flowi(&fl2), false)) { 762 762 if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway, 763 763 sizeof(rt1->rt6i_gateway)) && 764 764 rt1->dst.dev == rt2->dst.dev)
+1 -1
net/netfilter/xt_TCPMSS.c
··· 166 166 rcu_read_lock(); 167 167 ai = nf_get_afinfo(family); 168 168 if (ai != NULL) 169 - ai->route(&init_net, (struct dst_entry **)&rt, &fl); 169 + ai->route(&init_net, (struct dst_entry **)&rt, &fl, false); 170 170 rcu_read_unlock(); 171 171 172 172 if (rt != NULL) {