xt_physdev.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /* Kernel module to match the bridge port in and
  2. * out device for IP packets coming into contact with a bridge. */
  3. /* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10. #include <linux/module.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/netfilter_bridge.h>
  13. #include <linux/netfilter/xt_physdev.h>
  14. #include <linux/netfilter/x_tables.h>
  15. #include <net/netfilter/br_netfilter.h>
  16. MODULE_LICENSE("GPL");
  17. MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
  18. MODULE_DESCRIPTION("Xtables: Bridge physical device match");
  19. MODULE_ALIAS("ipt_physdev");
  20. MODULE_ALIAS("ip6t_physdev");
  21. static bool
  22. physdev_mt(const struct sk_buff *skb, struct xt_action_param *par)
  23. {
  24. static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
  25. const struct xt_physdev_info *info = par->matchinfo;
  26. unsigned long ret;
  27. const char *indev, *outdev;
  28. const struct nf_bridge_info *nf_bridge;
  29. /* Not a bridged IP packet or no info available yet:
  30. * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
  31. * the destination device will be a bridge. */
  32. if (!(nf_bridge = skb->nf_bridge)) {
  33. /* Return MATCH if the invert flags of the used options are on */
  34. if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
  35. !(info->invert & XT_PHYSDEV_OP_BRIDGED))
  36. return false;
  37. if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
  38. !(info->invert & XT_PHYSDEV_OP_ISIN))
  39. return false;
  40. if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
  41. !(info->invert & XT_PHYSDEV_OP_ISOUT))
  42. return false;
  43. if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
  44. !(info->invert & XT_PHYSDEV_OP_IN))
  45. return false;
  46. if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
  47. !(info->invert & XT_PHYSDEV_OP_OUT))
  48. return false;
  49. return true;
  50. }
  51. /* This only makes sense in the FORWARD and POSTROUTING chains */
  52. if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
  53. (!!(nf_bridge->mask & BRNF_BRIDGED) ^
  54. !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
  55. return false;
  56. if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
  57. (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
  58. (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
  59. (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
  60. return false;
  61. if (!(info->bitmask & XT_PHYSDEV_OP_IN))
  62. goto match_outdev;
  63. indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
  64. ret = ifname_compare_aligned(indev, info->physindev, info->in_mask);
  65. if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
  66. return false;
  67. match_outdev:
  68. if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
  69. return true;
  70. outdev = nf_bridge->physoutdev ?
  71. nf_bridge->physoutdev->name : nulldevname;
  72. ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask);
  73. return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
  74. }
  75. static int physdev_mt_check(const struct xt_mtchk_param *par)
  76. {
  77. const struct xt_physdev_info *info = par->matchinfo;
  78. br_netfilter_enable();
  79. if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
  80. info->bitmask & ~XT_PHYSDEV_OP_MASK)
  81. return -EINVAL;
  82. if (info->bitmask & XT_PHYSDEV_OP_OUT &&
  83. (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
  84. info->invert & XT_PHYSDEV_OP_BRIDGED) &&
  85. par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
  86. (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
  87. pr_info("using --physdev-out in the OUTPUT, FORWARD and "
  88. "POSTROUTING chains for non-bridged traffic is not "
  89. "supported anymore.\n");
  90. if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
  91. return -EINVAL;
  92. }
  93. return 0;
  94. }
  95. static struct xt_match physdev_mt_reg __read_mostly = {
  96. .name = "physdev",
  97. .revision = 0,
  98. .family = NFPROTO_UNSPEC,
  99. .checkentry = physdev_mt_check,
  100. .match = physdev_mt,
  101. .matchsize = sizeof(struct xt_physdev_info),
  102. .me = THIS_MODULE,
  103. };
  104. static int __init physdev_mt_init(void)
  105. {
  106. return xt_register_match(&physdev_mt_reg);
  107. }
  108. static void __exit physdev_mt_exit(void)
  109. {
  110. xt_unregister_match(&physdev_mt_reg);
  111. }
  112. module_init(physdev_mt_init);
  113. module_exit(physdev_mt_exit);