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