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 */ 108bee4badSJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 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> 164b7fd5d9SPablo Neira Ayuso #include <net/netfilter/br_netfilter.h> 172e4e6a17SHarald Welte 182e4e6a17SHarald Welte MODULE_LICENSE("GPL"); 192e4e6a17SHarald Welte MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); 202ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: Bridge physical device match"); 212e4e6a17SHarald Welte MODULE_ALIAS("ipt_physdev"); 222e4e6a17SHarald Welte MODULE_ALIAS("ip6t_physdev"); 232e4e6a17SHarald Welte 24eacc17fbSEric Dumazet 251d93a9cbSJan Engelhardt static bool 2662fc8051SJan Engelhardt physdev_mt(const struct sk_buff *skb, struct xt_action_param *par) 272e4e6a17SHarald Welte { 284f1c3b7eSEric Dumazet static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); 29f7108a20SJan Engelhardt const struct xt_physdev_info *info = par->matchinfo; 304f1c3b7eSEric Dumazet unsigned long ret; 312e4e6a17SHarald Welte const char *indev, *outdev; 32a47362a2SJan Engelhardt const struct nf_bridge_info *nf_bridge; 332e4e6a17SHarald Welte 342e4e6a17SHarald Welte /* Not a bridged IP packet or no info available yet: 352e4e6a17SHarald Welte * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if 362e4e6a17SHarald Welte * the destination device will be a bridge. */ 372e4e6a17SHarald Welte if (!(nf_bridge = skb->nf_bridge)) { 382e4e6a17SHarald Welte /* Return MATCH if the invert flags of the used options are on */ 392e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 402e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_BRIDGED)) 411d93a9cbSJan Engelhardt return false; 422e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN) && 432e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISIN)) 441d93a9cbSJan Engelhardt return false; 452e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) && 462e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_ISOUT)) 471d93a9cbSJan Engelhardt return false; 482e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_IN) && 492e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_IN)) 501d93a9cbSJan Engelhardt return false; 512e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_OUT) && 522e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_OUT)) 531d93a9cbSJan Engelhardt return false; 541d93a9cbSJan Engelhardt return true; 552e4e6a17SHarald Welte } 562e4e6a17SHarald Welte 572e4e6a17SHarald Welte /* This only makes sense in the FORWARD and POSTROUTING chains */ 582e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 592e4e6a17SHarald Welte (!!(nf_bridge->mask & BRNF_BRIDGED) ^ 602e4e6a17SHarald Welte !(info->invert & XT_PHYSDEV_OP_BRIDGED))) 611d93a9cbSJan Engelhardt return false; 622e4e6a17SHarald Welte 632e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN && 642e4e6a17SHarald Welte (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) || 652e4e6a17SHarald Welte (info->bitmask & XT_PHYSDEV_OP_ISOUT && 662e4e6a17SHarald Welte (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT)))) 671d93a9cbSJan Engelhardt return false; 682e4e6a17SHarald Welte 692e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_IN)) 702e4e6a17SHarald Welte goto match_outdev; 712e4e6a17SHarald Welte indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; 72b8dfe498SEric Dumazet ret = ifname_compare_aligned(indev, info->physindev, info->in_mask); 732e4e6a17SHarald Welte 741d93a9cbSJan Engelhardt if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) 751d93a9cbSJan Engelhardt return false; 762e4e6a17SHarald Welte 772e4e6a17SHarald Welte match_outdev: 782e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_OUT)) 791d93a9cbSJan Engelhardt return true; 802e4e6a17SHarald Welte outdev = nf_bridge->physoutdev ? 812e4e6a17SHarald Welte nf_bridge->physoutdev->name : nulldevname; 82b8dfe498SEric Dumazet ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask); 83eacc17fbSEric Dumazet 844f1c3b7eSEric Dumazet return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); 852e4e6a17SHarald Welte } 862e4e6a17SHarald Welte 87b0f38452SJan Engelhardt static int physdev_mt_check(const struct xt_mtchk_param *par) 882e4e6a17SHarald Welte { 899b4fce7aSJan Engelhardt const struct xt_physdev_info *info = par->matchinfo; 902e4e6a17SHarald Welte 914b7fd5d9SPablo Neira Ayuso br_netfilter_enable(); 924b7fd5d9SPablo Neira Ayuso 932e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || 942e4e6a17SHarald Welte info->bitmask & ~XT_PHYSDEV_OP_MASK) 95bd414ee6SJan Engelhardt return -EINVAL; 962bf540b7SPatrick McHardy if (info->bitmask & XT_PHYSDEV_OP_OUT && 9710ea6ac8SPatrick McHardy (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) || 9810ea6ac8SPatrick McHardy info->invert & XT_PHYSDEV_OP_BRIDGED) && 999b4fce7aSJan Engelhardt par->hook_mask & ((1 << NF_INET_LOCAL_OUT) | 1009b4fce7aSJan Engelhardt (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) { 1018bee4badSJan Engelhardt pr_info("using --physdev-out in the OUTPUT, FORWARD and " 1028bee4badSJan Engelhardt "POSTROUTING chains for non-bridged traffic is not " 1038bee4badSJan Engelhardt "supported anymore.\n"); 1049b4fce7aSJan Engelhardt if (par->hook_mask & (1 << NF_INET_LOCAL_OUT)) 105bd414ee6SJan Engelhardt return -EINVAL; 10610ea6ac8SPatrick McHardy } 107bd414ee6SJan Engelhardt return 0; 1082e4e6a17SHarald Welte } 1092e4e6a17SHarald Welte 110ab4f21e6SJan Engelhardt static struct xt_match physdev_mt_reg __read_mostly = { 1112e4e6a17SHarald Welte .name = "physdev", 112ab4f21e6SJan Engelhardt .revision = 0, 113ab4f21e6SJan Engelhardt .family = NFPROTO_UNSPEC, 114d3c5ee6dSJan Engelhardt .checkentry = physdev_mt_check, 115d3c5ee6dSJan Engelhardt .match = physdev_mt, 1165d04bff0SPatrick McHardy .matchsize = sizeof(struct xt_physdev_info), 1172e4e6a17SHarald Welte .me = THIS_MODULE, 1182e4e6a17SHarald Welte }; 1192e4e6a17SHarald Welte 120d3c5ee6dSJan Engelhardt static int __init physdev_mt_init(void) 1212e4e6a17SHarald Welte { 122ab4f21e6SJan Engelhardt return xt_register_match(&physdev_mt_reg); 1232e4e6a17SHarald Welte } 1242e4e6a17SHarald Welte 125d3c5ee6dSJan Engelhardt static void __exit physdev_mt_exit(void) 1262e4e6a17SHarald Welte { 127ab4f21e6SJan Engelhardt xt_unregister_match(&physdev_mt_reg); 1282e4e6a17SHarald Welte } 1292e4e6a17SHarald Welte 130d3c5ee6dSJan Engelhardt module_init(physdev_mt_init); 131d3c5ee6dSJan Engelhardt module_exit(physdev_mt_exit); 132