xt_ecn.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Xtables module for matching the value of the IPv4/IPv6 and TCP ECN bits
  3. *
  4. * (C) 2002 by Harald Welte <laforge@gnumonks.org>
  5. * (C) 2011 Patrick McHardy <kaber@trash.net>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12. #include <linux/in.h>
  13. #include <linux/ip.h>
  14. #include <net/ip.h>
  15. #include <linux/module.h>
  16. #include <linux/skbuff.h>
  17. #include <linux/tcp.h>
  18. #include <linux/netfilter/x_tables.h>
  19. #include <linux/netfilter/xt_ecn.h>
  20. #include <linux/netfilter_ipv4/ip_tables.h>
  21. #include <linux/netfilter_ipv6/ip6_tables.h>
  22. MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  23. MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match");
  24. MODULE_LICENSE("GPL");
  25. MODULE_ALIAS("ipt_ecn");
  26. MODULE_ALIAS("ip6t_ecn");
  27. static bool match_tcp(const struct sk_buff *skb, struct xt_action_param *par)
  28. {
  29. const struct xt_ecn_info *einfo = par->matchinfo;
  30. struct tcphdr _tcph;
  31. const struct tcphdr *th;
  32. /* In practice, TCP match does this, so can't fail. But let's
  33. * be good citizens.
  34. */
  35. th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
  36. if (th == NULL)
  37. return false;
  38. if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
  39. if (einfo->invert & XT_ECN_OP_MATCH_ECE) {
  40. if (th->ece == 1)
  41. return false;
  42. } else {
  43. if (th->ece == 0)
  44. return false;
  45. }
  46. }
  47. if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
  48. if (einfo->invert & XT_ECN_OP_MATCH_CWR) {
  49. if (th->cwr == 1)
  50. return false;
  51. } else {
  52. if (th->cwr == 0)
  53. return false;
  54. }
  55. }
  56. return true;
  57. }
  58. static inline bool match_ip(const struct sk_buff *skb,
  59. const struct xt_ecn_info *einfo)
  60. {
  61. return ((ip_hdr(skb)->tos & XT_ECN_IP_MASK) == einfo->ip_ect) ^
  62. !!(einfo->invert & XT_ECN_OP_MATCH_IP);
  63. }
  64. static bool ecn_mt4(const struct sk_buff *skb, struct xt_action_param *par)
  65. {
  66. const struct xt_ecn_info *info = par->matchinfo;
  67. if (info->operation & XT_ECN_OP_MATCH_IP && !match_ip(skb, info))
  68. return false;
  69. if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  70. !match_tcp(skb, par))
  71. return false;
  72. return true;
  73. }
  74. static int ecn_mt_check4(const struct xt_mtchk_param *par)
  75. {
  76. const struct xt_ecn_info *info = par->matchinfo;
  77. const struct ipt_ip *ip = par->entryinfo;
  78. if (info->operation & XT_ECN_OP_MATCH_MASK)
  79. return -EINVAL;
  80. if (info->invert & XT_ECN_OP_MATCH_MASK)
  81. return -EINVAL;
  82. if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  83. (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
  84. pr_info("cannot match TCP bits in rule for non-tcp packets\n");
  85. return -EINVAL;
  86. }
  87. return 0;
  88. }
  89. static inline bool match_ipv6(const struct sk_buff *skb,
  90. const struct xt_ecn_info *einfo)
  91. {
  92. return (((ipv6_hdr(skb)->flow_lbl[0] >> 4) & XT_ECN_IP_MASK) ==
  93. einfo->ip_ect) ^
  94. !!(einfo->invert & XT_ECN_OP_MATCH_IP);
  95. }
  96. static bool ecn_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  97. {
  98. const struct xt_ecn_info *info = par->matchinfo;
  99. if (info->operation & XT_ECN_OP_MATCH_IP && !match_ipv6(skb, info))
  100. return false;
  101. if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  102. !match_tcp(skb, par))
  103. return false;
  104. return true;
  105. }
  106. static int ecn_mt_check6(const struct xt_mtchk_param *par)
  107. {
  108. const struct xt_ecn_info *info = par->matchinfo;
  109. const struct ip6t_ip6 *ip = par->entryinfo;
  110. if (info->operation & XT_ECN_OP_MATCH_MASK)
  111. return -EINVAL;
  112. if (info->invert & XT_ECN_OP_MATCH_MASK)
  113. return -EINVAL;
  114. if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  115. (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) {
  116. pr_info("cannot match TCP bits in rule for non-tcp packets\n");
  117. return -EINVAL;
  118. }
  119. return 0;
  120. }
  121. static struct xt_match ecn_mt_reg[] __read_mostly = {
  122. {
  123. .name = "ecn",
  124. .family = NFPROTO_IPV4,
  125. .match = ecn_mt4,
  126. .matchsize = sizeof(struct xt_ecn_info),
  127. .checkentry = ecn_mt_check4,
  128. .me = THIS_MODULE,
  129. },
  130. {
  131. .name = "ecn",
  132. .family = NFPROTO_IPV6,
  133. .match = ecn_mt6,
  134. .matchsize = sizeof(struct xt_ecn_info),
  135. .checkentry = ecn_mt_check6,
  136. .me = THIS_MODULE,
  137. },
  138. };
  139. static int __init ecn_mt_init(void)
  140. {
  141. return xt_register_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
  142. }
  143. static void __exit ecn_mt_exit(void)
  144. {
  145. xt_unregister_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
  146. }
  147. module_init(ecn_mt_init);
  148. module_exit(ecn_mt_exit);