libxt_hashlimit.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /* ip6tables match extension for limiting packets per destination
  2. *
  3. * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
  4. *
  5. * Development of this code was funded by Astaro AG, http://www.astaro.com/
  6. *
  7. * Based on ipt_limit.c by
  8. * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
  9. * Hervé Eychenne <rv@wallfire.org>
  10. *
  11. * Error corections by nmalykh@bilim.com (22.01.2005)
  12. */
  13. #define _BSD_SOURCE 1
  14. #define _ISOC99_SOURCE 1
  15. #include <math.h>
  16. #include <stdbool.h>
  17. #include <stdint.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <xtables.h>
  22. #include <linux/netfilter/x_tables.h>
  23. #include <linux/netfilter/xt_hashlimit.h>
  24. #define XT_HASHLIMIT_BURST 5
  25. #define XT_HASHLIMIT_BURST_MAX 10000
  26. #define XT_HASHLIMIT_BYTE_EXPIRE 15
  27. #define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60
  28. /* miliseconds */
  29. #define XT_HASHLIMIT_GCINTERVAL 1000
  30. struct hashlimit_mt_udata {
  31. uint32_t mult;
  32. };
  33. static void hashlimit_help(void)
  34. {
  35. printf(
  36. "hashlimit match options:\n"
  37. "--hashlimit <avg> max average match rate\n"
  38. " [Packets per second unless followed by \n"
  39. " /sec /minute /hour /day postfixes]\n"
  40. "--hashlimit-mode <mode> mode is a comma-separated list of\n"
  41. " dstip,srcip,dstport,srcport\n"
  42. "--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n"
  43. "[--hashlimit-burst <num>] number to match in a burst, default %u\n"
  44. "[--hashlimit-htable-size <num>] number of hashtable buckets\n"
  45. "[--hashlimit-htable-max <num>] number of hashtable entries\n"
  46. "[--hashlimit-htable-gcinterval] interval between garbage collection runs\n"
  47. "[--hashlimit-htable-expire] after which time are idle entries expired?\n",
  48. XT_HASHLIMIT_BURST);
  49. }
  50. enum {
  51. O_UPTO = 0,
  52. O_ABOVE,
  53. O_LIMIT,
  54. O_MODE,
  55. O_SRCMASK,
  56. O_DSTMASK,
  57. O_NAME,
  58. O_BURST,
  59. O_HTABLE_SIZE,
  60. O_HTABLE_MAX,
  61. O_HTABLE_GCINT,
  62. O_HTABLE_EXPIRE,
  63. F_BURST = 1 << O_BURST,
  64. F_UPTO = 1 << O_UPTO,
  65. F_ABOVE = 1 << O_ABOVE,
  66. F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
  67. };
  68. static void hashlimit_mt_help(void)
  69. {
  70. printf(
  71. "hashlimit match options:\n"
  72. " --hashlimit-upto <avg> max average match rate\n"
  73. " [Packets per second unless followed by \n"
  74. " /sec /minute /hour /day postfixes]\n"
  75. " --hashlimit-above <avg> min average match rate\n"
  76. " --hashlimit-mode <mode> mode is a comma-separated list of\n"
  77. " dstip,srcip,dstport,srcport (or none)\n"
  78. " --hashlimit-srcmask <length> source address grouping prefix length\n"
  79. " --hashlimit-dstmask <length> destination address grouping prefix length\n"
  80. " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
  81. " --hashlimit-burst <num> number to match in a burst, default %u\n"
  82. " --hashlimit-htable-size <num> number of hashtable buckets\n"
  83. " --hashlimit-htable-max <num> number of hashtable entries\n"
  84. " --hashlimit-htable-gcinterval interval between garbage collection runs\n"
  85. " --hashlimit-htable-expire after which time are idle entries expired?\n"
  86. "\n", XT_HASHLIMIT_BURST);
  87. }
  88. #define s struct xt_hashlimit_info
  89. static const struct xt_option_entry hashlimit_opts[] = {
  90. {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
  91. .type = XTTYPE_STRING},
  92. {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
  93. .min = 1, .max = XT_HASHLIMIT_BURST_MAX, .flags = XTOPT_PUT,
  94. XTOPT_POINTER(s, cfg.burst)},
  95. {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
  96. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  97. XTOPT_POINTER(s, cfg.size)},
  98. {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
  99. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  100. XTOPT_POINTER(s, cfg.max)},
  101. {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
  102. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  103. XTOPT_POINTER(s, cfg.gc_interval)},
  104. {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
  105. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  106. XTOPT_POINTER(s, cfg.expire)},
  107. {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
  108. .flags = XTOPT_MAND},
  109. {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
  110. .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
  111. XTOPT_TABLEEND,
  112. };
  113. #undef s
  114. #define s struct xt_hashlimit_mtinfo1
  115. static const struct xt_option_entry hashlimit_mt_opts[] = {
  116. {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
  117. .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
  118. {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
  119. .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
  120. {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
  121. .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
  122. {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
  123. {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
  124. {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
  125. {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
  126. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  127. XTOPT_POINTER(s, cfg.size)},
  128. {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
  129. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  130. XTOPT_POINTER(s, cfg.max)},
  131. {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
  132. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  133. XTOPT_POINTER(s, cfg.gc_interval)},
  134. {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
  135. .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
  136. XTOPT_POINTER(s, cfg.expire)},
  137. {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
  138. {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
  139. .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
  140. XTOPT_TABLEEND,
  141. };
  142. #undef s
  143. static uint32_t cost_to_bytes(uint32_t cost)
  144. {
  145. uint32_t r;
  146. r = cost ? UINT32_MAX / cost : UINT32_MAX;
  147. r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
  148. return r;
  149. }
  150. static uint64_t bytes_to_cost(uint32_t bytes)
  151. {
  152. uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
  153. return UINT32_MAX / (r+1);
  154. }
  155. static uint32_t get_factor(int chr)
  156. {
  157. switch (chr) {
  158. case 'm': return 1024 * 1024;
  159. case 'k': return 1024;
  160. }
  161. return 1;
  162. }
  163. static void burst_error(void)
  164. {
  165. xtables_error(PARAMETER_PROBLEM, "bad value for option "
  166. "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
  167. }
  168. static uint32_t parse_burst(const char *burst, struct xt_hashlimit_mtinfo1 *info)
  169. {
  170. uintmax_t v;
  171. char *end;
  172. if (!xtables_strtoul(burst, &end, &v, 1, UINT32_MAX) ||
  173. (*end == 0 && v > XT_HASHLIMIT_BURST_MAX))
  174. burst_error();
  175. v *= get_factor(*end);
  176. if (v > UINT32_MAX)
  177. xtables_error(PARAMETER_PROBLEM, "bad value for option "
  178. "\"--hashlimit-burst\", value \"%s\" too large "
  179. "(max %umb).", burst, UINT32_MAX/1024/1024);
  180. return v;
  181. }
  182. static bool parse_bytes(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
  183. {
  184. unsigned int factor = 1;
  185. uint64_t tmp;
  186. int r;
  187. const char *mode = strstr(rate, "b/s");
  188. if (!mode || mode == rate)
  189. return false;
  190. mode--;
  191. r = atoi(rate);
  192. if (r == 0)
  193. return false;
  194. factor = get_factor(*mode);
  195. tmp = (uint64_t) r * factor;
  196. if (tmp > UINT32_MAX)
  197. xtables_error(PARAMETER_PROBLEM,
  198. "Rate value too large \"%llu\" (max %u)\n",
  199. (unsigned long long)tmp, UINT32_MAX);
  200. *val = bytes_to_cost(tmp);
  201. if (*val == 0)
  202. xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
  203. ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
  204. return true;
  205. }
  206. static
  207. int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
  208. {
  209. const char *delim;
  210. uint32_t r;
  211. ud->mult = 1; /* Seconds by default. */
  212. delim = strchr(rate, '/');
  213. if (delim) {
  214. if (strlen(delim+1) == 0)
  215. return 0;
  216. if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
  217. ud->mult = 1;
  218. else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
  219. ud->mult = 60;
  220. else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
  221. ud->mult = 60*60;
  222. else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
  223. ud->mult = 24*60*60;
  224. else
  225. return 0;
  226. }
  227. r = atoi(rate);
  228. if (!r)
  229. return 0;
  230. *val = XT_HASHLIMIT_SCALE * ud->mult / r;
  231. if (*val == 0)
  232. /*
  233. * The rate maps to infinity. (1/day is the minimum they can
  234. * specify, so we are ok at that end).
  235. */
  236. xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
  237. return 1;
  238. }
  239. static void hashlimit_init(struct xt_entry_match *m)
  240. {
  241. struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
  242. r->cfg.burst = XT_HASHLIMIT_BURST;
  243. r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
  244. }
  245. static void hashlimit_mt4_init(struct xt_entry_match *match)
  246. {
  247. struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
  248. info->cfg.mode = 0;
  249. info->cfg.burst = XT_HASHLIMIT_BURST;
  250. info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
  251. info->cfg.srcmask = 32;
  252. info->cfg.dstmask = 32;
  253. }
  254. static void hashlimit_mt6_init(struct xt_entry_match *match)
  255. {
  256. struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
  257. info->cfg.mode = 0;
  258. info->cfg.burst = XT_HASHLIMIT_BURST;
  259. info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
  260. info->cfg.srcmask = 128;
  261. info->cfg.dstmask = 128;
  262. }
  263. /* Parse a 'mode' parameter into the required bitmask */
  264. static int parse_mode(uint32_t *mode, const char *option_arg)
  265. {
  266. char *tok;
  267. char *arg = strdup(option_arg);
  268. if (!arg)
  269. return -1;
  270. for (tok = strtok(arg, ",|");
  271. tok;
  272. tok = strtok(NULL, ",|")) {
  273. if (!strcmp(tok, "dstip"))
  274. *mode |= XT_HASHLIMIT_HASH_DIP;
  275. else if (!strcmp(tok, "srcip"))
  276. *mode |= XT_HASHLIMIT_HASH_SIP;
  277. else if (!strcmp(tok, "srcport"))
  278. *mode |= XT_HASHLIMIT_HASH_SPT;
  279. else if (!strcmp(tok, "dstport"))
  280. *mode |= XT_HASHLIMIT_HASH_DPT;
  281. else {
  282. free(arg);
  283. return -1;
  284. }
  285. }
  286. free(arg);
  287. return 0;
  288. }
  289. static void hashlimit_parse(struct xt_option_call *cb)
  290. {
  291. struct xt_hashlimit_info *info = cb->data;
  292. xtables_option_parse(cb);
  293. switch (cb->entry->id) {
  294. case O_UPTO:
  295. if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
  296. xtables_param_act(XTF_BAD_VALUE, "hashlimit",
  297. "--hashlimit-upto", cb->arg);
  298. break;
  299. case O_MODE:
  300. if (parse_mode(&info->cfg.mode, cb->arg) < 0)
  301. xtables_param_act(XTF_BAD_VALUE, "hashlimit",
  302. "--hashlimit-mode", cb->arg);
  303. break;
  304. }
  305. }
  306. static void hashlimit_mt_parse(struct xt_option_call *cb)
  307. {
  308. struct xt_hashlimit_mtinfo1 *info = cb->data;
  309. xtables_option_parse(cb);
  310. switch (cb->entry->id) {
  311. case O_BURST:
  312. info->cfg.burst = parse_burst(cb->arg, info);
  313. break;
  314. case O_UPTO:
  315. if (cb->invert)
  316. info->cfg.mode |= XT_HASHLIMIT_INVERT;
  317. if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
  318. info->cfg.mode |= XT_HASHLIMIT_BYTES;
  319. else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
  320. xtables_param_act(XTF_BAD_VALUE, "hashlimit",
  321. "--hashlimit-upto", cb->arg);
  322. break;
  323. case O_ABOVE:
  324. if (!cb->invert)
  325. info->cfg.mode |= XT_HASHLIMIT_INVERT;
  326. if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
  327. info->cfg.mode |= XT_HASHLIMIT_BYTES;
  328. else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
  329. xtables_param_act(XTF_BAD_VALUE, "hashlimit",
  330. "--hashlimit-above", cb->arg);
  331. break;
  332. case O_MODE:
  333. if (parse_mode(&info->cfg.mode, cb->arg) < 0)
  334. xtables_param_act(XTF_BAD_VALUE, "hashlimit",
  335. "--hashlimit-mode", cb->arg);
  336. break;
  337. case O_SRCMASK:
  338. info->cfg.srcmask = cb->val.hlen;
  339. break;
  340. case O_DSTMASK:
  341. info->cfg.dstmask = cb->val.hlen;
  342. break;
  343. }
  344. }
  345. static void hashlimit_check(struct xt_fcheck_call *cb)
  346. {
  347. const struct hashlimit_mt_udata *udata = cb->udata;
  348. struct xt_hashlimit_info *info = cb->data;
  349. if (!(cb->xflags & (F_UPTO | F_ABOVE)))
  350. xtables_error(PARAMETER_PROBLEM,
  351. "You have to specify --hashlimit");
  352. if (!(cb->xflags & F_HTABLE_EXPIRE))
  353. info->cfg.expire = udata->mult * 1000; /* from s to msec */
  354. }
  355. static void hashlimit_mt_check(struct xt_fcheck_call *cb)
  356. {
  357. const struct hashlimit_mt_udata *udata = cb->udata;
  358. struct xt_hashlimit_mtinfo1 *info = cb->data;
  359. if (!(cb->xflags & (F_UPTO | F_ABOVE)))
  360. xtables_error(PARAMETER_PROBLEM,
  361. "You have to specify --hashlimit");
  362. if (!(cb->xflags & F_HTABLE_EXPIRE))
  363. info->cfg.expire = udata->mult * 1000; /* from s to msec */
  364. if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
  365. uint32_t burst = 0;
  366. if (cb->xflags & F_BURST) {
  367. if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
  368. xtables_error(PARAMETER_PROBLEM,
  369. "burst cannot be smaller than %ub", cost_to_bytes(info->cfg.avg));
  370. burst = info->cfg.burst;
  371. burst /= cost_to_bytes(info->cfg.avg);
  372. if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
  373. burst++;
  374. if (!(cb->xflags & F_HTABLE_EXPIRE))
  375. info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
  376. }
  377. info->cfg.burst = burst;
  378. } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
  379. burst_error();
  380. }
  381. static const struct rates
  382. {
  383. const char *name;
  384. uint32_t mult;
  385. } rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
  386. { "hour", XT_HASHLIMIT_SCALE*60*60 },
  387. { "min", XT_HASHLIMIT_SCALE*60 },
  388. { "sec", XT_HASHLIMIT_SCALE } };
  389. static uint32_t print_rate(uint32_t period)
  390. {
  391. unsigned int i;
  392. if (period == 0) {
  393. printf(" %f", INFINITY);
  394. return 0;
  395. }
  396. for (i = 1; i < ARRAY_SIZE(rates); ++i)
  397. if (period > rates[i].mult
  398. || rates[i].mult/period < rates[i].mult%period)
  399. break;
  400. printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
  401. /* return in msec */
  402. return rates[i-1].mult / XT_HASHLIMIT_SCALE * 1000;
  403. }
  404. static const struct {
  405. const char *name;
  406. uint32_t thresh;
  407. } units[] = {
  408. { "m", 1024 * 1024 },
  409. { "k", 1024 },
  410. { "", 1 },
  411. };
  412. static uint32_t print_bytes(uint32_t avg, uint32_t burst, const char *prefix)
  413. {
  414. unsigned int i;
  415. unsigned long long r;
  416. r = cost_to_bytes(avg);
  417. for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
  418. if (r >= units[i].thresh &&
  419. bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
  420. break;
  421. printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
  422. if (burst == 0)
  423. return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
  424. r *= burst;
  425. printf(" %s", prefix);
  426. for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
  427. if (r >= units[i].thresh)
  428. break;
  429. printf("burst %llu%sb", r / units[i].thresh, units[i].name);
  430. return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
  431. }
  432. static void print_mode(unsigned int mode, char separator)
  433. {
  434. bool prevmode = false;
  435. putchar(' ');
  436. if (mode & XT_HASHLIMIT_HASH_SIP) {
  437. fputs("srcip", stdout);
  438. prevmode = 1;
  439. }
  440. if (mode & XT_HASHLIMIT_HASH_SPT) {
  441. if (prevmode)
  442. putchar(separator);
  443. fputs("srcport", stdout);
  444. prevmode = 1;
  445. }
  446. if (mode & XT_HASHLIMIT_HASH_DIP) {
  447. if (prevmode)
  448. putchar(separator);
  449. fputs("dstip", stdout);
  450. prevmode = 1;
  451. }
  452. if (mode & XT_HASHLIMIT_HASH_DPT) {
  453. if (prevmode)
  454. putchar(separator);
  455. fputs("dstport", stdout);
  456. }
  457. }
  458. static void hashlimit_print(const void *ip,
  459. const struct xt_entry_match *match, int numeric)
  460. {
  461. const struct xt_hashlimit_info *r = (const void *)match->data;
  462. uint32_t quantum;
  463. fputs(" limit: avg", stdout);
  464. quantum = print_rate(r->cfg.avg);
  465. printf(" burst %u", r->cfg.burst);
  466. fputs(" mode", stdout);
  467. print_mode(r->cfg.mode, '-');
  468. if (r->cfg.size)
  469. printf(" htable-size %u", r->cfg.size);
  470. if (r->cfg.max)
  471. printf(" htable-max %u", r->cfg.max);
  472. if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
  473. printf(" htable-gcinterval %u", r->cfg.gc_interval);
  474. if (r->cfg.expire != quantum)
  475. printf(" htable-expire %u", r->cfg.expire);
  476. }
  477. static void
  478. hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
  479. {
  480. uint32_t quantum;
  481. if (info->cfg.mode & XT_HASHLIMIT_INVERT)
  482. fputs(" limit: above", stdout);
  483. else
  484. fputs(" limit: up to", stdout);
  485. if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
  486. quantum = print_bytes(info->cfg.avg, info->cfg.burst, "");
  487. } else {
  488. quantum = print_rate(info->cfg.avg);
  489. printf(" burst %u", info->cfg.burst);
  490. }
  491. if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
  492. XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
  493. fputs(" mode", stdout);
  494. print_mode(info->cfg.mode, '-');
  495. }
  496. if (info->cfg.size != 0)
  497. printf(" htable-size %u", info->cfg.size);
  498. if (info->cfg.max != 0)
  499. printf(" htable-max %u", info->cfg.max);
  500. if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
  501. printf(" htable-gcinterval %u", info->cfg.gc_interval);
  502. if (info->cfg.expire != quantum)
  503. printf(" htable-expire %u", info->cfg.expire);
  504. if (info->cfg.srcmask != dmask)
  505. printf(" srcmask %u", info->cfg.srcmask);
  506. if (info->cfg.dstmask != dmask)
  507. printf(" dstmask %u", info->cfg.dstmask);
  508. }
  509. static void
  510. hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
  511. int numeric)
  512. {
  513. const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
  514. hashlimit_mt_print(info, 32);
  515. }
  516. static void
  517. hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
  518. int numeric)
  519. {
  520. const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
  521. hashlimit_mt_print(info, 128);
  522. }
  523. static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
  524. {
  525. const struct xt_hashlimit_info *r = (const void *)match->data;
  526. uint32_t quantum;
  527. fputs(" --hashlimit", stdout);
  528. quantum = print_rate(r->cfg.avg);
  529. printf(" --hashlimit-burst %u", r->cfg.burst);
  530. fputs(" --hashlimit-mode", stdout);
  531. print_mode(r->cfg.mode, ',');
  532. printf(" --hashlimit-name %s", r->name);
  533. if (r->cfg.size)
  534. printf(" --hashlimit-htable-size %u", r->cfg.size);
  535. if (r->cfg.max)
  536. printf(" --hashlimit-htable-max %u", r->cfg.max);
  537. if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
  538. printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
  539. if (r->cfg.expire != quantum)
  540. printf(" --hashlimit-htable-expire %u", r->cfg.expire);
  541. }
  542. static void
  543. hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
  544. {
  545. uint32_t quantum;
  546. if (info->cfg.mode & XT_HASHLIMIT_INVERT)
  547. fputs(" --hashlimit-above", stdout);
  548. else
  549. fputs(" --hashlimit-upto", stdout);
  550. if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
  551. quantum = print_bytes(info->cfg.avg, info->cfg.burst, "--hashlimit-");
  552. } else {
  553. quantum = print_rate(info->cfg.avg);
  554. printf(" --hashlimit-burst %u", info->cfg.burst);
  555. }
  556. if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
  557. XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
  558. fputs(" --hashlimit-mode", stdout);
  559. print_mode(info->cfg.mode, ',');
  560. }
  561. printf(" --hashlimit-name %s", info->name);
  562. if (info->cfg.size != 0)
  563. printf(" --hashlimit-htable-size %u", info->cfg.size);
  564. if (info->cfg.max != 0)
  565. printf(" --hashlimit-htable-max %u", info->cfg.max);
  566. if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
  567. printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
  568. if (info->cfg.expire != quantum)
  569. printf(" --hashlimit-htable-expire %u", info->cfg.expire);
  570. if (info->cfg.srcmask != dmask)
  571. printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
  572. if (info->cfg.dstmask != dmask)
  573. printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
  574. }
  575. static void
  576. hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
  577. {
  578. const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
  579. hashlimit_mt_save(info, 32);
  580. }
  581. static void
  582. hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
  583. {
  584. const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
  585. hashlimit_mt_save(info, 128);
  586. }
  587. static struct xtables_match hashlimit_mt_reg[] = {
  588. {
  589. .family = NFPROTO_UNSPEC,
  590. .name = "hashlimit",
  591. .version = XTABLES_VERSION,
  592. .revision = 0,
  593. .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
  594. .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
  595. .help = hashlimit_help,
  596. .init = hashlimit_init,
  597. .x6_parse = hashlimit_parse,
  598. .x6_fcheck = hashlimit_check,
  599. .print = hashlimit_print,
  600. .save = hashlimit_save,
  601. .x6_options = hashlimit_opts,
  602. .udata_size = sizeof(struct hashlimit_mt_udata),
  603. },
  604. {
  605. .version = XTABLES_VERSION,
  606. .name = "hashlimit",
  607. .revision = 1,
  608. .family = NFPROTO_IPV4,
  609. .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
  610. .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
  611. .help = hashlimit_mt_help,
  612. .init = hashlimit_mt4_init,
  613. .x6_parse = hashlimit_mt_parse,
  614. .x6_fcheck = hashlimit_mt_check,
  615. .print = hashlimit_mt4_print,
  616. .save = hashlimit_mt4_save,
  617. .x6_options = hashlimit_mt_opts,
  618. .udata_size = sizeof(struct hashlimit_mt_udata),
  619. },
  620. {
  621. .version = XTABLES_VERSION,
  622. .name = "hashlimit",
  623. .revision = 1,
  624. .family = NFPROTO_IPV6,
  625. .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
  626. .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
  627. .help = hashlimit_mt_help,
  628. .init = hashlimit_mt6_init,
  629. .x6_parse = hashlimit_mt_parse,
  630. .x6_fcheck = hashlimit_mt_check,
  631. .print = hashlimit_mt6_print,
  632. .save = hashlimit_mt6_save,
  633. .x6_options = hashlimit_mt_opts,
  634. .udata_size = sizeof(struct hashlimit_mt_udata),
  635. },
  636. };
  637. void _init(void)
  638. {
  639. xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
  640. }