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