libxt_limit.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* Shared library add-on to iptables to add limit support.
  2. *
  3. * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
  4. * Hervé Eychenne <rv@wallfire.org>
  5. */
  6. #define _BSD_SOURCE 1
  7. #define _ISOC99_SOURCE 1
  8. #include <math.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <xtables.h>
  13. #include <linux/netfilter/x_tables.h>
  14. #include <linux/netfilter/xt_limit.h>
  15. #define XT_LIMIT_AVG "3/hour"
  16. #define XT_LIMIT_BURST 5
  17. enum {
  18. O_LIMIT = 0,
  19. O_BURST,
  20. };
  21. static void limit_help(void)
  22. {
  23. printf(
  24. "limit match options:\n"
  25. "--limit avg max average match rate: default "XT_LIMIT_AVG"\n"
  26. " [Packets per second unless followed by \n"
  27. " /sec /minute /hour /day postfixes]\n"
  28. "--limit-burst number number to match in a burst, default %u\n",
  29. XT_LIMIT_BURST);
  30. }
  31. static const struct xt_option_entry limit_opts[] = {
  32. {.name = "limit", .id = O_LIMIT, .type = XTTYPE_STRING},
  33. {.name = "limit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
  34. .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_rateinfo, burst),
  35. .min = 0, .max = 10000},
  36. XTOPT_TABLEEND,
  37. };
  38. static
  39. int parse_rate(const char *rate, uint32_t *val)
  40. {
  41. const char *delim;
  42. uint32_t r;
  43. uint32_t mult = 1; /* Seconds by default. */
  44. delim = strchr(rate, '/');
  45. if (delim) {
  46. if (strlen(delim+1) == 0)
  47. return 0;
  48. if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
  49. mult = 1;
  50. else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
  51. mult = 60;
  52. else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
  53. mult = 60*60;
  54. else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
  55. mult = 24*60*60;
  56. else
  57. return 0;
  58. }
  59. r = atoi(rate);
  60. if (!r)
  61. return 0;
  62. *val = XT_LIMIT_SCALE * mult / r;
  63. if (*val == 0)
  64. /*
  65. * The rate maps to infinity. (1/day is the minimum they can
  66. * specify, so we are ok at that end).
  67. */
  68. xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
  69. return 1;
  70. }
  71. static void limit_init(struct xt_entry_match *m)
  72. {
  73. struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
  74. parse_rate(XT_LIMIT_AVG, &r->avg);
  75. r->burst = XT_LIMIT_BURST;
  76. }
  77. /* FIXME: handle overflow:
  78. if (r->avg*r->burst/r->burst != r->avg)
  79. xtables_error(PARAMETER_PROBLEM,
  80. "Sorry: burst too large for that avg rate.\n");
  81. */
  82. static void limit_parse(struct xt_option_call *cb)
  83. {
  84. struct xt_rateinfo *r = cb->data;
  85. xtables_option_parse(cb);
  86. switch (cb->entry->id) {
  87. case O_LIMIT:
  88. if (!parse_rate(cb->arg, &r->avg))
  89. xtables_error(PARAMETER_PROBLEM,
  90. "bad rate \"%s\"'", cb->arg);
  91. break;
  92. }
  93. if (cb->invert)
  94. xtables_error(PARAMETER_PROBLEM,
  95. "limit does not support invert");
  96. }
  97. static const struct rates
  98. {
  99. const char *name;
  100. uint32_t mult;
  101. } rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
  102. { "hour", XT_LIMIT_SCALE*60*60 },
  103. { "min", XT_LIMIT_SCALE*60 },
  104. { "sec", XT_LIMIT_SCALE } };
  105. static void print_rate(uint32_t period)
  106. {
  107. unsigned int i;
  108. if (period == 0) {
  109. printf(" %f", INFINITY);
  110. return;
  111. }
  112. for (i = 1; i < ARRAY_SIZE(rates); ++i)
  113. if (period > rates[i].mult
  114. || rates[i].mult/period < rates[i].mult%period)
  115. break;
  116. printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
  117. }
  118. static void
  119. limit_print(const void *ip, const struct xt_entry_match *match, int numeric)
  120. {
  121. const struct xt_rateinfo *r = (const void *)match->data;
  122. printf(" limit: avg"); print_rate(r->avg);
  123. printf(" burst %u", r->burst);
  124. }
  125. static void limit_save(const void *ip, const struct xt_entry_match *match)
  126. {
  127. const struct xt_rateinfo *r = (const void *)match->data;
  128. printf(" --limit"); print_rate(r->avg);
  129. if (r->burst != XT_LIMIT_BURST)
  130. printf(" --limit-burst %u", r->burst);
  131. }
  132. static struct xtables_match limit_match = {
  133. .family = NFPROTO_UNSPEC,
  134. .name = "limit",
  135. .version = XTABLES_VERSION,
  136. .size = XT_ALIGN(sizeof(struct xt_rateinfo)),
  137. .userspacesize = offsetof(struct xt_rateinfo, prev),
  138. .help = limit_help,
  139. .init = limit_init,
  140. .x6_parse = limit_parse,
  141. .print = limit_print,
  142. .save = limit_save,
  143. .x6_options = limit_opts,
  144. };
  145. void _init(void)
  146. {
  147. xtables_register_match(&limit_match);
  148. }