/extensions/libip6t_limit.c

https://github.com/MIPS/external-iptables · C · 195 lines · 146 code · 29 blank · 20 comment · 29 complexity · d3a4f712b6d06c72ac3ec17abb501c1d MD5 · raw file

  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. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <getopt.h>
  10. #include <ip6tables.h>
  11. #include <stddef.h>
  12. #include <linux/netfilter_ipv6/ip6_tables.h>
  13. /* For 64bit kernel / 32bit userspace */
  14. #include "../include/linux/netfilter_ipv6/ip6t_limit.h"
  15. #define IP6T_LIMIT_AVG "3/hour"
  16. #define IP6T_LIMIT_BURST 5
  17. /* Function which prints out usage message. */
  18. static void
  19. help(void)
  20. {
  21. printf(
  22. "limit v%s options:\n"
  23. "--limit avg max average match rate: default "IP6T_LIMIT_AVG"\n"
  24. " [Packets per second unless followed by \n"
  25. " /sec /minute /hour /day postfixes]\n"
  26. "--limit-burst number number to match in a burst, default %u\n"
  27. "\n", IPTABLES_VERSION, IP6T_LIMIT_BURST);
  28. }
  29. static struct option opts[] = {
  30. { "limit", 1, 0, '%' },
  31. { "limit-burst", 1, 0, '$' },
  32. { 0 }
  33. };
  34. static
  35. int parse_rate(const char *rate, u_int32_t *val)
  36. {
  37. const char *delim;
  38. u_int32_t r;
  39. u_int32_t mult = 1; /* Seconds by default. */
  40. delim = strchr(rate, '/');
  41. if (delim) {
  42. if (strlen(delim+1) == 0)
  43. return 0;
  44. if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
  45. mult = 1;
  46. else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
  47. mult = 60;
  48. else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
  49. mult = 60*60;
  50. else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
  51. mult = 24*60*60;
  52. else
  53. return 0;
  54. }
  55. r = atoi(rate);
  56. if (!r)
  57. return 0;
  58. /* This would get mapped to infinite (1/day is minimum they
  59. can specify, so we're ok at that end). */
  60. if (r / mult > IP6T_LIMIT_SCALE)
  61. exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
  62. *val = IP6T_LIMIT_SCALE * mult / r;
  63. return 1;
  64. }
  65. /* Initialize the match. */
  66. static void
  67. init(struct ip6t_entry_match *m, unsigned int *nfcache)
  68. {
  69. struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)m->data;
  70. parse_rate(IP6T_LIMIT_AVG, &r->avg);
  71. r->burst = IP6T_LIMIT_BURST;
  72. }
  73. /* FIXME: handle overflow:
  74. if (r->avg*r->burst/r->burst != r->avg)
  75. exit_error(PARAMETER_PROBLEM,
  76. "Sorry: burst too large for that avg rate.\n");
  77. */
  78. /* Function which parses command options; returns true if it
  79. ate an option */
  80. static int
  81. parse(int c, char **argv, int invert, unsigned int *flags,
  82. const struct ip6t_entry *entry,
  83. unsigned int *nfcache,
  84. struct ip6t_entry_match **match)
  85. {
  86. struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)(*match)->data;
  87. unsigned int num;
  88. switch(c) {
  89. case '%':
  90. if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
  91. if (!parse_rate(optarg, &r->avg))
  92. exit_error(PARAMETER_PROBLEM,
  93. "bad rate `%s'", optarg);
  94. break;
  95. case '$':
  96. if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
  97. if (string_to_number(optarg, 0, 10000, &num) == -1)
  98. exit_error(PARAMETER_PROBLEM,
  99. "bad --limit-burst `%s'", optarg);
  100. r->burst = num;
  101. break;
  102. default:
  103. return 0;
  104. }
  105. if (invert)
  106. exit_error(PARAMETER_PROBLEM,
  107. "limit does not support invert");
  108. return 1;
  109. }
  110. /* Final check; nothing. */
  111. static void final_check(unsigned int flags)
  112. {
  113. }
  114. static struct rates
  115. {
  116. const char *name;
  117. u_int32_t mult;
  118. } rates[] = { { "day", IP6T_LIMIT_SCALE*24*60*60 },
  119. { "hour", IP6T_LIMIT_SCALE*60*60 },
  120. { "min", IP6T_LIMIT_SCALE*60 },
  121. { "sec", IP6T_LIMIT_SCALE } };
  122. static void print_rate(u_int32_t period)
  123. {
  124. unsigned int i;
  125. for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
  126. if (period > rates[i].mult
  127. || rates[i].mult % period != 0)
  128. break;
  129. }
  130. printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
  131. }
  132. /* Prints out the matchinfo. */
  133. static void
  134. print(const struct ip6t_ip6 *ip,
  135. const struct ip6t_entry_match *match,
  136. int numeric)
  137. {
  138. struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)match->data;
  139. printf("limit: avg "); print_rate(r->avg);
  140. printf("burst %u ", r->burst);
  141. }
  142. /* FIXME: Make minimalist: only print rate if not default --RR */
  143. static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
  144. {
  145. struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)match->data;
  146. printf("--limit "); print_rate(r->avg);
  147. if (r->burst != IP6T_LIMIT_BURST)
  148. printf("--limit-burst %u ", r->burst);
  149. }
  150. static struct ip6tables_match limit = {
  151. .name = "limit",
  152. .version = IPTABLES_VERSION,
  153. .size = IP6T_ALIGN(sizeof(struct ip6t_rateinfo)),
  154. .userspacesize = offsetof(struct ip6t_rateinfo, prev),
  155. .help = &help,
  156. .init = &init,
  157. .parse = &parse,
  158. .final_check = &final_check,
  159. .print = &print,
  160. .save = &save,
  161. .extra_opts = opts,
  162. };
  163. void _init(void)
  164. {
  165. register_match6(&limit);
  166. }