xt_physdev.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. MODULE_LICENSE("GPL");
  16. MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
  17. MODULE_DESCRIPTION("Xtables: Bridge physical device match");
  18. MODULE_ALIAS("ipt_physdev");
  19. MODULE_ALIAS("ip6t_physdev");
  20. static bool
  21. physdev_mt(const struct sk_buff *skb, struct xt_action_param *par)
  22. {
  23. static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
  24. const struct xt_physdev_info *info = par->matchinfo;
  25. unsigned long ret;
  26. const char *indev, *outdev;
  27. const struct nf_bridge_info *nf_bridge;
  28. /* Not a bridged IP packet or no info available yet:
  29. * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
  30. * the destination device will be a bridge. */
  31. if (!(nf_bridge = skb->nf_bridge)) {
  32. /* Return MATCH if the invert flags of the used options are on */
  33. if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
  34. !(info->invert & XT_PHYSDEV_OP_BRIDGED))
  35. return false;
  36. if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
  37. !(info->invert & XT_PHYSDEV_OP_ISIN))
  38. return false;
  39. if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
  40. !(info->invert & XT_PHYSDEV_OP_ISOUT))
  41. return false;
  42. if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
  43. !(info->invert & XT_PHYSDEV_OP_IN))
  44. return false;
  45. if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
  46. !(info->invert & XT_PHYSDEV_OP_OUT))
  47. return false;
  48. return true;
  49. }
  50. /* This only makes sense in the FORWARD and POSTROUTING chains */
  51. if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
  52. (!!(nf_bridge->mask & BRNF_BRIDGED) ^
  53. !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
  54. return false;
  55. if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
  56. (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
  57. (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
  58. (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
  59. return false;
  60. if (!(info->bitmask & XT_PHYSDEV_OP_IN))
  61. goto match_outdev;
  62. indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
  63. ret = ifname_compare_aligned(indev, info->physindev, info->in_mask);
  64. if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
  65. return false;
  66. match_outdev:
  67. if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
  68. return true;
  69. outdev = nf_bridge->physoutdev ?
  70. nf_bridge->physoutdev->name : nulldevname;
  71. ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask);
  72. return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
  73. }
  74. static int physdev_mt_check(const struct xt_mtchk_param *par)
  75. {
  76. const struct xt_physdev_info *info = par->matchinfo;
  77. if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
  78. info->bitmask & ~XT_PHYSDEV_OP_MASK)
  79. return -EINVAL;
  80. if (info->bitmask & XT_PHYSDEV_OP_OUT &&
  81. (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
  82. info->invert & XT_PHYSDEV_OP_BRIDGED) &&
  83. par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
  84. (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
  85. pr_info("using --physdev-out in the OUTPUT, FORWARD and "
  86. "POSTROUTING chains for non-bridged traffic is not "
  87. "supported anymore.\n");
  88. if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
  89. return -EINVAL;
  90. }
  91. return 0;
  92. }
  93. static struct xt_match physdev_mt_reg __read_mostly = {
  94. .name = "physdev",
  95. .revision = 0,
  96. .family = NFPROTO_UNSPEC,
  97. .checkentry = physdev_mt_check,
  98. .match = physdev_mt,
  99. .matchsize = sizeof(struct xt_physdev_info),
  100. .me = THIS_MODULE,
  101. };
  102. static int __init physdev_mt_init(void)
  103. {
  104. return xt_register_match(&physdev_mt_reg);
  105. }
  106. static void __exit physdev_mt_exit(void)
  107. {
  108. xt_unregister_match(&physdev_mt_reg);
  109. }
  110. module_init(physdev_mt_init);
  111. module_exit(physdev_mt_exit);