Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: xt_rpfilter: skip locally generated broadcast/multicast, too

Alex Efros reported rpfilter module doesn't match following packets:
IN=br.qemu SRC=192.168.2.1 DST=192.168.2.255 [ .. ]
(netfilter bugzilla #814).

Problem is that network stack arranges for the locally generated broadcasts
to appear on the interface they were sent out, so the IFF_LOOPBACK check
doesn't trigger.

As -m rpfilter is restricted to PREROUTING, we can check for existing
rtable instead, it catches locally-generated broad/multicast case, too.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
f83a7ea2 5add189a

+14 -2
+7 -1
net/ipv4/netfilter/ipt_rpfilter.c
··· 66 66 return dev_match; 67 67 } 68 68 69 + static bool rpfilter_is_local(const struct sk_buff *skb) 70 + { 71 + const struct rtable *rt = skb_rtable(skb); 72 + return rt && (rt->rt_flags & RTCF_LOCAL); 73 + } 74 + 69 75 static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) 70 76 { 71 77 const struct xt_rpfilter_info *info; ··· 82 76 info = par->matchinfo; 83 77 invert = info->flags & XT_RPFILTER_INVERT; 84 78 85 - if (par->in->flags & IFF_LOOPBACK) 79 + if (rpfilter_is_local(skb)) 86 80 return true ^ invert; 87 81 88 82 iph = ip_hdr(skb);
+7 -1
net/ipv6/netfilter/ip6t_rpfilter.c
··· 71 71 return ret; 72 72 } 73 73 74 + static bool rpfilter_is_local(const struct sk_buff *skb) 75 + { 76 + const struct rt6_info *rt = (const void *) skb_dst(skb); 77 + return rt && (rt->rt6i_flags & RTF_LOCAL); 78 + } 79 + 74 80 static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) 75 81 { 76 82 const struct xt_rpfilter_info *info = par->matchinfo; ··· 84 78 struct ipv6hdr *iph; 85 79 bool invert = info->flags & XT_RPFILTER_INVERT; 86 80 87 - if (par->in->flags & IFF_LOOPBACK) 81 + if (rpfilter_is_local(skb)) 88 82 return true ^ invert; 89 83 90 84 iph = ipv6_hdr(skb);