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, 292e4e6a17SHarald Welte const void *matchinfo, 302e4e6a17SHarald Welte int offset, 312e4e6a17SHarald Welte unsigned int protoff, 322e4e6a17SHarald Welte int *hotdrop) 332e4e6a17SHarald Welte { 342e4e6a17SHarald Welte int i; 352e4e6a17SHarald Welte static const char nulldevname[IFNAMSIZ]; 362e4e6a17SHarald Welte const struct xt_physdev_info *info = matchinfo; 372e4e6a17SHarald Welte unsigned int 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)) 482e4e6a17SHarald Welte return NOMATCH; 492e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN) && 502e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISIN)) 512e4e6a17SHarald Welte return NOMATCH; 522e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) && 532e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISOUT)) 542e4e6a17SHarald Welte return NOMATCH; 552e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_IN) && 562e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_IN)) 572e4e6a17SHarald Welte return NOMATCH; 582e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_OUT) && 592e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_OUT)) 602e4e6a17SHarald Welte return NOMATCH; 612e4e6a17SHarald Welte return MATCH; 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))) 682e4e6a17SHarald Welte return NOMATCH; 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)))) 742e4e6a17SHarald Welte return NOMATCH; 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; 792e4e6a17SHarald Welte for (i = 0, ret = 0; 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 852e4e6a17SHarald Welte if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN)) 862e4e6a17SHarald Welte return NOMATCH; 872e4e6a17SHarald Welte 882e4e6a17SHarald Welte match_outdev: 892e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_OUT)) 902e4e6a17SHarald Welte return MATCH; 912e4e6a17SHarald Welte outdev = nf_bridge->physoutdev ? 922e4e6a17SHarald Welte nf_bridge->physoutdev->name : nulldevname; 932e4e6a17SHarald Welte for (i = 0, ret = 0; 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 992e4e6a17SHarald Welte return (ret != 0) ^ !(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, 1052e4e6a17SHarald Welte void *matchinfo, 1062e4e6a17SHarald Welte unsigned int matchsize, 1072e4e6a17SHarald Welte unsigned int hook_mask) 1082e4e6a17SHarald Welte { 1092e4e6a17SHarald Welte const struct xt_physdev_info *info = matchinfo; 1102e4e6a17SHarald Welte 1112e4e6a17SHarald Welte if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info))) 1122e4e6a17SHarald Welte return 0; 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", 1212e4e6a17SHarald Welte .match = &match, 1222e4e6a17SHarald Welte .checkentry = &checkentry, 1232e4e6a17SHarald Welte .me = THIS_MODULE, 1242e4e6a17SHarald Welte }; 1252e4e6a17SHarald Welte 1262e4e6a17SHarald Welte static struct xt_match physdev6_match = { 1272e4e6a17SHarald Welte .name = "physdev", 1282e4e6a17SHarald Welte .match = &match, 1292e4e6a17SHarald Welte .checkentry = &checkentry, 1302e4e6a17SHarald Welte .me = THIS_MODULE, 1312e4e6a17SHarald Welte }; 1322e4e6a17SHarald Welte 1332e4e6a17SHarald Welte static int __init init(void) 1342e4e6a17SHarald Welte { 1352e4e6a17SHarald Welte int ret; 1362e4e6a17SHarald Welte 1372e4e6a17SHarald Welte ret = xt_register_match(AF_INET, &physdev_match); 1382e4e6a17SHarald Welte if (ret < 0) 1392e4e6a17SHarald Welte return ret; 1402e4e6a17SHarald Welte 1412e4e6a17SHarald Welte ret = xt_register_match(AF_INET6, &physdev6_match); 1422e4e6a17SHarald Welte if (ret < 0) 1432e4e6a17SHarald Welte xt_unregister_match(AF_INET, &physdev_match); 1442e4e6a17SHarald Welte 1452e4e6a17SHarald Welte return ret; 1462e4e6a17SHarald Welte } 1472e4e6a17SHarald Welte 1482e4e6a17SHarald Welte static void __exit fini(void) 1492e4e6a17SHarald Welte { 1502e4e6a17SHarald Welte xt_unregister_match(AF_INET, &physdev_match); 1512e4e6a17SHarald Welte xt_unregister_match(AF_INET6, &physdev6_match); 1522e4e6a17SHarald Welte } 1532e4e6a17SHarald Welte 1542e4e6a17SHarald Welte module_init(init); 1552e4e6a17SHarald Welte module_exit(fini); 156