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 #define MATCH 1 182e4e6a17SHarald Welte #define NOMATCH 0 192e4e6a17SHarald Welte 202e4e6a17SHarald Welte MODULE_LICENSE("GPL"); 212e4e6a17SHarald Welte MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); 222e4e6a17SHarald Welte MODULE_DESCRIPTION("iptables bridge physical device match module"); 232e4e6a17SHarald Welte MODULE_ALIAS("ipt_physdev"); 242e4e6a17SHarald Welte MODULE_ALIAS("ip6t_physdev"); 252e4e6a17SHarald Welte 262e4e6a17SHarald Welte static int 272e4e6a17SHarald Welte match(const struct sk_buff *skb, 282e4e6a17SHarald Welte const struct net_device *in, 292e4e6a17SHarald Welte const struct net_device *out, 30c4986734SPatrick McHardy const struct xt_match *match, 312e4e6a17SHarald Welte const void *matchinfo, 322e4e6a17SHarald Welte int offset, 332e4e6a17SHarald Welte unsigned int protoff, 342e4e6a17SHarald Welte int *hotdrop) 352e4e6a17SHarald Welte { 362e4e6a17SHarald Welte int i; 372e4e6a17SHarald Welte static const char nulldevname[IFNAMSIZ]; 382e4e6a17SHarald Welte const struct xt_physdev_info *info = matchinfo; 392e4e6a17SHarald Welte unsigned int ret; 402e4e6a17SHarald Welte const char *indev, *outdev; 412e4e6a17SHarald Welte struct nf_bridge_info *nf_bridge; 422e4e6a17SHarald Welte 432e4e6a17SHarald Welte /* Not a bridged IP packet or no info available yet: 442e4e6a17SHarald Welte * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if 452e4e6a17SHarald Welte * the destination device will be a bridge. */ 462e4e6a17SHarald Welte if (!(nf_bridge = skb->nf_bridge)) { 472e4e6a17SHarald Welte /* Return MATCH if the invert flags of the used options are on */ 482e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 492e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_BRIDGED)) 502e4e6a17SHarald Welte return NOMATCH; 512e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN) && 522e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISIN)) 532e4e6a17SHarald Welte return NOMATCH; 542e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) && 552e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISOUT)) 562e4e6a17SHarald Welte return NOMATCH; 572e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_IN) && 582e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_IN)) 592e4e6a17SHarald Welte return NOMATCH; 602e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_OUT) && 612e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_OUT)) 622e4e6a17SHarald Welte return NOMATCH; 632e4e6a17SHarald Welte return MATCH; 642e4e6a17SHarald Welte } 652e4e6a17SHarald Welte 662e4e6a17SHarald Welte /* This only makes sense in the FORWARD and POSTROUTING chains */ 672e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 682e4e6a17SHarald Welte (!!(nf_bridge->mask & BRNF_BRIDGED) ^ 692e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_BRIDGED))) 702e4e6a17SHarald Welte return NOMATCH; 712e4e6a17SHarald Welte 722e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN && 732e4e6a17SHarald Welte (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) || 742e4e6a17SHarald Welte (info->bitmask & XT_PHYSDEV_OP_ISOUT && 752e4e6a17SHarald Welte (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT)))) 762e4e6a17SHarald Welte return NOMATCH; 772e4e6a17SHarald Welte 782e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_IN)) 792e4e6a17SHarald Welte goto match_outdev; 802e4e6a17SHarald Welte indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; 812e4e6a17SHarald Welte for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) { 822e4e6a17SHarald Welte ret |= (((const unsigned int *)indev)[i] 832e4e6a17SHarald Welte ^ ((const unsigned int *)info->physindev)[i]) 842e4e6a17SHarald Welte & ((const unsigned int *)info->in_mask)[i]; 852e4e6a17SHarald Welte } 862e4e6a17SHarald Welte 872e4e6a17SHarald Welte if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN)) 882e4e6a17SHarald Welte return NOMATCH; 892e4e6a17SHarald Welte 902e4e6a17SHarald Welte match_outdev: 912e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_OUT)) 922e4e6a17SHarald Welte return MATCH; 932e4e6a17SHarald Welte outdev = nf_bridge->physoutdev ? 942e4e6a17SHarald Welte nf_bridge->physoutdev->name : nulldevname; 952e4e6a17SHarald Welte for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) { 962e4e6a17SHarald Welte ret |= (((const unsigned int *)outdev)[i] 972e4e6a17SHarald Welte ^ ((const unsigned int *)info->physoutdev)[i]) 982e4e6a17SHarald Welte & ((const unsigned int *)info->out_mask)[i]; 992e4e6a17SHarald Welte } 1002e4e6a17SHarald Welte 1012e4e6a17SHarald Welte return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT); 1022e4e6a17SHarald Welte } 1032e4e6a17SHarald Welte 1042e4e6a17SHarald Welte static int 1052e4e6a17SHarald Welte checkentry(const char *tablename, 1062e4e6a17SHarald Welte const void *ip, 107c4986734SPatrick McHardy const struct xt_match *match, 1082e4e6a17SHarald Welte void *matchinfo, 1092e4e6a17SHarald Welte unsigned int matchsize, 1102e4e6a17SHarald Welte unsigned int hook_mask) 1112e4e6a17SHarald Welte { 1122e4e6a17SHarald Welte const struct xt_physdev_info *info = matchinfo; 1132e4e6a17SHarald Welte 1142e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || 1152e4e6a17SHarald Welte info->bitmask & ~XT_PHYSDEV_OP_MASK) 1162e4e6a17SHarald Welte return 0; 11710ea6ac8SPatrick McHardy if (brnf_deferred_hooks == 0 && 11810ea6ac8SPatrick McHardy info->bitmask & XT_PHYSDEV_OP_OUT && 11910ea6ac8SPatrick McHardy (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) || 12010ea6ac8SPatrick McHardy info->invert & XT_PHYSDEV_OP_BRIDGED) && 12110ea6ac8SPatrick McHardy hook_mask & ((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | 12210ea6ac8SPatrick McHardy (1 << NF_IP_POST_ROUTING))) { 12310ea6ac8SPatrick McHardy printk(KERN_WARNING "physdev match: using --physdev-out in the " 12410ea6ac8SPatrick McHardy "OUTPUT, FORWARD and POSTROUTING chains for non-bridged " 12510ea6ac8SPatrick McHardy "traffic is deprecated and breaks other things, it will " 12610ea6ac8SPatrick McHardy "be removed in January 2007. See Documentation/" 12710ea6ac8SPatrick McHardy "feature-removal-schedule.txt for details. This doesn't " 12810ea6ac8SPatrick McHardy "affect you in case you're using it for purely bridged " 12910ea6ac8SPatrick McHardy "traffic.\n"); 13010ea6ac8SPatrick McHardy brnf_deferred_hooks = 1; 13110ea6ac8SPatrick McHardy } 1322e4e6a17SHarald Welte return 1; 1332e4e6a17SHarald Welte } 1342e4e6a17SHarald Welte 1352e4e6a17SHarald Welte static struct xt_match physdev_match = { 1362e4e6a17SHarald Welte .name = "physdev", 1375d04bff0SPatrick McHardy .match = match, 1385d04bff0SPatrick McHardy .matchsize = sizeof(struct xt_physdev_info), 1395d04bff0SPatrick McHardy .checkentry = checkentry, 140a45049c5SPablo Neira Ayuso .family = AF_INET, 1412e4e6a17SHarald Welte .me = THIS_MODULE, 1422e4e6a17SHarald Welte }; 1432e4e6a17SHarald Welte 1442e4e6a17SHarald Welte static struct xt_match physdev6_match = { 1452e4e6a17SHarald Welte .name = "physdev", 1465d04bff0SPatrick McHardy .match = match, 1475d04bff0SPatrick McHardy .matchsize = sizeof(struct xt_physdev_info), 1485d04bff0SPatrick McHardy .checkentry = checkentry, 149a45049c5SPablo Neira Ayuso .family = AF_INET6, 1502e4e6a17SHarald Welte .me = THIS_MODULE, 1512e4e6a17SHarald Welte }; 1522e4e6a17SHarald Welte 15365b4b4e8SAndrew Morton static int __init xt_physdev_init(void) 1542e4e6a17SHarald Welte { 1552e4e6a17SHarald Welte int ret; 1562e4e6a17SHarald Welte 157a45049c5SPablo Neira Ayuso ret = xt_register_match(&physdev_match); 1582e4e6a17SHarald Welte if (ret < 0) 1592e4e6a17SHarald Welte return ret; 1602e4e6a17SHarald Welte 161a45049c5SPablo Neira Ayuso ret = xt_register_match(&physdev6_match); 1622e4e6a17SHarald Welte if (ret < 0) 163a45049c5SPablo Neira Ayuso xt_unregister_match(&physdev_match); 1642e4e6a17SHarald Welte 1652e4e6a17SHarald Welte return ret; 1662e4e6a17SHarald Welte } 1672e4e6a17SHarald Welte 16865b4b4e8SAndrew Morton static void __exit xt_physdev_fini(void) 1692e4e6a17SHarald Welte { 170a45049c5SPablo Neira Ayuso xt_unregister_match(&physdev_match); 171a45049c5SPablo Neira Ayuso xt_unregister_match(&physdev6_match); 1722e4e6a17SHarald Welte } 1732e4e6a17SHarald Welte 17465b4b4e8SAndrew Morton module_init(xt_physdev_init); 17565b4b4e8SAndrew Morton module_exit(xt_physdev_fini); 176