xt_physdev.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. const struct xt_physdev_info *info = par->matchinfo;
  25. const struct net_device *physdev;
  26. unsigned long ret;
  27. const char *indev, *outdev;
  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 (!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. physdev = nf_bridge_get_physoutdev(skb);
  51. outdev = physdev ? physdev->name : NULL;
  52. /* This only makes sense in the FORWARD and POSTROUTING chains */
  53. if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
  54. (!!outdev ^ !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
  55. return false;
  56. physdev = nf_bridge_get_physindev(skb);
  57. indev = physdev ? physdev->name : NULL;
  58. if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
  59. (!indev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
  60. (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
  61. (!outdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
  62. return false;
  63. if (!(info->bitmask & XT_PHYSDEV_OP_IN))
  64. goto match_outdev;
  65. if (indev) {
  66. ret = ifname_compare_aligned(indev, info->physindev,
  67. info->in_mask);
  68. if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
  69. return false;
  70. }
  71. match_outdev:
  72. if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
  73. return true;
  74. if (!outdev)
  75. return false;
  76. ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask);
  77. return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
  78. }
  79. static int physdev_mt_check(const struct xt_mtchk_param *par)
  80. {
  81. const struct xt_physdev_info *info = par->matchinfo;
  82. static bool brnf_probed __read_mostly;
  83. if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
  84. info->bitmask & ~XT_PHYSDEV_OP_MASK)
  85. return -EINVAL;
  86. if (info->bitmask & XT_PHYSDEV_OP_OUT &&
  87. (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
  88. info->invert & XT_PHYSDEV_OP_BRIDGED) &&
  89. par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
  90. (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
  91. pr_info("using --physdev-out in the OUTPUT, FORWARD and "
  92. "POSTROUTING chains for non-bridged traffic is not "
  93. "supported anymore.\n");
  94. if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
  95. return -EINVAL;
  96. }
  97. if (!brnf_probed) {
  98. brnf_probed = true;
  99. request_module("br_netfilter");
  100. }
  101. return 0;
  102. }
  103. static struct xt_match physdev_mt_reg __read_mostly = {
  104. .name = "physdev",
  105. .revision = 0,
  106. .family = NFPROTO_UNSPEC,
  107. .checkentry = physdev_mt_check,
  108. .match = physdev_mt,
  109. .matchsize = sizeof(struct xt_physdev_info),
  110. .me = THIS_MODULE,
  111. };
  112. static int __init physdev_mt_init(void)
  113. {
  114. return xt_register_match(&physdev_mt_reg);
  115. }
  116. static void __exit physdev_mt_exit(void)
  117. {
  118. xt_unregister_match(&physdev_mt_reg);
  119. }
  120. module_init(physdev_mt_init);
  121. module_exit(physdev_mt_exit);