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