xt_connbytes.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* Kernel module to match connection tracking byte counter.
  2. * GPL (C) 2002 Martin Devera (devik@cdi.cz).
  3. */
  4. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  5. #include <linux/module.h>
  6. #include <linux/bitops.h>
  7. #include <linux/skbuff.h>
  8. #include <linux/math64.h>
  9. #include <linux/netfilter/x_tables.h>
  10. #include <linux/netfilter/xt_connbytes.h>
  11. #include <net/netfilter/nf_conntrack.h>
  12. #include <net/netfilter/nf_conntrack_acct.h>
  13. MODULE_LICENSE("GPL");
  14. MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  15. MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
  16. MODULE_ALIAS("ipt_connbytes");
  17. MODULE_ALIAS("ip6t_connbytes");
  18. static bool
  19. connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
  20. {
  21. const struct xt_connbytes_info *sinfo = par->matchinfo;
  22. const struct nf_conn *ct;
  23. enum ip_conntrack_info ctinfo;
  24. u_int64_t what = 0; /* initialize to make gcc happy */
  25. u_int64_t bytes = 0;
  26. u_int64_t pkts = 0;
  27. const struct nf_conn_acct *acct;
  28. const struct nf_conn_counter *counters;
  29. ct = nf_ct_get(skb, &ctinfo);
  30. if (!ct)
  31. return false;
  32. acct = nf_conn_acct_find(ct);
  33. if (!acct)
  34. return false;
  35. counters = acct->counter;
  36. switch (sinfo->what) {
  37. case XT_CONNBYTES_PKTS:
  38. switch (sinfo->direction) {
  39. case XT_CONNBYTES_DIR_ORIGINAL:
  40. what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
  41. break;
  42. case XT_CONNBYTES_DIR_REPLY:
  43. what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  44. break;
  45. case XT_CONNBYTES_DIR_BOTH:
  46. what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
  47. what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  48. break;
  49. }
  50. break;
  51. case XT_CONNBYTES_BYTES:
  52. switch (sinfo->direction) {
  53. case XT_CONNBYTES_DIR_ORIGINAL:
  54. what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
  55. break;
  56. case XT_CONNBYTES_DIR_REPLY:
  57. what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  58. break;
  59. case XT_CONNBYTES_DIR_BOTH:
  60. what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
  61. what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  62. break;
  63. }
  64. break;
  65. case XT_CONNBYTES_AVGPKT:
  66. switch (sinfo->direction) {
  67. case XT_CONNBYTES_DIR_ORIGINAL:
  68. bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
  69. pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
  70. break;
  71. case XT_CONNBYTES_DIR_REPLY:
  72. bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  73. pkts = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  74. break;
  75. case XT_CONNBYTES_DIR_BOTH:
  76. bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
  77. atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
  78. pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
  79. atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
  80. break;
  81. }
  82. if (pkts != 0)
  83. what = div64_u64(bytes, pkts);
  84. break;
  85. }
  86. if (sinfo->count.to >= sinfo->count.from)
  87. return what <= sinfo->count.to && what >= sinfo->count.from;
  88. else /* inverted */
  89. return what < sinfo->count.to || what > sinfo->count.from;
  90. }
  91. static int connbytes_mt_check(const struct xt_mtchk_param *par)
  92. {
  93. const struct xt_connbytes_info *sinfo = par->matchinfo;
  94. int ret;
  95. if (sinfo->what != XT_CONNBYTES_PKTS &&
  96. sinfo->what != XT_CONNBYTES_BYTES &&
  97. sinfo->what != XT_CONNBYTES_AVGPKT)
  98. return -EINVAL;
  99. if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
  100. sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
  101. sinfo->direction != XT_CONNBYTES_DIR_BOTH)
  102. return -EINVAL;
  103. ret = nf_ct_l3proto_try_module_get(par->family);
  104. if (ret < 0)
  105. pr_info("cannot load conntrack support for proto=%u\n",
  106. par->family);
  107. /*
  108. * This filter cannot function correctly unless connection tracking
  109. * accounting is enabled, so complain in the hope that someone notices.
  110. */
  111. if (!nf_ct_acct_enabled(par->net)) {
  112. pr_warn("Forcing CT accounting to be enabled\n");
  113. nf_ct_set_acct(par->net, true);
  114. }
  115. return ret;
  116. }
  117. static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
  118. {
  119. nf_ct_l3proto_module_put(par->family);
  120. }
  121. static struct xt_match connbytes_mt_reg __read_mostly = {
  122. .name = "connbytes",
  123. .revision = 0,
  124. .family = NFPROTO_UNSPEC,
  125. .checkentry = connbytes_mt_check,
  126. .match = connbytes_mt,
  127. .destroy = connbytes_mt_destroy,
  128. .matchsize = sizeof(struct xt_connbytes_info),
  129. .me = THIS_MODULE,
  130. };
  131. static int __init connbytes_mt_init(void)
  132. {
  133. return xt_register_match(&connbytes_mt_reg);
  134. }
  135. static void __exit connbytes_mt_exit(void)
  136. {
  137. xt_unregister_match(&connbytes_mt_reg);
  138. }
  139. module_init(connbytes_mt_init);
  140. module_exit(connbytes_mt_exit);