xt_connbytes.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /* Kernel module to match connection tracking byte counter.
  2. * GPL (C) 2002 Martin Devera (devik@cdi.cz).
  3. *
  4. * 2004-07-20 Harald Welte <laforge@netfilter.org>
  5. * - reimplemented to use per-connection accounting counters
  6. * - add functionality to match number of packets
  7. * - add functionality to match average packet size
  8. * - add support to match directions seperately
  9. * 2005-10-16 Harald Welte <laforge@netfilter.org>
  10. * - Port to x_tables
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/skbuff.h>
  15. #include <net/netfilter/nf_conntrack_compat.h>
  16. #include <linux/netfilter/x_tables.h>
  17. #include <linux/netfilter/xt_connbytes.h>
  18. #include <asm/div64.h>
  19. #include <asm/bitops.h>
  20. MODULE_LICENSE("GPL");
  21. MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  22. MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
  23. MODULE_ALIAS("ipt_connbytes");
  24. static int
  25. match(const struct sk_buff *skb,
  26. const struct net_device *in,
  27. const struct net_device *out,
  28. const struct xt_match *match,
  29. const void *matchinfo,
  30. int offset,
  31. unsigned int protoff,
  32. int *hotdrop)
  33. {
  34. const struct xt_connbytes_info *sinfo = matchinfo;
  35. u_int64_t what = 0; /* initialize to make gcc happy */
  36. u_int64_t bytes = 0;
  37. u_int64_t pkts = 0;
  38. const struct ip_conntrack_counter *counters;
  39. if (!(counters = nf_ct_get_counters(skb)))
  40. return 0; /* no match */
  41. switch (sinfo->what) {
  42. case XT_CONNBYTES_PKTS:
  43. switch (sinfo->direction) {
  44. case XT_CONNBYTES_DIR_ORIGINAL:
  45. what = counters[IP_CT_DIR_ORIGINAL].packets;
  46. break;
  47. case XT_CONNBYTES_DIR_REPLY:
  48. what = counters[IP_CT_DIR_REPLY].packets;
  49. break;
  50. case XT_CONNBYTES_DIR_BOTH:
  51. what = counters[IP_CT_DIR_ORIGINAL].packets;
  52. what += counters[IP_CT_DIR_REPLY].packets;
  53. break;
  54. }
  55. break;
  56. case XT_CONNBYTES_BYTES:
  57. switch (sinfo->direction) {
  58. case XT_CONNBYTES_DIR_ORIGINAL:
  59. what = counters[IP_CT_DIR_ORIGINAL].bytes;
  60. break;
  61. case XT_CONNBYTES_DIR_REPLY:
  62. what = counters[IP_CT_DIR_REPLY].bytes;
  63. break;
  64. case XT_CONNBYTES_DIR_BOTH:
  65. what = counters[IP_CT_DIR_ORIGINAL].bytes;
  66. what += counters[IP_CT_DIR_REPLY].bytes;
  67. break;
  68. }
  69. break;
  70. case XT_CONNBYTES_AVGPKT:
  71. switch (sinfo->direction) {
  72. case XT_CONNBYTES_DIR_ORIGINAL:
  73. bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
  74. pkts = counters[IP_CT_DIR_ORIGINAL].packets;
  75. break;
  76. case XT_CONNBYTES_DIR_REPLY:
  77. bytes = counters[IP_CT_DIR_REPLY].bytes;
  78. pkts = counters[IP_CT_DIR_REPLY].packets;
  79. break;
  80. case XT_CONNBYTES_DIR_BOTH:
  81. bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
  82. counters[IP_CT_DIR_REPLY].bytes;
  83. pkts = counters[IP_CT_DIR_ORIGINAL].packets +
  84. counters[IP_CT_DIR_REPLY].packets;
  85. break;
  86. }
  87. if (pkts != 0)
  88. what = div64_64(bytes, pkts);
  89. break;
  90. }
  91. if (sinfo->count.to)
  92. return (what <= sinfo->count.to && what >= sinfo->count.from);
  93. else
  94. return (what >= sinfo->count.from);
  95. }
  96. static int check(const char *tablename,
  97. const void *ip,
  98. const struct xt_match *match,
  99. void *matchinfo,
  100. unsigned int hook_mask)
  101. {
  102. const struct xt_connbytes_info *sinfo = matchinfo;
  103. if (sinfo->what != XT_CONNBYTES_PKTS &&
  104. sinfo->what != XT_CONNBYTES_BYTES &&
  105. sinfo->what != XT_CONNBYTES_AVGPKT)
  106. return 0;
  107. if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
  108. sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
  109. sinfo->direction != XT_CONNBYTES_DIR_BOTH)
  110. return 0;
  111. if (nf_ct_l3proto_try_module_get(match->family) < 0) {
  112. printk(KERN_WARNING "can't load conntrack support for "
  113. "proto=%d\n", match->family);
  114. return 0;
  115. }
  116. return 1;
  117. }
  118. static void
  119. destroy(const struct xt_match *match, void *matchinfo)
  120. {
  121. nf_ct_l3proto_module_put(match->family);
  122. }
  123. static struct xt_match xt_connbytes_match[] = {
  124. {
  125. .name = "connbytes",
  126. .family = AF_INET,
  127. .checkentry = check,
  128. .match = match,
  129. .destroy = destroy,
  130. .matchsize = sizeof(struct xt_connbytes_info),
  131. .me = THIS_MODULE
  132. },
  133. {
  134. .name = "connbytes",
  135. .family = AF_INET6,
  136. .checkentry = check,
  137. .match = match,
  138. .destroy = destroy,
  139. .matchsize = sizeof(struct xt_connbytes_info),
  140. .me = THIS_MODULE
  141. },
  142. };
  143. static int __init xt_connbytes_init(void)
  144. {
  145. return xt_register_matches(xt_connbytes_match,
  146. ARRAY_SIZE(xt_connbytes_match));
  147. }
  148. static void __exit xt_connbytes_fini(void)
  149. {
  150. xt_unregister_matches(xt_connbytes_match,
  151. ARRAY_SIZE(xt_connbytes_match));
  152. }
  153. module_init(xt_connbytes_init);
  154. module_exit(xt_connbytes_fini);