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 { 28f7108a20SJan Engelhardt const struct xt_physdev_info *info = par->matchinfo; 29a99074aeSFlorian Westphal const struct net_device *physdev; 304f1c3b7eSEric Dumazet unsigned long ret; 312e4e6a17SHarald Welte const char *indev, *outdev; 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. */ 36c4b0e771SFlorian Westphal if (!nf_bridge_info_exists(skb)) { 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 56a99074aeSFlorian Westphal physdev = nf_bridge_get_physoutdev(skb); 57a99074aeSFlorian Westphal outdev = physdev ? physdev->name : NULL; 58a99074aeSFlorian Westphal 592e4e6a17SHarald Welte /* This only makes sense in the FORWARD and POSTROUTING chains */ 602e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) && 61a99074aeSFlorian Westphal (!!outdev ^ !(info->invert & XT_PHYSDEV_OP_BRIDGED))) 621d93a9cbSJan Engelhardt return false; 632e4e6a17SHarald Welte 64a99074aeSFlorian Westphal physdev = nf_bridge_get_physindev(skb); 65a99074aeSFlorian Westphal indev = physdev ? physdev->name : NULL; 66a99074aeSFlorian Westphal 672e4e6a17SHarald Welte if ((info->bitmask & XT_PHYSDEV_OP_ISIN && 68a99074aeSFlorian Westphal (!indev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) || 692e4e6a17SHarald Welte (info->bitmask & XT_PHYSDEV_OP_ISOUT && 70a99074aeSFlorian Westphal (!outdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT)))) 711d93a9cbSJan Engelhardt return false; 722e4e6a17SHarald Welte 732e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_IN)) 742e4e6a17SHarald Welte goto match_outdev; 75a99074aeSFlorian Westphal 76a99074aeSFlorian Westphal if (indev) { 77a99074aeSFlorian Westphal ret = ifname_compare_aligned(indev, info->physindev, 78a99074aeSFlorian Westphal info->in_mask); 792e4e6a17SHarald Welte 801d93a9cbSJan Engelhardt if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) 811d93a9cbSJan Engelhardt return false; 82a99074aeSFlorian Westphal } 832e4e6a17SHarald Welte 842e4e6a17SHarald Welte match_outdev: 852e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_OUT)) 861d93a9cbSJan Engelhardt return true; 87a99074aeSFlorian Westphal 88a99074aeSFlorian Westphal if (!outdev) 89a99074aeSFlorian Westphal return false; 90a99074aeSFlorian Westphal 91b8dfe498SEric Dumazet ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask); 92eacc17fbSEric Dumazet 934f1c3b7eSEric Dumazet return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); 942e4e6a17SHarald Welte } 952e4e6a17SHarald Welte 96b0f38452SJan Engelhardt static int physdev_mt_check(const struct xt_mtchk_param *par) 972e4e6a17SHarald Welte { 989b4fce7aSJan Engelhardt const struct xt_physdev_info *info = par->matchinfo; 992e4e6a17SHarald Welte 1004b7fd5d9SPablo Neira Ayuso br_netfilter_enable(); 1014b7fd5d9SPablo Neira Ayuso 1022e4e6a17SHarald Welte if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || 1032e4e6a17SHarald Welte info->bitmask & ~XT_PHYSDEV_OP_MASK) 104bd414ee6SJan Engelhardt return -EINVAL; 10547c74456SHangbin Liu if (info->bitmask & (XT_PHYSDEV_OP_OUT | XT_PHYSDEV_OP_ISOUT) && 10610ea6ac8SPatrick McHardy (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) || 10710ea6ac8SPatrick McHardy info->invert & XT_PHYSDEV_OP_BRIDGED) && 1089b4fce7aSJan Engelhardt par->hook_mask & ((1 << NF_INET_LOCAL_OUT) | 1099b4fce7aSJan Engelhardt (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) { 110b2606644SFlorian Westphal pr_info_ratelimited("--physdev-out and --physdev-is-out only supported in the FORWARD and POSTROUTING chains with bridged traffic\n"); 1119b4fce7aSJan Engelhardt if (par->hook_mask & (1 << NF_INET_LOCAL_OUT)) 112bd414ee6SJan Engelhardt return -EINVAL; 11310ea6ac8SPatrick McHardy } 114bd414ee6SJan Engelhardt return 0; 1152e4e6a17SHarald Welte } 1162e4e6a17SHarald Welte 117ab4f21e6SJan Engelhardt static struct xt_match physdev_mt_reg __read_mostly = { 1182e4e6a17SHarald Welte .name = "physdev", 119ab4f21e6SJan Engelhardt .revision = 0, 120ab4f21e6SJan Engelhardt .family = NFPROTO_UNSPEC, 121d3c5ee6dSJan Engelhardt .checkentry = physdev_mt_check, 122d3c5ee6dSJan Engelhardt .match = physdev_mt, 1235d04bff0SPatrick McHardy .matchsize = sizeof(struct xt_physdev_info), 1242e4e6a17SHarald Welte .me = THIS_MODULE, 1252e4e6a17SHarald Welte }; 1262e4e6a17SHarald Welte 127d3c5ee6dSJan Engelhardt static int __init physdev_mt_init(void) 1282e4e6a17SHarald Welte { 129ab4f21e6SJan Engelhardt return xt_register_match(&physdev_mt_reg); 1302e4e6a17SHarald Welte } 1312e4e6a17SHarald Welte 132d3c5ee6dSJan Engelhardt static void __exit physdev_mt_exit(void) 1332e4e6a17SHarald Welte { 134ab4f21e6SJan Engelhardt xt_unregister_match(&physdev_mt_reg); 1352e4e6a17SHarald Welte } 1362e4e6a17SHarald Welte 137d3c5ee6dSJan Engelhardt module_init(physdev_mt_init); 138d3c5ee6dSJan Engelhardt module_exit(physdev_mt_exit); 139