xt_physdev.c 3.9 KB

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