xref: /openbmc/linux/net/netfilter/xt_physdev.c (revision 1d93a9cb)
12e4e6a17SHarald Welte /* Kernel module to match the bridge port in and
22e4e6a17SHarald Welte  * out device for IP packets coming into contact with a bridge. */
32e4e6a17SHarald Welte 
42e4e6a17SHarald Welte /* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
52e4e6a17SHarald Welte  *
62e4e6a17SHarald Welte  * This program is free software; you can redistribute it and/or modify
72e4e6a17SHarald Welte  * it under the terms of the GNU General Public License version 2 as
82e4e6a17SHarald Welte  * published by the Free Software Foundation.
92e4e6a17SHarald Welte  */
102e4e6a17SHarald Welte 
112e4e6a17SHarald Welte #include <linux/module.h>
122e4e6a17SHarald Welte #include <linux/skbuff.h>
13deb47c66SAndrew Morton #include <linux/netfilter_bridge.h>
142e4e6a17SHarald Welte #include <linux/netfilter/xt_physdev.h>
152e4e6a17SHarald Welte #include <linux/netfilter/x_tables.h>
162e4e6a17SHarald Welte #include <linux/netfilter_bridge.h>
172e4e6a17SHarald Welte 
182e4e6a17SHarald Welte MODULE_LICENSE("GPL");
192e4e6a17SHarald Welte MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
202e4e6a17SHarald Welte MODULE_DESCRIPTION("iptables bridge physical device match module");
212e4e6a17SHarald Welte MODULE_ALIAS("ipt_physdev");
222e4e6a17SHarald Welte MODULE_ALIAS("ip6t_physdev");
232e4e6a17SHarald Welte 
241d93a9cbSJan Engelhardt static bool
252e4e6a17SHarald Welte match(const struct sk_buff *skb,
262e4e6a17SHarald Welte       const struct net_device *in,
272e4e6a17SHarald Welte       const struct net_device *out,
28c4986734SPatrick McHardy       const struct xt_match *match,
292e4e6a17SHarald Welte       const void *matchinfo,
302e4e6a17SHarald Welte       int offset,
312e4e6a17SHarald Welte       unsigned int protoff,
32cff533acSJan Engelhardt       bool *hotdrop)
332e4e6a17SHarald Welte {
342e4e6a17SHarald Welte 	int i;
352e4e6a17SHarald Welte 	static const char nulldevname[IFNAMSIZ];
362e4e6a17SHarald Welte 	const struct xt_physdev_info *info = matchinfo;
371d93a9cbSJan Engelhardt 	bool ret;
382e4e6a17SHarald Welte 	const char *indev, *outdev;
392e4e6a17SHarald Welte 	struct nf_bridge_info *nf_bridge;
402e4e6a17SHarald Welte 
412e4e6a17SHarald Welte 	/* Not a bridged IP packet or no info available yet:
422e4e6a17SHarald Welte 	 * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
432e4e6a17SHarald Welte 	 * the destination device will be a bridge. */
442e4e6a17SHarald Welte 	if (!(nf_bridge = skb->nf_bridge)) {
452e4e6a17SHarald Welte 		/* Return MATCH if the invert flags of the used options are on */
462e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
472e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_BRIDGED))
481d93a9cbSJan Engelhardt 			return false;
492e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
502e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_ISIN))
511d93a9cbSJan Engelhardt 			return false;
522e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
532e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_ISOUT))
541d93a9cbSJan Engelhardt 			return false;
552e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
562e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_IN))
571d93a9cbSJan Engelhardt 			return false;
582e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
592e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_OUT))
601d93a9cbSJan Engelhardt 			return false;
611d93a9cbSJan Engelhardt 		return true;
622e4e6a17SHarald Welte 	}
632e4e6a17SHarald Welte 
642e4e6a17SHarald Welte 	/* This only makes sense in the FORWARD and POSTROUTING chains */
652e4e6a17SHarald Welte 	if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
662e4e6a17SHarald Welte 	    (!!(nf_bridge->mask & BRNF_BRIDGED) ^
672e4e6a17SHarald Welte 	    !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
681d93a9cbSJan Engelhardt 		return false;
692e4e6a17SHarald Welte 
702e4e6a17SHarald Welte 	if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
712e4e6a17SHarald Welte 	    (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
722e4e6a17SHarald Welte 	    (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
732e4e6a17SHarald Welte 	    (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
741d93a9cbSJan Engelhardt 		return false;
752e4e6a17SHarald Welte 
762e4e6a17SHarald Welte 	if (!(info->bitmask & XT_PHYSDEV_OP_IN))
772e4e6a17SHarald Welte 		goto match_outdev;
782e4e6a17SHarald Welte 	indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
791d93a9cbSJan Engelhardt 	for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
802e4e6a17SHarald Welte 		ret |= (((const unsigned int *)indev)[i]
812e4e6a17SHarald Welte 			^ ((const unsigned int *)info->physindev)[i])
822e4e6a17SHarald Welte 			& ((const unsigned int *)info->in_mask)[i];
832e4e6a17SHarald Welte 	}
842e4e6a17SHarald Welte 
851d93a9cbSJan Engelhardt 	if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
861d93a9cbSJan Engelhardt 		return false;
872e4e6a17SHarald Welte 
882e4e6a17SHarald Welte match_outdev:
892e4e6a17SHarald Welte 	if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
901d93a9cbSJan Engelhardt 		return true;
912e4e6a17SHarald Welte 	outdev = nf_bridge->physoutdev ?
922e4e6a17SHarald Welte 		 nf_bridge->physoutdev->name : nulldevname;
931d93a9cbSJan Engelhardt 	for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
942e4e6a17SHarald Welte 		ret |= (((const unsigned int *)outdev)[i]
952e4e6a17SHarald Welte 			^ ((const unsigned int *)info->physoutdev)[i])
962e4e6a17SHarald Welte 			& ((const unsigned int *)info->out_mask)[i];
972e4e6a17SHarald Welte 	}
982e4e6a17SHarald Welte 
991d93a9cbSJan Engelhardt 	return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT);
1002e4e6a17SHarald Welte }
1012e4e6a17SHarald Welte 
1022e4e6a17SHarald Welte static int
1032e4e6a17SHarald Welte checkentry(const char *tablename,
1042e4e6a17SHarald Welte 		       const void *ip,
105c4986734SPatrick McHardy 		       const struct xt_match *match,
1062e4e6a17SHarald Welte 		       void *matchinfo,
1072e4e6a17SHarald Welte 		       unsigned int hook_mask)
1082e4e6a17SHarald Welte {
1092e4e6a17SHarald Welte 	const struct xt_physdev_info *info = matchinfo;
1102e4e6a17SHarald Welte 
1112e4e6a17SHarald Welte 	if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
1122e4e6a17SHarald Welte 	    info->bitmask & ~XT_PHYSDEV_OP_MASK)
1132e4e6a17SHarald Welte 		return 0;
1142bf540b7SPatrick McHardy 	if (info->bitmask & XT_PHYSDEV_OP_OUT &&
11510ea6ac8SPatrick McHardy 	    (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
11610ea6ac8SPatrick McHardy 	     info->invert & XT_PHYSDEV_OP_BRIDGED) &&
11710ea6ac8SPatrick McHardy 	    hook_mask & ((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
11810ea6ac8SPatrick McHardy 			 (1 << NF_IP_POST_ROUTING))) {
11910ea6ac8SPatrick McHardy 		printk(KERN_WARNING "physdev match: using --physdev-out in the "
12010ea6ac8SPatrick McHardy 		       "OUTPUT, FORWARD and POSTROUTING chains for non-bridged "
1212bf540b7SPatrick McHardy 		       "traffic is not supported anymore.\n");
1222bf540b7SPatrick McHardy 		if (hook_mask & (1 << NF_IP_LOCAL_OUT))
1232bf540b7SPatrick McHardy 			return 0;
12410ea6ac8SPatrick McHardy 	}
1252e4e6a17SHarald Welte 	return 1;
1262e4e6a17SHarald Welte }
1272e4e6a17SHarald Welte 
1284470bbc7SPatrick McHardy static struct xt_match xt_physdev_match[] = {
1294470bbc7SPatrick McHardy 	{
1302e4e6a17SHarald Welte 		.name		= "physdev",
131a45049c5SPablo Neira Ayuso 		.family		= AF_INET,
1324470bbc7SPatrick McHardy 		.checkentry	= checkentry,
1335d04bff0SPatrick McHardy 		.match		= match,
1345d04bff0SPatrick McHardy 		.matchsize	= sizeof(struct xt_physdev_info),
1352e4e6a17SHarald Welte 		.me		= THIS_MODULE,
1364470bbc7SPatrick McHardy 	},
1374470bbc7SPatrick McHardy 	{
1384470bbc7SPatrick McHardy 		.name		= "physdev",
1394470bbc7SPatrick McHardy 		.family		= AF_INET6,
1404470bbc7SPatrick McHardy 		.checkentry	= checkentry,
1414470bbc7SPatrick McHardy 		.match		= match,
1424470bbc7SPatrick McHardy 		.matchsize	= sizeof(struct xt_physdev_info),
1434470bbc7SPatrick McHardy 		.me		= THIS_MODULE,
1444470bbc7SPatrick McHardy 	},
1452e4e6a17SHarald Welte };
1462e4e6a17SHarald Welte 
14765b4b4e8SAndrew Morton static int __init xt_physdev_init(void)
1482e4e6a17SHarald Welte {
1494470bbc7SPatrick McHardy 	return xt_register_matches(xt_physdev_match,
1504470bbc7SPatrick McHardy 				   ARRAY_SIZE(xt_physdev_match));
1512e4e6a17SHarald Welte }
1522e4e6a17SHarald Welte 
15365b4b4e8SAndrew Morton static void __exit xt_physdev_fini(void)
1542e4e6a17SHarald Welte {
1554470bbc7SPatrick McHardy 	xt_unregister_matches(xt_physdev_match, ARRAY_SIZE(xt_physdev_match));
1562e4e6a17SHarald Welte }
1572e4e6a17SHarald Welte 
15865b4b4e8SAndrew Morton module_init(xt_physdev_init);
15965b4b4e8SAndrew Morton module_exit(xt_physdev_fini);
160