xref: /openbmc/linux/net/netfilter/xt_physdev.c (revision a45049c5)
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>
132e4e6a17SHarald Welte #include <linux/netfilter/xt_physdev.h>
142e4e6a17SHarald Welte #include <linux/netfilter/x_tables.h>
152e4e6a17SHarald Welte #include <linux/netfilter_bridge.h>
162e4e6a17SHarald Welte #define MATCH   1
172e4e6a17SHarald Welte #define NOMATCH 0
182e4e6a17SHarald Welte 
192e4e6a17SHarald Welte MODULE_LICENSE("GPL");
202e4e6a17SHarald Welte MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
212e4e6a17SHarald Welte MODULE_DESCRIPTION("iptables bridge physical device match module");
222e4e6a17SHarald Welte MODULE_ALIAS("ipt_physdev");
232e4e6a17SHarald Welte MODULE_ALIAS("ip6t_physdev");
242e4e6a17SHarald Welte 
252e4e6a17SHarald Welte static int
262e4e6a17SHarald Welte match(const struct sk_buff *skb,
272e4e6a17SHarald Welte       const struct net_device *in,
282e4e6a17SHarald Welte       const struct net_device *out,
29c4986734SPatrick McHardy       const struct xt_match *match,
302e4e6a17SHarald Welte       const void *matchinfo,
312e4e6a17SHarald Welte       int offset,
322e4e6a17SHarald Welte       unsigned int protoff,
332e4e6a17SHarald Welte       int *hotdrop)
342e4e6a17SHarald Welte {
352e4e6a17SHarald Welte 	int i;
362e4e6a17SHarald Welte 	static const char nulldevname[IFNAMSIZ];
372e4e6a17SHarald Welte 	const struct xt_physdev_info *info = matchinfo;
382e4e6a17SHarald Welte 	unsigned int ret;
392e4e6a17SHarald Welte 	const char *indev, *outdev;
402e4e6a17SHarald Welte 	struct nf_bridge_info *nf_bridge;
412e4e6a17SHarald Welte 
422e4e6a17SHarald Welte 	/* Not a bridged IP packet or no info available yet:
432e4e6a17SHarald Welte 	 * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
442e4e6a17SHarald Welte 	 * the destination device will be a bridge. */
452e4e6a17SHarald Welte 	if (!(nf_bridge = skb->nf_bridge)) {
462e4e6a17SHarald Welte 		/* Return MATCH if the invert flags of the used options are on */
472e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
482e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_BRIDGED))
492e4e6a17SHarald Welte 			return NOMATCH;
502e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
512e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_ISIN))
522e4e6a17SHarald Welte 			return NOMATCH;
532e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
542e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_ISOUT))
552e4e6a17SHarald Welte 			return NOMATCH;
562e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
572e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_IN))
582e4e6a17SHarald Welte 			return NOMATCH;
592e4e6a17SHarald Welte 		if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
602e4e6a17SHarald Welte 		    !(info->invert & XT_PHYSDEV_OP_OUT))
612e4e6a17SHarald Welte 			return NOMATCH;
622e4e6a17SHarald Welte 		return MATCH;
632e4e6a17SHarald Welte 	}
642e4e6a17SHarald Welte 
652e4e6a17SHarald Welte 	/* This only makes sense in the FORWARD and POSTROUTING chains */
662e4e6a17SHarald Welte 	if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
672e4e6a17SHarald Welte 	    (!!(nf_bridge->mask & BRNF_BRIDGED) ^
682e4e6a17SHarald Welte 	    !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
692e4e6a17SHarald Welte 		return NOMATCH;
702e4e6a17SHarald Welte 
712e4e6a17SHarald Welte 	if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
722e4e6a17SHarald Welte 	    (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
732e4e6a17SHarald Welte 	    (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
742e4e6a17SHarald Welte 	    (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
752e4e6a17SHarald Welte 		return NOMATCH;
762e4e6a17SHarald Welte 
772e4e6a17SHarald Welte 	if (!(info->bitmask & XT_PHYSDEV_OP_IN))
782e4e6a17SHarald Welte 		goto match_outdev;
792e4e6a17SHarald Welte 	indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
802e4e6a17SHarald Welte 	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
812e4e6a17SHarald Welte 		ret |= (((const unsigned int *)indev)[i]
822e4e6a17SHarald Welte 			^ ((const unsigned int *)info->physindev)[i])
832e4e6a17SHarald Welte 			& ((const unsigned int *)info->in_mask)[i];
842e4e6a17SHarald Welte 	}
852e4e6a17SHarald Welte 
862e4e6a17SHarald Welte 	if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN))
872e4e6a17SHarald Welte 		return NOMATCH;
882e4e6a17SHarald Welte 
892e4e6a17SHarald Welte match_outdev:
902e4e6a17SHarald Welte 	if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
912e4e6a17SHarald Welte 		return MATCH;
922e4e6a17SHarald Welte 	outdev = nf_bridge->physoutdev ?
932e4e6a17SHarald Welte 		 nf_bridge->physoutdev->name : nulldevname;
942e4e6a17SHarald Welte 	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
952e4e6a17SHarald Welte 		ret |= (((const unsigned int *)outdev)[i]
962e4e6a17SHarald Welte 			^ ((const unsigned int *)info->physoutdev)[i])
972e4e6a17SHarald Welte 			& ((const unsigned int *)info->out_mask)[i];
982e4e6a17SHarald Welte 	}
992e4e6a17SHarald Welte 
1002e4e6a17SHarald Welte 	return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT);
1012e4e6a17SHarald Welte }
1022e4e6a17SHarald Welte 
1032e4e6a17SHarald Welte static int
1042e4e6a17SHarald Welte checkentry(const char *tablename,
1052e4e6a17SHarald Welte 		       const void *ip,
106c4986734SPatrick McHardy 		       const struct xt_match *match,
1072e4e6a17SHarald Welte 		       void *matchinfo,
1082e4e6a17SHarald Welte 		       unsigned int matchsize,
1092e4e6a17SHarald Welte 		       unsigned int hook_mask)
1102e4e6a17SHarald Welte {
1112e4e6a17SHarald Welte 	const struct xt_physdev_info *info = matchinfo;
1122e4e6a17SHarald Welte 
1132e4e6a17SHarald Welte 	if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
1142e4e6a17SHarald Welte 	    info->bitmask & ~XT_PHYSDEV_OP_MASK)
1152e4e6a17SHarald Welte 		return 0;
1162e4e6a17SHarald Welte 	return 1;
1172e4e6a17SHarald Welte }
1182e4e6a17SHarald Welte 
1192e4e6a17SHarald Welte static struct xt_match physdev_match = {
1202e4e6a17SHarald Welte 	.name		= "physdev",
1215d04bff0SPatrick McHardy 	.match		= match,
1225d04bff0SPatrick McHardy 	.matchsize	= sizeof(struct xt_physdev_info),
1235d04bff0SPatrick McHardy 	.checkentry	= checkentry,
124a45049c5SPablo Neira Ayuso 	.family		= AF_INET,
1252e4e6a17SHarald Welte 	.me		= THIS_MODULE,
1262e4e6a17SHarald Welte };
1272e4e6a17SHarald Welte 
1282e4e6a17SHarald Welte static struct xt_match physdev6_match = {
1292e4e6a17SHarald Welte 	.name		= "physdev",
1305d04bff0SPatrick McHardy 	.match		= match,
1315d04bff0SPatrick McHardy 	.matchsize	= sizeof(struct xt_physdev_info),
1325d04bff0SPatrick McHardy 	.checkentry	= checkentry,
133a45049c5SPablo Neira Ayuso 	.family		= AF_INET6,
1342e4e6a17SHarald Welte 	.me		= THIS_MODULE,
1352e4e6a17SHarald Welte };
1362e4e6a17SHarald Welte 
1372e4e6a17SHarald Welte static int __init init(void)
1382e4e6a17SHarald Welte {
1392e4e6a17SHarald Welte 	int ret;
1402e4e6a17SHarald Welte 
141a45049c5SPablo Neira Ayuso 	ret = xt_register_match(&physdev_match);
1422e4e6a17SHarald Welte 	if (ret < 0)
1432e4e6a17SHarald Welte 		return ret;
1442e4e6a17SHarald Welte 
145a45049c5SPablo Neira Ayuso 	ret = xt_register_match(&physdev6_match);
1462e4e6a17SHarald Welte 	if (ret < 0)
147a45049c5SPablo Neira Ayuso 		xt_unregister_match(&physdev_match);
1482e4e6a17SHarald Welte 
1492e4e6a17SHarald Welte 	return ret;
1502e4e6a17SHarald Welte }
1512e4e6a17SHarald Welte 
1522e4e6a17SHarald Welte static void __exit fini(void)
1532e4e6a17SHarald Welte {
154a45049c5SPablo Neira Ayuso 	xt_unregister_match(&physdev_match);
155a45049c5SPablo Neira Ayuso 	xt_unregister_match(&physdev6_match);
1562e4e6a17SHarald Welte }
1572e4e6a17SHarald Welte 
1582e4e6a17SHarald Welte module_init(init);
1592e4e6a17SHarald Welte module_exit(fini);
160