100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy/* ip6tables match extension for limiting packets per destination
200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy *
300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy *
500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy * Development of this code was funded by Astaro AG, http://www.astaro.com/
600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy *
700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy * Based on ipt_limit.c by
881bd58838403fc8c4a63840f0af42deebe6d4a20Jan Engelhardt * Jérôme de Vivie   <devivie@info.enserb.u-bordeaux.fr>
981bd58838403fc8c4a63840f0af42deebe6d4a20Jan Engelhardt * Hervé Eychenne    <rv@wallfire.org>
1000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy *
1100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy * Error corections by nmalykh@bilim.com (22.01.2005)
1200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy */
139921f2b9a241750e4730fc7d486687c6a32779f4Jan Engelhardt#define _BSD_SOURCE 1
149921f2b9a241750e4730fc7d486687c6a32779f4Jan Engelhardt#define _ISOC99_SOURCE 1
159d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt#include <math.h>
169a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt#include <stdbool.h>
17ef18e8147903885708d1c264904129af4fb636d6Jan Engelhardt#include <stdint.h>
1800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy#include <stdio.h>
1900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy#include <string.h>
2000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy#include <stdlib.h>
21d62a9db1295608ef98394b830703389973346716Yasuyuki KOZAKAI#include <xtables.h>
22d62a9db1295608ef98394b830703389973346716Yasuyuki KOZAKAI#include <linux/netfilter/x_tables.h>
2300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy#include <linux/netfilter/xt_hashlimit.h>
2400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
2500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy#define XT_HASHLIMIT_BURST	5
26abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal#define XT_HASHLIMIT_BURST_MAX	10000
27abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
28abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal#define XT_HASHLIMIT_BYTE_EXPIRE	15
29abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal#define XT_HASHLIMIT_BYTE_EXPIRE_BURST	60
3000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
3100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy/* miliseconds */
3200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy#define XT_HASHLIMIT_GCINTERVAL	1000
3300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
3468146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardtstruct hashlimit_mt_udata {
3568146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	uint32_t mult;
3668146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt};
3768146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt
38181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void hashlimit_help(void)
3900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
4000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	printf(
418b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"hashlimit match options:\n"
4200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"--hashlimit <avg>		max average match rate\n"
4300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"                                [Packets per second unless followed by \n"
4400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"                                /sec /minute /hour /day postfixes]\n"
4500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"--hashlimit-mode <mode>		mode is a comma-separated list of\n"
4600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"					dstip,srcip,dstport,srcport\n"
4700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"--hashlimit-name <name>		name for /proc/net/ipt_hashlimit/\n"
4800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"[--hashlimit-burst <num>]	number to match in a burst, default %u\n"
4900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"[--hashlimit-htable-size <num>]	number of hashtable buckets\n"
5000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"[--hashlimit-htable-max <num>]	number of hashtable entries\n"
5100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy"[--hashlimit-htable-gcinterval]	interval between garbage collection runs\n"
528b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"[--hashlimit-htable-expire]	after which time are idle entries expired?\n",
538b7c64d6ba156a99008fcd810cba874c73294333Jan EngelhardtXT_HASHLIMIT_BURST);
5400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
5500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
56fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtenum {
57fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_UPTO = 0,
58fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_ABOVE,
59fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_LIMIT,
60fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_MODE,
61fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_SRCMASK,
62fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_DSTMASK,
63fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_NAME,
64fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_BURST,
65fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_HTABLE_SIZE,
66fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_HTABLE_MAX,
67fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_HTABLE_GCINT,
68fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	O_HTABLE_EXPIRE,
69abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	F_BURST         = 1 << O_BURST,
7068146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	F_UPTO          = 1 << O_UPTO,
7168146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	F_ABOVE         = 1 << O_ABOVE,
7268146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
73fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt};
74fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt
759a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void hashlimit_mt_help(void)
769a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
779a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	printf(
789a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"hashlimit match options:\n"
799a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-upto <avg>           max average match rate\n"
809a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"                                   [Packets per second unless followed by \n"
819a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"                                   /sec /minute /hour /day postfixes]\n"
829a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-above <avg>          min average match rate\n"
839a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-mode <mode>          mode is a comma-separated list of\n"
849a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"                                   dstip,srcip,dstport,srcport (or none)\n"
859a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-srcmask <length>     source address grouping prefix length\n"
869a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-dstmask <length>     destination address grouping prefix length\n"
879a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-name <name>          name for /proc/net/ipt_hashlimit\n"
889a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-burst <num>	    number to match in a burst, default %u\n"
899a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-htable-size <num>    number of hashtable buckets\n"
909a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-htable-max <num>     number of hashtable entries\n"
919a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-htable-gcinterval    interval between garbage collection runs\n"
929a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"  --hashlimit-htable-expire        after which time are idle entries expired?\n"
939a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt"\n", XT_HASHLIMIT_BURST);
949a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
959a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
96fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt#define s struct xt_hashlimit_info
97fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtstatic const struct xt_option_entry hashlimit_opts[] = {
98fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
99de1f06dca906bfcb82d7c7c2d555fbf3229d12b6Jan Engelhardt	 .type = XTTYPE_STRING},
100fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
101abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	 .min = 1, .max = XT_HASHLIMIT_BURST_MAX, .flags = XTOPT_PUT,
102fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.burst)},
103fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
104fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
105fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.size)},
106fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
107fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
108fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.max)},
109fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
110fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
111fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.gc_interval)},
112fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
113fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
114fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.expire)},
115fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
116fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .flags = XTOPT_MAND},
117fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
118fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
119fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	XTOPT_TABLEEND,
12000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy};
121fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt#undef s
122fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt
123fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt#define s struct xt_hashlimit_mtinfo1
124fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtstatic const struct xt_option_entry hashlimit_mt_opts[] = {
125fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
126fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
127fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
128fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
129fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
130fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
131fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
132fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
133abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
134fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
135fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
136fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.size)},
137fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
138fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
139fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.max)},
140fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
141fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
142fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.gc_interval)},
143fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
144fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
145fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 XTOPT_POINTER(s, cfg.expire)},
146fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
147fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
148fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
149fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	XTOPT_TABLEEND,
1509a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt};
151fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt#undef s
1529a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
153abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic uint32_t cost_to_bytes(uint32_t cost)
154abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
155abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	uint32_t r;
156abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
157abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	r = cost ? UINT32_MAX / cost : UINT32_MAX;
158abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
159abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	return r;
160abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
161abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
162abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic uint64_t bytes_to_cost(uint32_t bytes)
163abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
164abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
165abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	return UINT32_MAX / (r+1);
166abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
167abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
168abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic uint32_t get_factor(int chr)
169abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
170abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	switch (chr) {
171abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	case 'm': return 1024 * 1024;
172abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	case 'k': return 1024;
173abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	}
174abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	return 1;
175abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
176abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
177abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic void burst_error(void)
178abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
179abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	xtables_error(PARAMETER_PROBLEM, "bad value for option "
180abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			"\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
181abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
182abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
183abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic uint32_t parse_burst(const char *burst, struct xt_hashlimit_mtinfo1 *info)
184abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
185abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	uintmax_t v;
186abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	char *end;
187abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
188abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (!xtables_strtoul(burst, &end, &v, 1, UINT32_MAX) ||
189abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	    (*end == 0 && v > XT_HASHLIMIT_BURST_MAX))
190abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		burst_error();
191abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
192abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	v *= get_factor(*end);
193abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (v > UINT32_MAX)
194abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		xtables_error(PARAMETER_PROBLEM, "bad value for option "
195abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			"\"--hashlimit-burst\", value \"%s\" too large "
196abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal				"(max %umb).", burst, UINT32_MAX/1024/1024);
197abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	return v;
198abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
199abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
200abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic bool parse_bytes(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
201abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
202abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	unsigned int factor = 1;
203abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	uint64_t tmp;
204abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	int r;
205abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	const char *mode = strstr(rate, "b/s");
206abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (!mode || mode == rate)
207abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		return false;
208abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
209abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	mode--;
210abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	r = atoi(rate);
211abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (r == 0)
212abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		return false;
213abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
214abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	factor = get_factor(*mode);
215abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	tmp = (uint64_t) r * factor;
216abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (tmp > UINT32_MAX)
217abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		xtables_error(PARAMETER_PROBLEM,
218abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			"Rate value too large \"%llu\" (max %u)\n",
219abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal					(unsigned long long)tmp, UINT32_MAX);
220abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
221abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	*val = bytes_to_cost(tmp);
222abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (*val == 0)
223abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
224abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
225abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
226abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	return true;
227abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
228abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
22900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardystatic
23068146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardtint parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
23100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
23200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	const char *delim;
2337ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardt	uint32_t r;
23400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
23568146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	ud->mult = 1;  /* Seconds by default. */
23600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	delim = strchr(rate, '/');
23700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (delim) {
23800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (strlen(delim+1) == 0)
23900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			return 0;
24000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
24100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
24268146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt			ud->mult = 1;
24300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
24468146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt			ud->mult = 60;
24500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
24668146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt			ud->mult = 60*60;
24700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
24868146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt			ud->mult = 24*60*60;
24900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else
25000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			return 0;
25100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
25200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	r = atoi(rate);
25300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (!r)
25400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		return 0;
25500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
25668146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	*val = XT_HASHLIMIT_SCALE * ud->mult / r;
2579d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt	if (*val == 0)
2589d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		/*
2599d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		 * The rate maps to infinity. (1/day is the minimum they can
2609d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		 * specify, so we are ok at that end).
2619d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		 */
2629d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
26300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	return 1;
26400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
26500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
266181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void hashlimit_init(struct xt_entry_match *m)
26700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
26800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
26900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
27000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	r->cfg.burst = XT_HASHLIMIT_BURST;
27100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
27200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
27300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
27400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
2759a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void hashlimit_mt4_init(struct xt_entry_match *match)
2769a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
2779a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
2789a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
2799a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.mode        = 0;
2809a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.burst       = XT_HASHLIMIT_BURST;
2819a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
2829a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.srcmask     = 32;
2839a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.dstmask     = 32;
2849a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
2859a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
2869a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void hashlimit_mt6_init(struct xt_entry_match *match)
2879a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
2889a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
2899a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
2909a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.mode        = 0;
2919a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.burst       = XT_HASHLIMIT_BURST;
2929a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
2939a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.srcmask     = 128;
2949a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	info->cfg.dstmask     = 128;
2959a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
29600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
29700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy/* Parse a 'mode' parameter into the required bitmask */
298fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtstatic int parse_mode(uint32_t *mode, const char *option_arg)
29900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
30000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	char *tok;
301dbb77543ad6afe29e9a1881b2d4fc212de621a55Jan Engelhardt	char *arg = strdup(option_arg);
30200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
30300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (!arg)
30400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		return -1;
30500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
30600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	for (tok = strtok(arg, ",|");
30700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	     tok;
30800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	     tok = strtok(NULL, ",|")) {
30900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (!strcmp(tok, "dstip"))
3109a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt			*mode |= XT_HASHLIMIT_HASH_DIP;
31100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else if (!strcmp(tok, "srcip"))
3129a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt			*mode |= XT_HASHLIMIT_HASH_SIP;
31300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else if (!strcmp(tok, "srcport"))
3149a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt			*mode |= XT_HASHLIMIT_HASH_SPT;
31500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else if (!strcmp(tok, "dstport"))
3169a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt			*mode |= XT_HASHLIMIT_HASH_DPT;
31700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		else {
31800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			free(arg);
31900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			return -1;
32000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		}
32100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
32200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	free(arg);
32300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	return 0;
32400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
32500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
326fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtstatic void hashlimit_parse(struct xt_option_call *cb)
32700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
328fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	struct xt_hashlimit_info *info = cb->data;
32900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
330fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	xtables_option_parse(cb);
331fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	switch (cb->entry->id) {
332fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_UPTO:
33368146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
334fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
335fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			          "--hashlimit-upto", cb->arg);
33600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		break;
337fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_MODE:
338fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
339fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
340fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			          "--hashlimit-mode", cb->arg);
34100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		break;
34200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
34300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
34400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
345fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtstatic void hashlimit_mt_parse(struct xt_option_call *cb)
3469a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
347fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	struct xt_hashlimit_mtinfo1 *info = cb->data;
3489a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
349fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	xtables_option_parse(cb);
350fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	switch (cb->entry->id) {
351abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	case O_BURST:
352abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		info->cfg.burst = parse_burst(cb->arg, info);
353abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		break;
354fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_UPTO:
355fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		if (cb->invert)
3569a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt			info->cfg.mode |= XT_HASHLIMIT_INVERT;
357abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
358abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			info->cfg.mode |= XT_HASHLIMIT_BYTES;
359abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
360a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
361fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			          "--hashlimit-upto", cb->arg);
362fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		break;
363fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_ABOVE:
364fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		if (!cb->invert)
3659a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt			info->cfg.mode |= XT_HASHLIMIT_INVERT;
366abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
367abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			info->cfg.mode |= XT_HASHLIMIT_BYTES;
368abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
369a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
370fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			          "--hashlimit-above", cb->arg);
371fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		break;
372fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_MODE:
373fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
374a41545ca7cde43e0ba53260ba74bd9bf74025a68Jan Engelhardt			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
375fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt			          "--hashlimit-mode", cb->arg);
376fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		break;
377fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_SRCMASK:
378fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		info->cfg.srcmask = cb->val.hlen;
379fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		break;
380fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	case O_DSTMASK:
381fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		info->cfg.dstmask = cb->val.hlen;
382fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		break;
3839a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	}
3849a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
3859a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
386fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardtstatic void hashlimit_check(struct xt_fcheck_call *cb)
38700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
38868146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	const struct hashlimit_mt_udata *udata = cb->udata;
38968146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	struct xt_hashlimit_info *info = cb->data;
39068146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt
391fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
3921829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
39300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy				"You have to specify --hashlimit");
39468146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	if (!(cb->xflags & F_HTABLE_EXPIRE))
395c148c4ad2e28b94125c0c9954a887f0a473d598bJan Engelhardt		info->cfg.expire = udata->mult * 1000; /* from s to msec */
39668146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt}
39768146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt
39868146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardtstatic void hashlimit_mt_check(struct xt_fcheck_call *cb)
39968146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt{
40068146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	const struct hashlimit_mt_udata *udata = cb->udata;
40168146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	struct xt_hashlimit_mtinfo1 *info = cb->data;
40268146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt
40368146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
40468146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
40568146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt				"You have to specify --hashlimit");
40668146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt	if (!(cb->xflags & F_HTABLE_EXPIRE))
407c148c4ad2e28b94125c0c9954a887f0a473d598bJan Engelhardt		info->cfg.expire = udata->mult * 1000; /* from s to msec */
408abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
409abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
410abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		uint32_t burst = 0;
411abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		if (cb->xflags & F_BURST) {
412abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
413abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal				xtables_error(PARAMETER_PROBLEM,
414abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal					"burst cannot be smaller than %ub", cost_to_bytes(info->cfg.avg));
415abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
416abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			burst = info->cfg.burst;
417abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			burst /= cost_to_bytes(info->cfg.avg);
418abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
419abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal				burst++;
420abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			if (!(cb->xflags & F_HTABLE_EXPIRE))
421abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal				info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
422abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		}
423abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		info->cfg.burst = burst;
424abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	} else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
425abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		burst_error();
4269a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
4279a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
4280e2abed11985e16215559cefd90625f99317b96cJan Engelhardtstatic const struct rates
42900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
43000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	const char *name;
4317ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardt	uint32_t mult;
43200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
43300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	      { "hour", XT_HASHLIMIT_SCALE*60*60 },
43400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	      { "min", XT_HASHLIMIT_SCALE*60 },
43500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	      { "sec", XT_HASHLIMIT_SCALE } };
43600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
4374a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardtstatic uint32_t print_rate(uint32_t period)
43800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
43900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	unsigned int i;
44000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
4419d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt	if (period == 0) {
4429d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		printf(" %f", INFINITY);
4439d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt		return 0;
4449d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt	}
4459d69da4bdb1d546218d168b72f12ac8aa042e3d8Jan Engelhardt
4462c69b55e55f2efc5a334b87ccdceaa9de0ecb658Jan Engelhardt	for (i = 1; i < ARRAY_SIZE(rates); ++i)
44700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (period > rates[i].mult
44800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy            || rates[i].mult/period < rates[i].mult%period)
44900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			break;
45000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
45173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
4524a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	/* return in msec */
4534a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	return rates[i-1].mult / XT_HASHLIMIT_SCALE * 1000;
45400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
45500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
456abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic const struct {
457abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	const char *name;
458abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	uint32_t thresh;
459abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal} units[] = {
460abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	{ "m", 1024 * 1024 },
461abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	{ "k", 1024 },
462abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	{ "", 1 },
463abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal};
464abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
465abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphalstatic uint32_t print_bytes(uint32_t avg, uint32_t burst, const char *prefix)
466abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal{
467abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	unsigned int i;
468abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	unsigned long long r;
469abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
470abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	r = cost_to_bytes(avg);
471abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
472abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
473abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		if (r >= units[i].thresh &&
474abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		    bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
475abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			break;
476abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
477abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
478abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (burst == 0)
479abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
480abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
481abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	r *= burst;
482abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	printf(" %s", prefix);
483abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
484abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		if (r >= units[i].thresh)
485abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal			break;
486abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
487abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	printf("burst %llu%sb", r / units[i].thresh, units[i].name);
488abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
489abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal}
490abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
4919a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void print_mode(unsigned int mode, char separator)
49200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
4939a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	bool prevmode = false;
49400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
49573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	putchar(' ');
4969a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (mode & XT_HASHLIMIT_HASH_SIP) {
49700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		fputs("srcip", stdout);
49800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		prevmode = 1;
49900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
5009a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (mode & XT_HASHLIMIT_HASH_SPT) {
50100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (prevmode)
50200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			putchar(separator);
50300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		fputs("srcport", stdout);
50400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		prevmode = 1;
50500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
5069a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (mode & XT_HASHLIMIT_HASH_DIP) {
50700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (prevmode)
50800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			putchar(separator);
50900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		fputs("dstip", stdout);
51000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		prevmode = 1;
51100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
5129a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (mode & XT_HASHLIMIT_HASH_DPT) {
51300524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		if (prevmode)
51400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy			putchar(separator);
51500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy		fputs("dstport", stdout);
51600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	}
51700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
51800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
519181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void hashlimit_print(const void *ip,
520181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt                            const struct xt_entry_match *match, int numeric)
52100524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
52269f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt	const struct xt_hashlimit_info *r = (const void *)match->data;
5234a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	uint32_t quantum;
5244a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt
5254a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	fputs(" limit: avg", stdout);
5264a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	quantum = print_rate(r->cfg.avg);
52773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" burst %u", r->cfg.burst);
52873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	fputs(" mode", stdout);
5299a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	print_mode(r->cfg.mode, '-');
53000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (r->cfg.size)
53173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-size %u", r->cfg.size);
53200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (r->cfg.max)
53373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-max %u", r->cfg.max);
53400524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
53573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-gcinterval %u", r->cfg.gc_interval);
5364a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	if (r->cfg.expire != quantum)
53773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-expire %u", r->cfg.expire);
53800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
53900524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
5409a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void
5419a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardthashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
5429a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
5434a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	uint32_t quantum;
5444a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt
5459a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.mode & XT_HASHLIMIT_INVERT)
54673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(" limit: above", stdout);
5479a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	else
54873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(" limit: up to", stdout);
549abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
550abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
551abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		quantum = print_bytes(info->cfg.avg, info->cfg.burst, "");
552abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	} else {
553abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		quantum = print_rate(info->cfg.avg);
554abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		printf(" burst %u", info->cfg.burst);
555abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	}
5569a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
5579a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
55873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(" mode", stdout);
5599a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt		print_mode(info->cfg.mode, '-');
5609a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	}
5619a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.size != 0)
56273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-size %u", info->cfg.size);
5639a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.max != 0)
56473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-max %u", info->cfg.max);
5659a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
56673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-gcinterval %u", info->cfg.gc_interval);
5674a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	if (info->cfg.expire != quantum)
56873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" htable-expire %u", info->cfg.expire);
5699a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
5709a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.srcmask != dmask)
57173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" srcmask %u", info->cfg.srcmask);
5729a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.dstmask != dmask)
57373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" dstmask %u", info->cfg.dstmask);
5749a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
5759a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
5769a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void
5779a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardthashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
5789a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt                   int numeric)
5799a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
5809a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
5819a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
5829a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	hashlimit_mt_print(info, 32);
5839a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
5849a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
5859a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void
5869a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardthashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
5879a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt                   int numeric)
5889a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
5899a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
5909a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
5919a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	hashlimit_mt_print(info, 128);
5929a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
5939a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
594181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void hashlimit_save(const void *ip, const struct xt_entry_match *match)
59500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
59669f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt	const struct xt_hashlimit_info *r = (const void *)match->data;
5974a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	uint32_t quantum;
59800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
5994a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	fputs(" --hashlimit", stdout);
6004a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	quantum = print_rate(r->cfg.avg);
60173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" --hashlimit-burst %u", r->cfg.burst);
60200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
60373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	fputs(" --hashlimit-mode", stdout);
6049a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	print_mode(r->cfg.mode, ',');
605abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
60673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" --hashlimit-name %s", r->name);
60700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
60800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (r->cfg.size)
60973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-size %u", r->cfg.size);
61000524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (r->cfg.max)
61173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-max %u", r->cfg.max);
61200524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
61373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
6144a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	if (r->cfg.expire != quantum)
61573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-expire %u", r->cfg.expire);
61600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
61700524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy
6189a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void
6199a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardthashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
6209a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
6214a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	uint32_t quantum;
6224a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt
6239a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.mode & XT_HASHLIMIT_INVERT)
62473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(" --hashlimit-above", stdout);
6259a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	else
62673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(" --hashlimit-upto", stdout);
627abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal
628abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
629abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		quantum = print_bytes(info->cfg.avg, info->cfg.burst, "--hashlimit-");
630abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	} else {
631abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		quantum = print_rate(info->cfg.avg);
632abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal		printf(" --hashlimit-burst %u", info->cfg.burst);
633abdef13f36b63758f8775eb86febd96bf062df6fFlorian Westphal	}
6349a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6359a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
6369a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
63773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		fputs(" --hashlimit-mode", stdout);
6389a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt		print_mode(info->cfg.mode, ',');
6399a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	}
6409a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
64173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" --hashlimit-name %s", info->name);
6429a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6439a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.size != 0)
64473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-size %u", info->cfg.size);
6459a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.max != 0)
64673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-max %u", info->cfg.max);
6479a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
64873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
6494a56bcbd49ef20a0203017c15ab1cec9bb140d1aJan Engelhardt	if (info->cfg.expire != quantum)
65073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-htable-expire %u", info->cfg.expire);
6519a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6529a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.srcmask != dmask)
65373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
6549a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	if (info->cfg.dstmask != dmask)
65573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
6569a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
6579a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6589a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void
6599a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardthashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
6609a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
6619a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
6629a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6639a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	hashlimit_mt_save(info, 32);
6649a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
6659a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6669a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardtstatic void
6679a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardthashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
6689a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt{
6699a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
6709a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
6719a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt	hashlimit_mt_save(info, 128);
6729a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt}
6739a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
674f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardtstatic struct xtables_match hashlimit_mt_reg[] = {
675f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
676f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_UNSPEC,
677f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "hashlimit",
678f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
679f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 0,
680f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
681f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
682f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = hashlimit_help,
683f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = hashlimit_init,
684fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		.x6_parse      = hashlimit_parse,
685fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		.x6_fcheck     = hashlimit_check,
686f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = hashlimit_print,
687f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = hashlimit_save,
688de1f06dca906bfcb82d7c7c2d555fbf3229d12b6Jan Engelhardt		.x6_options    = hashlimit_opts,
68968146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		.udata_size    = sizeof(struct hashlimit_mt_udata),
690f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
691f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
692f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
693f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "hashlimit",
694f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 1,
695f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_IPV4,
696f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
697f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
698f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = hashlimit_mt_help,
699f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = hashlimit_mt4_init,
700fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		.x6_parse      = hashlimit_mt_parse,
70168146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		.x6_fcheck     = hashlimit_mt_check,
702f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = hashlimit_mt4_print,
703f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = hashlimit_mt4_save,
704fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		.x6_options    = hashlimit_mt_opts,
70568146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		.udata_size    = sizeof(struct hashlimit_mt_udata),
706f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
707f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	{
708f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.version       = XTABLES_VERSION,
709f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.name          = "hashlimit",
710f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.revision      = 1,
711f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.family        = NFPROTO_IPV6,
712f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
713f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
714f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.help          = hashlimit_mt_help,
715f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.init          = hashlimit_mt6_init,
716fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		.x6_parse      = hashlimit_mt_parse,
71768146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		.x6_fcheck     = hashlimit_mt_check,
718f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.print         = hashlimit_mt6_print,
719f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt		.save          = hashlimit_mt6_save,
720fe02f76e013941a7f65f57f297d3177bcfeb0623Jan Engelhardt		.x6_options    = hashlimit_mt_opts,
72168146dad91611bd8d6d12c8ba27219130d99607bJan Engelhardt		.udata_size    = sizeof(struct hashlimit_mt_udata),
722f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	},
7239a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt};
7249a8c77fc8df3155747c34dcea79b7834a2a9a40aJan Engelhardt
72500524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardyvoid _init(void)
72600524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy{
727f2a77520693f0a6dd1df1f87be4b81913961c1f5Jan Engelhardt	xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
72800524b27b5e442d27414cf48e0d6e6372b6113aePatrick McHardy}
729