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 172e4e6a17SHarald Welte MODULE_LICENSE("GPL"); 182e4e6a17SHarald Welte MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); 192ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: Bridge physical device match"); 202e4e6a17SHarald Welte MODULE_ALIAS("ipt_physdev"); 212e4e6a17SHarald Welte MODULE_ALIAS("ip6t_physdev"); 222e4e6a17SHarald Welte 23eacc17fbSEric Dumazet 241d93a9cbSJan Engelhardt static bool 25f7108a20SJan Engelhardt physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) 262e4e6a17SHarald Welte { 274f1c3b7eSEric Dumazet static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); 28f7108a20SJan Engelhardt const struct xt_physdev_info *info = par->matchinfo; 294f1c3b7eSEric Dumazet unsigned long ret; 302e4e6a17SHarald Welte const char *indev, *outdev; 31a47362a2SJan Engelhardt const struct nf_bridge_info *nf_bridge; 322e4e6a17SHarald Welte 332e4e6a17SHarald Welte /* Not a bridged IP packet or no info available yet: 342e4e6a17SHarald Welte * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if 352e4e6a17SHarald Welte * the destination device will be a bridge. */ 362e4e6a17SHarald Welte if (!(nf_bridge = skb->nf_bridge)) { 372e4e6a17SHarald Welte /* Return MATCH if the invert flags of the used options are on */ 382e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 392e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_BRIDGED)) 401d93a9cbSJan Engelhardt return false; 412e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN) && 422e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISIN)) 431d93a9cbSJan Engelhardt return false; 442e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) && 452e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISOUT)) 461d93a9cbSJan Engelhardt return false; 472e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_IN) && 482e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_IN)) 491d93a9cbSJan Engelhardt return false; 502e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_OUT) && 512e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_OUT)) 521d93a9cbSJan Engelhardt return false; 531d93a9cbSJan Engelhardt return true; 542e4e6a17SHarald Welte } 552e4e6a17SHarald Welte 562e4e6a17SHarald Welte /* This only makes sense in the FORWARD and POSTROUTING chains */ 572e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 582e4e6a17SHarald Welte (!!(nf_bridge->mask & BRNF_BRIDGED) ^ 592e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_BRIDGED))) 601d93a9cbSJan Engelhardt return false; 612e4e6a17SHarald Welte 622e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN && 632e4e6a17SHarald Welte (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) || 642e4e6a17SHarald Welte (info->bitmask & XT_PHYSDEV_OP_ISOUT && 652e4e6a17SHarald Welte (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT)))) 661d93a9cbSJan Engelhardt return false; 672e4e6a17SHarald Welte 682e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_IN)) 692e4e6a17SHarald Welte goto match_outdev; 702e4e6a17SHarald Welte indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; 71b8dfe498SEric Dumazet ret = ifname_compare_aligned(indev, info->physindev, info->in_mask); 722e4e6a17SHarald Welte 731d93a9cbSJan Engelhardt if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) 741d93a9cbSJan Engelhardt return false; 752e4e6a17SHarald Welte 762e4e6a17SHarald Welte match_outdev: 772e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_OUT)) 781d93a9cbSJan Engelhardt return true; 792e4e6a17SHarald Welte outdev = nf_bridge->physoutdev ? 802e4e6a17SHarald Welte nf_bridge->physoutdev->name : nulldevname; 81b8dfe498SEric Dumazet ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask); 82eacc17fbSEric Dumazet 834f1c3b7eSEric Dumazet return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); 842e4e6a17SHarald Welte } 852e4e6a17SHarald Welte 869b4fce7aSJan Engelhardt static bool physdev_mt_check(const struct xt_mtchk_param *par) 872e4e6a17SHarald Welte { 889b4fce7aSJan Engelhardt const struct xt_physdev_info *info = par->matchinfo; 892e4e6a17SHarald Welte 902e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || 912e4e6a17SHarald Welte info->bitmask & ~XT_PHYSDEV_OP_MASK) 92ccb79bdcSJan Engelhardt return false; 932bf540b7SPatrick McHardy if (info->bitmask & XT_PHYSDEV_OP_OUT && 9410ea6ac8SPatrick McHardy (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) || 9510ea6ac8SPatrick McHardy info->invert & XT_PHYSDEV_OP_BRIDGED) && 969b4fce7aSJan Engelhardt par->hook_mask & ((1 << NF_INET_LOCAL_OUT) | 979b4fce7aSJan Engelhardt (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) { 9810ea6ac8SPatrick McHardy printk(KERN_WARNING "physdev match: using --physdev-out in the " 9910ea6ac8SPatrick McHardy "OUTPUT, FORWARD and POSTROUTING chains for non-bridged " 1002bf540b7SPatrick McHardy "traffic is not supported anymore.\n"); 1019b4fce7aSJan Engelhardt if (par->hook_mask & (1 << NF_INET_LOCAL_OUT)) 102ccb79bdcSJan Engelhardt return false; 10310ea6ac8SPatrick McHardy } 104ccb79bdcSJan Engelhardt return true; 1052e4e6a17SHarald Welte } 1062e4e6a17SHarald Welte 107ab4f21e6SJan Engelhardt static struct xt_match physdev_mt_reg __read_mostly = { 1082e4e6a17SHarald Welte .name = "physdev", 109ab4f21e6SJan Engelhardt .revision = 0, 110ab4f21e6SJan Engelhardt .family = NFPROTO_UNSPEC, 111d3c5ee6dSJan Engelhardt .checkentry = physdev_mt_check, 112d3c5ee6dSJan Engelhardt .match = physdev_mt, 1135d04bff0SPatrick McHardy .matchsize = sizeof(struct xt_physdev_info), 1142e4e6a17SHarald Welte .me = THIS_MODULE, 1152e4e6a17SHarald Welte }; 1162e4e6a17SHarald Welte 117d3c5ee6dSJan Engelhardt static int __init physdev_mt_init(void) 1182e4e6a17SHarald Welte { 119ab4f21e6SJan Engelhardt return xt_register_match(&physdev_mt_reg); 1202e4e6a17SHarald Welte } 1212e4e6a17SHarald Welte 122d3c5ee6dSJan Engelhardt static void __exit physdev_mt_exit(void) 1232e4e6a17SHarald Welte { 124ab4f21e6SJan Engelhardt xt_unregister_match(&physdev_mt_reg); 1252e4e6a17SHarald Welte } 1262e4e6a17SHarald Welte 127d3c5ee6dSJan Engelhardt module_init(physdev_mt_init); 128d3c5ee6dSJan Engelhardt module_exit(physdev_mt_exit); 129