Blame extensions/libxt_hashlimit.c

Packit 7b22a4
/* ip6tables match extension for limiting packets per destination
Packit 7b22a4
 *
Packit 7b22a4
 * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
Packit 7b22a4
 *
Packit 7b22a4
 * Development of this code was funded by Astaro AG, http://www.astaro.com/
Packit 7b22a4
 *
Packit 7b22a4
 * Based on ipt_limit.c by
Packit 7b22a4
 * Jérôme de Vivie   <devivie@info.enserb.u-bordeaux.fr>
Packit 7b22a4
 * Hervé Eychenne    <rv@wallfire.org>
Packit 7b22a4
 *
Packit 7b22a4
 * Error corections by nmalykh@bilim.com (22.01.2005)
Packit 7b22a4
 */
Packit 7b22a4
#define _BSD_SOURCE 1
Packit 7b22a4
#define _DEFAULT_SOURCE 1
Packit 7b22a4
#define _ISOC99_SOURCE 1
Packit 7b22a4
#include <inttypes.h>
Packit 7b22a4
#include <math.h>
Packit 7b22a4
#include <stdbool.h>
Packit 7b22a4
#include <stdio.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <stdlib.h>
Packit 7b22a4
#include <errno.h>
Packit 7b22a4
#include <xtables.h>
Packit 7b22a4
#include <linux/netfilter/x_tables.h>
Packit 7b22a4
#include <linux/netfilter/xt_hashlimit.h>
Packit 7b22a4
Packit 7b22a4
#define XT_HASHLIMIT_BURST	5
Packit 7b22a4
#define XT_HASHLIMIT_BURST_MAX_v1	10000
Packit 7b22a4
#define XT_HASHLIMIT_BURST_MAX		1000000
Packit 7b22a4
Packit 7b22a4
#define XT_HASHLIMIT_BYTE_EXPIRE	15
Packit 7b22a4
#define XT_HASHLIMIT_BYTE_EXPIRE_BURST	60
Packit 7b22a4
Packit 7b22a4
/* miliseconds */
Packit 7b22a4
#define XT_HASHLIMIT_GCINTERVAL	1000
Packit 7b22a4
Packit 7b22a4
struct hashlimit_mt_udata {
Packit 7b22a4
	uint32_t mult;
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void hashlimit_help(void)
Packit 7b22a4
{
Packit 7b22a4
	printf(
Packit 7b22a4
"hashlimit match options:\n"
Packit 7b22a4
"--hashlimit <avg>		max average match rate\n"
Packit 7b22a4
"                                [Packets per second unless followed by \n"
Packit 7b22a4
"                                /sec /minute /hour /day postfixes]\n"
Packit 7b22a4
"--hashlimit-mode <mode>		mode is a comma-separated list of\n"
Packit 7b22a4
"					dstip,srcip,dstport,srcport\n"
Packit 7b22a4
"--hashlimit-name <name>		name for /proc/net/ipt_hashlimit/\n"
Packit 7b22a4
"[--hashlimit-burst <num>]	number to match in a burst, default %u\n"
Packit 7b22a4
"[--hashlimit-htable-size <num>]	number of hashtable buckets\n"
Packit 7b22a4
"[--hashlimit-htable-max <num>]	number of hashtable entries\n"
Packit 7b22a4
"[--hashlimit-htable-gcinterval]	interval between garbage collection runs\n"
Packit 7b22a4
"[--hashlimit-htable-expire]	after which time are idle entries expired?\n",
Packit 7b22a4
XT_HASHLIMIT_BURST);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
enum {
Packit 7b22a4
	O_UPTO = 0,
Packit 7b22a4
	O_ABOVE,
Packit 7b22a4
	O_LIMIT,
Packit 7b22a4
	O_MODE,
Packit 7b22a4
	O_SRCMASK,
Packit 7b22a4
	O_DSTMASK,
Packit 7b22a4
	O_NAME,
Packit 7b22a4
	O_BURST,
Packit 7b22a4
	O_HTABLE_SIZE,
Packit 7b22a4
	O_HTABLE_MAX,
Packit 7b22a4
	O_HTABLE_GCINT,
Packit 7b22a4
	O_HTABLE_EXPIRE,
Packit 7b22a4
	O_RATEMATCH,
Packit 7b22a4
	O_INTERVAL,
Packit 7b22a4
	F_BURST         = 1 << O_BURST,
Packit 7b22a4
	F_UPTO          = 1 << O_UPTO,
Packit 7b22a4
	F_ABOVE         = 1 << O_ABOVE,
Packit 7b22a4
	F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
Packit 7b22a4
	F_RATEMATCH	= 1 << O_RATEMATCH,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_help(void)
Packit 7b22a4
{
Packit 7b22a4
	printf(
Packit 7b22a4
"hashlimit match options:\n"
Packit 7b22a4
"  --hashlimit-upto <avg>           max average match rate\n"
Packit 7b22a4
"                                   [Packets per second unless followed by \n"
Packit 7b22a4
"                                   /sec /minute /hour /day postfixes]\n"
Packit 7b22a4
"  --hashlimit-above <avg>          min average match rate\n"
Packit 7b22a4
"  --hashlimit-mode <mode>          mode is a comma-separated list of\n"
Packit 7b22a4
"                                   dstip,srcip,dstport,srcport (or none)\n"
Packit 7b22a4
"  --hashlimit-srcmask <length>     source address grouping prefix length\n"
Packit 7b22a4
"  --hashlimit-dstmask <length>     destination address grouping prefix length\n"
Packit 7b22a4
"  --hashlimit-name <name>          name for /proc/net/ipt_hashlimit\n"
Packit 7b22a4
"  --hashlimit-burst <num>	    number to match in a burst, default %u\n"
Packit 7b22a4
"  --hashlimit-htable-size <num>    number of hashtable buckets\n"
Packit 7b22a4
"  --hashlimit-htable-max <num>     number of hashtable entries\n"
Packit 7b22a4
"  --hashlimit-htable-gcinterval    interval between garbage collection runs\n"
Packit 7b22a4
"  --hashlimit-htable-expire        after which time are idle entries expired?\n"
Packit 7b22a4
"\n", XT_HASHLIMIT_BURST);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_help_v3(void)
Packit 7b22a4
{
Packit 7b22a4
	printf(
Packit 7b22a4
"hashlimit match options:\n"
Packit 7b22a4
"  --hashlimit-upto <avg>           max average match rate\n"
Packit 7b22a4
"                                   [Packets per second unless followed by \n"
Packit 7b22a4
"                                   /sec /minute /hour /day postfixes]\n"
Packit 7b22a4
"  --hashlimit-above <avg>          min average match rate\n"
Packit 7b22a4
"  --hashlimit-mode <mode>          mode is a comma-separated list of\n"
Packit 7b22a4
"                                   dstip,srcip,dstport,srcport (or none)\n"
Packit 7b22a4
"  --hashlimit-srcmask <length>     source address grouping prefix length\n"
Packit 7b22a4
"  --hashlimit-dstmask <length>     destination address grouping prefix length\n"
Packit 7b22a4
"  --hashlimit-name <name>          name for /proc/net/ipt_hashlimit\n"
Packit 7b22a4
"  --hashlimit-burst <num>	    number to match in a burst, default %u\n"
Packit 7b22a4
"  --hashlimit-htable-size <num>    number of hashtable buckets\n"
Packit 7b22a4
"  --hashlimit-htable-max <num>     number of hashtable entries\n"
Packit 7b22a4
"  --hashlimit-htable-gcinterval    interval between garbage collection runs\n"
Packit 7b22a4
"  --hashlimit-htable-expire        after which time are idle entries expired?\n"
Packit 7b22a4
"  --hashlimit-rate-match           rate match the flow without rate-limiting it\n"
Packit 7b22a4
"  --hashlimit-rate-interval        interval in seconds for hashlimit-rate-match\n"
Packit 7b22a4
"\n", XT_HASHLIMIT_BURST);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
#define s struct xt_hashlimit_info
Packit 7b22a4
static const struct xt_option_entry hashlimit_opts[] = {
Packit 7b22a4
	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
Packit 7b22a4
	 .min = 1, .max = XT_HASHLIMIT_BURST_MAX_v1, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.burst)},
Packit 7b22a4
	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.size)},
Packit 7b22a4
	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.max)},
Packit 7b22a4
	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.gc_interval)},
Packit 7b22a4
	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.expire)},
Packit 7b22a4
	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_MAND},
Packit 7b22a4
	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
Packit 7b22a4
	XTOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
#undef s
Packit 7b22a4
Packit 7b22a4
#define s struct xt_hashlimit_mtinfo1
Packit 7b22a4
static const struct xt_option_entry hashlimit_mt_opts_v1[] = {
Packit 7b22a4
	{.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
Packit 7b22a4
	{.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
Packit 7b22a4
	{.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
Packit 7b22a4
	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.size)},
Packit 7b22a4
	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.max)},
Packit 7b22a4
	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.gc_interval)},
Packit 7b22a4
	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.expire)},
Packit 7b22a4
	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
Packit 7b22a4
	XTOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
#undef s
Packit 7b22a4
Packit 7b22a4
#define s struct xt_hashlimit_mtinfo2
Packit 7b22a4
static const struct xt_option_entry hashlimit_mt_opts_v2[] = {
Packit 7b22a4
	{.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
Packit 7b22a4
	{.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
Packit 7b22a4
	{.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
Packit 7b22a4
	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.size)},
Packit 7b22a4
	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.max)},
Packit 7b22a4
	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.gc_interval)},
Packit 7b22a4
	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.expire)},
Packit 7b22a4
	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
Packit 7b22a4
	XTOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
#undef s
Packit 7b22a4
Packit 7b22a4
#define s struct xt_hashlimit_mtinfo3
Packit 7b22a4
static const struct xt_option_entry hashlimit_mt_opts[] = {
Packit 7b22a4
	{.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
Packit 7b22a4
	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
Packit 7b22a4
	{.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
Packit 7b22a4
	{.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
Packit 7b22a4
	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.size)},
Packit 7b22a4
	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.max)},
Packit 7b22a4
	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.gc_interval)},
Packit 7b22a4
	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
Packit 7b22a4
	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
Packit 7b22a4
	 XTOPT_POINTER(s, cfg.expire)},
Packit 7b22a4
	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
Packit 7b22a4
	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
Packit 7b22a4
	{.name = "hashlimit-rate-match", .id = O_RATEMATCH, .type = XTTYPE_NONE},
Packit 7b22a4
	{.name = "hashlimit-rate-interval", .id = O_INTERVAL, .type = XTTYPE_STRING},
Packit 7b22a4
	XTOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
#undef s
Packit 7b22a4
Packit 7b22a4
static int
Packit 7b22a4
cfg_copy(struct hashlimit_cfg3 *to, const void *from, int revision)
Packit 7b22a4
{
Packit 7b22a4
	if (revision == 1) {
Packit 7b22a4
		struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from;
Packit 7b22a4
Packit 7b22a4
		to->mode = cfg->mode;
Packit 7b22a4
		to->avg = cfg->avg;
Packit 7b22a4
		to->burst = cfg->burst;
Packit 7b22a4
		to->size = cfg->size;
Packit 7b22a4
		to->max = cfg->max;
Packit 7b22a4
		to->gc_interval = cfg->gc_interval;
Packit 7b22a4
		to->expire = cfg->expire;
Packit 7b22a4
		to->srcmask = cfg->srcmask;
Packit 7b22a4
		to->dstmask = cfg->dstmask;
Packit 7b22a4
	} else if (revision == 2) {
Packit 7b22a4
		struct hashlimit_cfg2 *cfg = (struct hashlimit_cfg2 *)from;
Packit 7b22a4
Packit 7b22a4
		to->mode = cfg->mode;
Packit 7b22a4
		to->avg = cfg->avg;
Packit 7b22a4
		to->burst = cfg->burst;
Packit 7b22a4
		to->size = cfg->size;
Packit 7b22a4
		to->max = cfg->max;
Packit 7b22a4
		to->gc_interval = cfg->gc_interval;
Packit 7b22a4
		to->expire = cfg->expire;
Packit 7b22a4
		to->srcmask = cfg->srcmask;
Packit 7b22a4
		to->dstmask = cfg->dstmask;
Packit 7b22a4
	} else if (revision == 3) {
Packit 7b22a4
		memcpy(to, from, sizeof(struct hashlimit_cfg3));
Packit 7b22a4
	} else {
Packit 7b22a4
		return -EINVAL;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static uint64_t cost_to_bytes(uint64_t cost)
Packit 7b22a4
{
Packit 7b22a4
	uint64_t r;
Packit 7b22a4
Packit 7b22a4
	r = cost ? UINT32_MAX / cost : UINT32_MAX;
Packit 7b22a4
	r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
Packit 7b22a4
	return r;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static uint64_t bytes_to_cost(uint64_t bytes)
Packit 7b22a4
{
Packit 7b22a4
	uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
Packit 7b22a4
	return UINT32_MAX / (r+1);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static uint32_t get_factor(int chr)
Packit 7b22a4
{
Packit 7b22a4
	switch (chr) {
Packit 7b22a4
	case 'm': return 1024 * 1024;
Packit 7b22a4
	case 'k': return 1024;
Packit 7b22a4
	}
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void burst_error_v1(void)
Packit 7b22a4
{
Packit 7b22a4
	xtables_error(PARAMETER_PROBLEM, "bad value for option "
Packit 7b22a4
			"\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX_v1);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void burst_error(void)
Packit 7b22a4
{
Packit 7b22a4
	xtables_error(PARAMETER_PROBLEM, "bad value for option "
Packit 7b22a4
			"\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static uint64_t parse_burst(const char *burst, int revision)
Packit 7b22a4
{
Packit 7b22a4
	uintmax_t v;
Packit 7b22a4
	char *end;
Packit 7b22a4
	uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
Packit 7b22a4
	uint64_t burst_max = (revision == 1) ?
Packit 7b22a4
			      XT_HASHLIMIT_BURST_MAX_v1 : XT_HASHLIMIT_BURST_MAX;
Packit 7b22a4
Packit 7b22a4
	if (!xtables_strtoul(burst, &end, &v, 1, max) ||
Packit 7b22a4
		(*end == 0 && v > burst_max)) {
Packit 7b22a4
		if (revision == 1)
Packit 7b22a4
			burst_error_v1();
Packit 7b22a4
		else
Packit 7b22a4
			burst_error();
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	v *= get_factor(*end);
Packit 7b22a4
	if (v > max)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "bad value for option "
Packit 7b22a4
			"\"--hashlimit-burst\", value \"%s\" too large "
Packit 7b22a4
				"(max %"PRIu64"mb).", burst, max/1024/1024);
Packit 7b22a4
	return v;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int factor = 1;
Packit 7b22a4
	uint64_t tmp, r;
Packit 7b22a4
	const char *mode = strstr(rate, "b/s");
Packit 7b22a4
	uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
Packit 7b22a4
Packit 7b22a4
	if (!mode || mode == rate)
Packit 7b22a4
		return false;
Packit 7b22a4
Packit 7b22a4
	mode--;
Packit 7b22a4
	r = atoll(rate);
Packit 7b22a4
	if (r == 0)
Packit 7b22a4
		return false;
Packit 7b22a4
Packit 7b22a4
	factor = get_factor(*mode);
Packit 7b22a4
	tmp = (uint64_t) r * factor;
Packit 7b22a4
	if (tmp > max)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			"Rate value too large \"%"PRIu64"\" (max %"PRIu64")\n",
Packit 7b22a4
					tmp, max);
Packit 7b22a4
Packit 7b22a4
	tmp = bytes_to_cost(tmp);
Packit 7b22a4
	if (tmp == 0)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
Packit 7b22a4
Packit 7b22a4
	ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
Packit 7b22a4
Packit 7b22a4
	if(revision == 1)
Packit 7b22a4
		*((uint32_t*)val) = tmp;
Packit 7b22a4
	else
Packit 7b22a4
		*((uint64_t*)val) = tmp;
Packit 7b22a4
Packit 7b22a4
	return true;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static
Packit 7b22a4
int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
Packit 7b22a4
{
Packit 7b22a4
	const char *delim;
Packit 7b22a4
	uint64_t tmp, r;
Packit 7b22a4
	uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
Packit 7b22a4
Packit 7b22a4
	ud->mult = 1;  /* Seconds by default. */
Packit 7b22a4
	delim = strchr(rate, '/');
Packit 7b22a4
	if (delim) {
Packit 7b22a4
		if (strlen(delim+1) == 0)
Packit 7b22a4
			return 0;
Packit 7b22a4
Packit 7b22a4
		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
Packit 7b22a4
			ud->mult = 1;
Packit 7b22a4
		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
Packit 7b22a4
			ud->mult = 60;
Packit 7b22a4
		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
Packit 7b22a4
			ud->mult = 60*60;
Packit 7b22a4
		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
Packit 7b22a4
			ud->mult = 24*60*60;
Packit 7b22a4
		else
Packit 7b22a4
			return 0;
Packit 7b22a4
	}
Packit 7b22a4
	r = atoll(rate);
Packit 7b22a4
	if (!r)
Packit 7b22a4
		return 0;
Packit 7b22a4
Packit 7b22a4
	tmp = scale * ud->mult / r;
Packit 7b22a4
	if (tmp == 0)
Packit 7b22a4
		/*
Packit 7b22a4
		 * The rate maps to infinity. (1/day is the minimum they can
Packit 7b22a4
		 * specify, so we are ok at that end).
Packit 7b22a4
		 */
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Packit 7b22a4
Packit 7b22a4
	if(revision == 1)
Packit 7b22a4
		*((uint32_t*)val) = tmp;
Packit 7b22a4
	else
Packit 7b22a4
		*((uint64_t*)val) = tmp;
Packit 7b22a4
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int parse_interval(const char *rate, uint32_t *val)
Packit 7b22a4
{
Packit 7b22a4
	int r = atoi(rate);
Packit 7b22a4
	if (r <= 0)
Packit 7b22a4
		return 0;
Packit 7b22a4
Packit 7b22a4
	*val = r;
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_init(struct xt_entry_match *m)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
Packit 7b22a4
Packit 7b22a4
	r->cfg.burst = XT_HASHLIMIT_BURST;
Packit 7b22a4
	r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt4_init_v1(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->cfg.mode        = 0;
Packit 7b22a4
	info->cfg.burst       = XT_HASHLIMIT_BURST;
Packit 7b22a4
	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
	info->cfg.srcmask     = 32;
Packit 7b22a4
	info->cfg.dstmask     = 32;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt6_init_v1(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->cfg.mode        = 0;
Packit 7b22a4
	info->cfg.burst       = XT_HASHLIMIT_BURST;
Packit 7b22a4
	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
	info->cfg.srcmask     = 128;
Packit 7b22a4
	info->cfg.dstmask     = 128;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt4_init_v2(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->cfg.mode        = 0;
Packit 7b22a4
	info->cfg.burst       = XT_HASHLIMIT_BURST;
Packit 7b22a4
	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
	info->cfg.srcmask     = 32;
Packit 7b22a4
	info->cfg.dstmask     = 32;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt6_init_v2(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->cfg.mode        = 0;
Packit 7b22a4
	info->cfg.burst       = XT_HASHLIMIT_BURST;
Packit 7b22a4
	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
	info->cfg.srcmask     = 128;
Packit 7b22a4
	info->cfg.dstmask     = 128;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt4_init(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo3 *info = (void *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->cfg.mode        = 0;
Packit 7b22a4
	info->cfg.burst       = XT_HASHLIMIT_BURST;
Packit 7b22a4
	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
	info->cfg.srcmask     = 32;
Packit 7b22a4
	info->cfg.dstmask     = 32;
Packit 7b22a4
	info->cfg.interval    = 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt6_init(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo3 *info = (void *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->cfg.mode        = 0;
Packit 7b22a4
	info->cfg.burst       = XT_HASHLIMIT_BURST;
Packit 7b22a4
	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
Packit 7b22a4
	info->cfg.srcmask     = 128;
Packit 7b22a4
	info->cfg.dstmask     = 128;
Packit 7b22a4
	info->cfg.interval    = 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* Parse a 'mode' parameter into the required bitmask */
Packit 7b22a4
static int parse_mode(uint32_t *mode, const char *option_arg)
Packit 7b22a4
{
Packit 7b22a4
	char *tok;
Packit 7b22a4
	char *arg = strdup(option_arg);
Packit 7b22a4
Packit 7b22a4
	if (!arg)
Packit 7b22a4
		return -1;
Packit 7b22a4
Packit 7b22a4
	for (tok = strtok(arg, ",|");
Packit 7b22a4
	     tok;
Packit 7b22a4
	     tok = strtok(NULL, ",|")) {
Packit 7b22a4
		if (!strcmp(tok, "dstip"))
Packit 7b22a4
			*mode |= XT_HASHLIMIT_HASH_DIP;
Packit 7b22a4
		else if (!strcmp(tok, "srcip"))
Packit 7b22a4
			*mode |= XT_HASHLIMIT_HASH_SIP;
Packit 7b22a4
		else if (!strcmp(tok, "srcport"))
Packit 7b22a4
			*mode |= XT_HASHLIMIT_HASH_SPT;
Packit 7b22a4
		else if (!strcmp(tok, "dstport"))
Packit 7b22a4
			*mode |= XT_HASHLIMIT_HASH_DPT;
Packit 7b22a4
		else {
Packit 7b22a4
			free(arg);
Packit 7b22a4
			return -1;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	free(arg);
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_parse(struct xt_option_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_info *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	xtables_option_parse(cb);
Packit 7b22a4
	switch (cb->entry->id) {
Packit 7b22a4
	case O_UPTO:
Packit 7b22a4
		if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-upto", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_MODE:
Packit 7b22a4
		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-mode", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_parse_v1(struct xt_option_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo1 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	xtables_option_parse(cb);
Packit 7b22a4
	switch (cb->entry->id) {
Packit 7b22a4
	case O_BURST:
Packit 7b22a4
		info->cfg.burst = parse_burst(cb->arg, 1);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_UPTO:
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_INVERT;
Packit 7b22a4
		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_BYTES;
Packit 7b22a4
		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-upto", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_ABOVE:
Packit 7b22a4
		if (!cb->invert)
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_INVERT;
Packit 7b22a4
		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_BYTES;
Packit 7b22a4
		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-above", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_MODE:
Packit 7b22a4
		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-mode", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_SRCMASK:
Packit 7b22a4
		info->cfg.srcmask = cb->val.hlen;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_DSTMASK:
Packit 7b22a4
		info->cfg.dstmask = cb->val.hlen;
Packit 7b22a4
		break;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_parse_v2(struct xt_option_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo2 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	xtables_option_parse(cb);
Packit 7b22a4
	switch (cb->entry->id) {
Packit 7b22a4
	case O_BURST:
Packit 7b22a4
		info->cfg.burst = parse_burst(cb->arg, 2);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_UPTO:
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_INVERT;
Packit 7b22a4
		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_BYTES;
Packit 7b22a4
		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-upto", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_ABOVE:
Packit 7b22a4
		if (!cb->invert)
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_INVERT;
Packit 7b22a4
		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_BYTES;
Packit 7b22a4
		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-above", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_MODE:
Packit 7b22a4
		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-mode", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_SRCMASK:
Packit 7b22a4
		info->cfg.srcmask = cb->val.hlen;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_DSTMASK:
Packit 7b22a4
		info->cfg.dstmask = cb->val.hlen;
Packit 7b22a4
		break;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_parse(struct xt_option_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_hashlimit_mtinfo3 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	xtables_option_parse(cb);
Packit 7b22a4
	switch (cb->entry->id) {
Packit 7b22a4
	case O_BURST:
Packit 7b22a4
		info->cfg.burst = parse_burst(cb->arg, 2);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_UPTO:
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_INVERT;
Packit 7b22a4
		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_BYTES;
Packit 7b22a4
		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-upto", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_ABOVE:
Packit 7b22a4
		if (!cb->invert)
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_INVERT;
Packit 7b22a4
		if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			info->cfg.mode |= XT_HASHLIMIT_BYTES;
Packit 7b22a4
		else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-above", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_MODE:
Packit 7b22a4
		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
			          "--hashlimit-mode", cb->arg);
Packit 7b22a4
		break;
Packit 7b22a4
	case O_SRCMASK:
Packit 7b22a4
		info->cfg.srcmask = cb->val.hlen;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_DSTMASK:
Packit 7b22a4
		info->cfg.dstmask = cb->val.hlen;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_RATEMATCH:
Packit 7b22a4
		info->cfg.mode |= XT_HASHLIMIT_RATE_MATCH;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_INTERVAL:
Packit 7b22a4
		if (!parse_interval(cb->arg, &info->cfg.interval))
Packit 7b22a4
			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Packit 7b22a4
				"--hashlimit-rate-interval", cb->arg);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_check(struct xt_fcheck_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	const struct hashlimit_mt_udata *udata = cb->udata;
Packit 7b22a4
	struct xt_hashlimit_info *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				"You have to specify --hashlimit");
Packit 7b22a4
	if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
		info->cfg.expire = udata->mult * 1000; /* from s to msec */
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	const struct hashlimit_mt_udata *udata = cb->udata;
Packit 7b22a4
	struct xt_hashlimit_mtinfo1 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				"You have to specify --hashlimit");
Packit 7b22a4
	if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
		info->cfg.expire = udata->mult * 1000; /* from s to msec */
Packit 7b22a4
Packit 7b22a4
	if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
Packit 7b22a4
		uint32_t burst = 0;
Packit 7b22a4
		if (cb->xflags & F_BURST) {
Packit 7b22a4
			if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					"burst cannot be smaller than %"PRIu64"b",
Packit 7b22a4
					cost_to_bytes(info->cfg.avg));
Packit 7b22a4
Packit 7b22a4
			burst = info->cfg.burst;
Packit 7b22a4
			burst /= cost_to_bytes(info->cfg.avg);
Packit 7b22a4
			if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
Packit 7b22a4
				burst++;
Packit 7b22a4
			if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
				info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
Packit 7b22a4
		}
Packit 7b22a4
		info->cfg.burst = burst;
Packit 7b22a4
	} else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX_v1)
Packit 7b22a4
		burst_error_v1();
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_check_v2(struct xt_fcheck_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	const struct hashlimit_mt_udata *udata = cb->udata;
Packit 7b22a4
	struct xt_hashlimit_mtinfo2 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				"You have to specify --hashlimit");
Packit 7b22a4
	if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
		info->cfg.expire = udata->mult * 1000; /* from s to msec */
Packit 7b22a4
Packit 7b22a4
	if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
Packit 7b22a4
		uint32_t burst = 0;
Packit 7b22a4
		if (cb->xflags & F_BURST) {
Packit 7b22a4
			if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					"burst cannot be smaller than %"PRIu64"b",
Packit 7b22a4
					cost_to_bytes(info->cfg.avg));
Packit 7b22a4
Packit 7b22a4
			burst = info->cfg.burst;
Packit 7b22a4
			burst /= cost_to_bytes(info->cfg.avg);
Packit 7b22a4
			if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
Packit 7b22a4
				burst++;
Packit 7b22a4
			if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
				info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
Packit 7b22a4
		}
Packit 7b22a4
		info->cfg.burst = burst;
Packit 7b22a4
	} else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
Packit 7b22a4
		burst_error();
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_mt_check(struct xt_fcheck_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	const struct hashlimit_mt_udata *udata = cb->udata;
Packit 7b22a4
	struct xt_hashlimit_mtinfo3 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				"You have to specify --hashlimit");
Packit 7b22a4
	if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
		info->cfg.expire = udata->mult * 1000; /* from s to msec */
Packit 7b22a4
Packit 7b22a4
	if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
Packit 7b22a4
		uint32_t burst = 0;
Packit 7b22a4
		if (cb->xflags & F_BURST) {
Packit 7b22a4
			if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
Packit 7b22a4
				xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
					"burst cannot be smaller than %"PRIu64"b", cost_to_bytes(info->cfg.avg));
Packit 7b22a4
Packit 7b22a4
			burst = info->cfg.burst;
Packit 7b22a4
			burst /= cost_to_bytes(info->cfg.avg);
Packit 7b22a4
			if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
Packit 7b22a4
				burst++;
Packit 7b22a4
			if (!(cb->xflags & F_HTABLE_EXPIRE))
Packit 7b22a4
				info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
Packit 7b22a4
		}
Packit 7b22a4
		info->cfg.burst = burst;
Packit 7b22a4
	} else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
Packit 7b22a4
		burst_error();
Packit 7b22a4
Packit 7b22a4
	if (cb->xflags & F_RATEMATCH) {
Packit 7b22a4
		if (!(info->cfg.mode & XT_HASHLIMIT_BYTES))
Packit 7b22a4
			info->cfg.avg /= udata->mult;
Packit 7b22a4
Packit 7b22a4
		if (info->cfg.interval == 0) {
Packit 7b22a4
			if (info->cfg.mode & XT_HASHLIMIT_BYTES)
Packit 7b22a4
				info->cfg.interval = 1;
Packit 7b22a4
			else
Packit 7b22a4
				info->cfg.interval = udata->mult;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
struct rates {
Packit 7b22a4
	const char *name;
Packit 7b22a4
	uint64_t mult;
Packit 7b22a4
} rates_v1[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
Packit 7b22a4
		 { "hour", XT_HASHLIMIT_SCALE*60*60 },
Packit 7b22a4
		 { "min", XT_HASHLIMIT_SCALE*60 },
Packit 7b22a4
		 { "sec", XT_HASHLIMIT_SCALE } };
Packit 7b22a4
Packit 7b22a4
static const struct rates rates[] = {
Packit 7b22a4
	{ "day", XT_HASHLIMIT_SCALE_v2*24*60*60 },
Packit 7b22a4
	{ "hour", XT_HASHLIMIT_SCALE_v2*60*60 },
Packit 7b22a4
	{ "min", XT_HASHLIMIT_SCALE_v2*60 },
Packit 7b22a4
	{ "sec", XT_HASHLIMIT_SCALE_v2 } };
Packit 7b22a4
Packit 7b22a4
static uint32_t print_rate(uint64_t period, int revision)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
	const struct rates *_rates = (revision == 1) ? rates_v1 : rates;
Packit 7b22a4
	uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
Packit 7b22a4
Packit 7b22a4
	if (period == 0) {
Packit 7b22a4
		printf(" %f", INFINITY);
Packit 7b22a4
		return 0;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (i = 1; i < ARRAY_SIZE(rates); ++i)
Packit 7b22a4
		if (period > _rates[i].mult
Packit 7b22a4
            || _rates[i].mult/period < _rates[i].mult%period)
Packit 7b22a4
			break;
Packit 7b22a4
Packit 7b22a4
	printf(" %"PRIu64"/%s", _rates[i-1].mult / period, _rates[i-1].name);
Packit 7b22a4
	/* return in msec */
Packit 7b22a4
	return _rates[i-1].mult / scale * 1000;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const struct {
Packit 7b22a4
	const char *name;
Packit 7b22a4
	uint32_t thresh;
Packit 7b22a4
} units[] = {
Packit 7b22a4
	{ "m", 1024 * 1024 },
Packit 7b22a4
	{ "k", 1024 },
Packit 7b22a4
	{ "", 1 },
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static uint32_t print_bytes(uint64_t avg, uint64_t burst, const char *prefix)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
	unsigned long long r;
Packit 7b22a4
Packit 7b22a4
	r = cost_to_bytes(avg);
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
Packit 7b22a4
		if (r >= units[i].thresh &&
Packit 7b22a4
		    bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
Packit 7b22a4
			break;
Packit 7b22a4
	printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
Packit 7b22a4
Packit 7b22a4
	if (burst == 0)
Packit 7b22a4
		return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
Packit 7b22a4
Packit 7b22a4
	r *= burst;
Packit 7b22a4
	printf(" %s", prefix);
Packit 7b22a4
	for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
Packit 7b22a4
		if (r >= units[i].thresh)
Packit 7b22a4
			break;
Packit 7b22a4
Packit 7b22a4
	printf("burst %llu%sb", r / units[i].thresh, units[i].name);
Packit 7b22a4
	return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void print_mode(unsigned int mode, char separator)
Packit 7b22a4
{
Packit 7b22a4
	bool prevmode = false;
Packit 7b22a4
Packit 7b22a4
	putchar(' ');
Packit 7b22a4
	if (mode & XT_HASHLIMIT_HASH_SIP) {
Packit 7b22a4
		fputs("srcip", stdout);
Packit 7b22a4
		prevmode = 1;
Packit 7b22a4
	}
Packit 7b22a4
	if (mode & XT_HASHLIMIT_HASH_SPT) {
Packit 7b22a4
		if (prevmode)
Packit 7b22a4
			putchar(separator);
Packit 7b22a4
		fputs("srcport", stdout);
Packit 7b22a4
		prevmode = 1;
Packit 7b22a4
	}
Packit 7b22a4
	if (mode & XT_HASHLIMIT_HASH_DIP) {
Packit 7b22a4
		if (prevmode)
Packit 7b22a4
			putchar(separator);
Packit 7b22a4
		fputs("dstip", stdout);
Packit 7b22a4
		prevmode = 1;
Packit 7b22a4
	}
Packit 7b22a4
	if (mode & XT_HASHLIMIT_HASH_DPT) {
Packit 7b22a4
		if (prevmode)
Packit 7b22a4
			putchar(separator);
Packit 7b22a4
		fputs("dstport", stdout);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_print(const void *ip,
Packit 7b22a4
                            const struct xt_entry_match *match, int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_info *r = (const void *)match->data;
Packit 7b22a4
	uint32_t quantum;
Packit 7b22a4
Packit 7b22a4
	fputs(" limit: avg", stdout);
Packit 7b22a4
	quantum = print_rate(r->cfg.avg, 1);
Packit 7b22a4
	printf(" burst %u", r->cfg.burst);
Packit 7b22a4
	fputs(" mode", stdout);
Packit 7b22a4
	print_mode(r->cfg.mode, '-');
Packit 7b22a4
	if (r->cfg.size)
Packit 7b22a4
		printf(" htable-size %u", r->cfg.size);
Packit 7b22a4
	if (r->cfg.max)
Packit 7b22a4
		printf(" htable-max %u", r->cfg.max);
Packit 7b22a4
	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Packit 7b22a4
		printf(" htable-gcinterval %u", r->cfg.gc_interval);
Packit 7b22a4
	if (r->cfg.expire != quantum)
Packit 7b22a4
		printf(" htable-expire %u", r->cfg.expire);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt_print(const struct hashlimit_cfg3 *cfg, unsigned int dmask, int revision)
Packit 7b22a4
{
Packit 7b22a4
	uint64_t quantum;
Packit 7b22a4
	uint64_t period;
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & XT_HASHLIMIT_INVERT)
Packit 7b22a4
		fputs(" limit: above", stdout);
Packit 7b22a4
	else
Packit 7b22a4
		fputs(" limit: up to", stdout);
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & XT_HASHLIMIT_BYTES) {
Packit 7b22a4
		quantum = print_bytes(cfg->avg, cfg->burst, "");
Packit 7b22a4
	} else {
Packit 7b22a4
		if (revision == 3) {
Packit 7b22a4
			period = cfg->avg;
Packit 7b22a4
			if (cfg->interval != 0)
Packit 7b22a4
				period *= cfg->interval;
Packit 7b22a4
Packit 7b22a4
			quantum = print_rate(period, revision);
Packit 7b22a4
		} else {
Packit 7b22a4
			quantum = print_rate(cfg->avg, revision);
Packit 7b22a4
		}
Packit 7b22a4
		printf(" burst %llu", cfg->burst);
Packit 7b22a4
	}
Packit 7b22a4
	if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
Packit 7b22a4
	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
Packit 7b22a4
		fputs(" mode", stdout);
Packit 7b22a4
		print_mode(cfg->mode, '-');
Packit 7b22a4
	}
Packit 7b22a4
	if (cfg->size != 0)
Packit 7b22a4
		printf(" htable-size %u", cfg->size);
Packit 7b22a4
	if (cfg->max != 0)
Packit 7b22a4
		printf(" htable-max %u", cfg->max);
Packit 7b22a4
	if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
Packit 7b22a4
		printf(" htable-gcinterval %u", cfg->gc_interval);
Packit 7b22a4
	if (cfg->expire != quantum)
Packit 7b22a4
		printf(" htable-expire %u", cfg->expire);
Packit 7b22a4
Packit 7b22a4
	if (cfg->srcmask != dmask)
Packit 7b22a4
		printf(" srcmask %u", cfg->srcmask);
Packit 7b22a4
	if (cfg->dstmask != dmask)
Packit 7b22a4
		printf(" dstmask %u", cfg->dstmask);
Packit 7b22a4
Packit 7b22a4
	if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
Packit 7b22a4
		printf(" rate-match");
Packit 7b22a4
Packit 7b22a4
	if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
Packit 7b22a4
		if (cfg->interval != 1)
Packit 7b22a4
			printf(" rate-interval %u", cfg->interval);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                   int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_print(&cfg, 32, 1);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                   int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_print(&cfg, 128, 1);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt4_print_v2(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                   int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_print(&cfg, 32, 2);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt6_print_v2(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                   int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_print(&cfg, 128, 2);
Packit 7b22a4
}
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                   int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_print(&info->cfg, 32, 3);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                   int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_print(&info->cfg, 128, 3);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_info *r = (const void *)match->data;
Packit 7b22a4
	uint32_t quantum;
Packit 7b22a4
Packit 7b22a4
	fputs(" --hashlimit", stdout);
Packit 7b22a4
	quantum = print_rate(r->cfg.avg, 1);
Packit 7b22a4
	printf(" --hashlimit-burst %u", r->cfg.burst);
Packit 7b22a4
Packit 7b22a4
	fputs(" --hashlimit-mode", stdout);
Packit 7b22a4
	print_mode(r->cfg.mode, ',');
Packit 7b22a4
Packit 7b22a4
	printf(" --hashlimit-name %s", r->name);
Packit 7b22a4
Packit 7b22a4
	if (r->cfg.size)
Packit 7b22a4
		printf(" --hashlimit-htable-size %u", r->cfg.size);
Packit 7b22a4
	if (r->cfg.max)
Packit 7b22a4
		printf(" --hashlimit-htable-max %u", r->cfg.max);
Packit 7b22a4
	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Packit 7b22a4
		printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
Packit 7b22a4
	if (r->cfg.expire != quantum)
Packit 7b22a4
		printf(" --hashlimit-htable-expire %u", r->cfg.expire);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt_save(const struct hashlimit_cfg3 *cfg, const char* name, unsigned int dmask, int revision)
Packit 7b22a4
{
Packit 7b22a4
	uint32_t quantum;
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & XT_HASHLIMIT_INVERT)
Packit 7b22a4
		fputs(" --hashlimit-above", stdout);
Packit 7b22a4
	else
Packit 7b22a4
		fputs(" --hashlimit-upto", stdout);
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & XT_HASHLIMIT_BYTES) {
Packit 7b22a4
		quantum = print_bytes(cfg->avg, cfg->burst, "--hashlimit-");
Packit 7b22a4
	} else {
Packit 7b22a4
		quantum = print_rate(cfg->avg, revision);
Packit 7b22a4
		printf(" --hashlimit-burst %llu", cfg->burst);
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
Packit 7b22a4
	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
Packit 7b22a4
		fputs(" --hashlimit-mode", stdout);
Packit 7b22a4
		print_mode(cfg->mode, ',');
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	printf(" --hashlimit-name %s", name);
Packit 7b22a4
Packit 7b22a4
	if (cfg->size != 0)
Packit 7b22a4
		printf(" --hashlimit-htable-size %u", cfg->size);
Packit 7b22a4
	if (cfg->max != 0)
Packit 7b22a4
		printf(" --hashlimit-htable-max %u", cfg->max);
Packit 7b22a4
	if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
Packit 7b22a4
		printf(" --hashlimit-htable-gcinterval %u", cfg->gc_interval);
Packit 7b22a4
	if (cfg->expire != quantum)
Packit 7b22a4
		printf(" --hashlimit-htable-expire %u", cfg->expire);
Packit 7b22a4
Packit 7b22a4
	if (cfg->srcmask != dmask)
Packit 7b22a4
		printf(" --hashlimit-srcmask %u", cfg->srcmask);
Packit 7b22a4
	if (cfg->dstmask != dmask)
Packit 7b22a4
		printf(" --hashlimit-dstmask %u", cfg->dstmask);
Packit 7b22a4
Packit 7b22a4
	if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
Packit 7b22a4
		printf(" --hashlimit-rate-match");
Packit 7b22a4
Packit 7b22a4
	if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
Packit 7b22a4
		if (cfg->interval != 1)
Packit 7b22a4
			printf(" --hashlimit-rate-interval %u", cfg->interval);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_save(&cfg, info->name, 32, 1);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_save(&cfg, info->name, 128, 1);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt4_save_v2(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_save(&cfg, info->name, 32, 2);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt6_save_v2(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
	int ret;
Packit 7b22a4
Packit 7b22a4
	ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
Packit 7b22a4
Packit 7b22a4
	if (ret)
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_save(&cfg, info->name, 128, 2);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_save(&info->cfg, info->name, 32, 3);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	hashlimit_mt_save(&info->cfg, info->name, 128, 3);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const struct rates rates_v1_xlate[] = {
Packit 7b22a4
	{ "day", XT_HASHLIMIT_SCALE * 24 * 60 * 60 },
Packit 7b22a4
	{ "hour", XT_HASHLIMIT_SCALE * 60 * 60 },
Packit 7b22a4
	{ "minute", XT_HASHLIMIT_SCALE * 60 },
Packit 7b22a4
	{ "second", XT_HASHLIMIT_SCALE } };
Packit 7b22a4
Packit 7b22a4
static const struct rates rates_xlate[] = {
Packit 7b22a4
	{ "day", XT_HASHLIMIT_SCALE_v2 * 24 * 60 * 60 },
Packit 7b22a4
	{ "hour", XT_HASHLIMIT_SCALE_v2 * 60 * 60 },
Packit 7b22a4
	{ "minute", XT_HASHLIMIT_SCALE_v2 * 60 },
Packit 7b22a4
	{ "second", XT_HASHLIMIT_SCALE_v2 } };
Packit 7b22a4
Packit 7b22a4
static void print_packets_rate_xlate(struct xt_xlate *xl, uint64_t avg,
Packit 7b22a4
				     int revision)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
	const struct rates *_rates = (revision == 1) ?
Packit 7b22a4
		rates_v1_xlate : rates_xlate;
Packit 7b22a4
Packit 7b22a4
	for (i = 1; i < ARRAY_SIZE(rates); ++i)
Packit 7b22a4
		if (avg > _rates[i].mult ||
Packit 7b22a4
		    _rates[i].mult / avg < _rates[i].mult % avg)
Packit 7b22a4
			break;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, " %" PRIu64 "/%s ",
Packit 7b22a4
		     _rates[i-1].mult / avg, _rates[i-1].name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void print_bytes_rate_xlate(struct xt_xlate *xl,
Packit 7b22a4
				   const struct hashlimit_cfg3 *cfg)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
	unsigned long long r;
Packit 7b22a4
Packit 7b22a4
	r = cost_to_bytes(cfg->avg);
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
Packit 7b22a4
		if (r >= units[i].thresh &&
Packit 7b22a4
		    bytes_to_cost(r & ~(units[i].thresh - 1)) == cfg->avg)
Packit 7b22a4
			break;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, " %llu %sbytes/second", r / units[i].thresh,
Packit 7b22a4
		     units[i].name);
Packit 7b22a4
Packit 7b22a4
	r *= cfg->burst;
Packit 7b22a4
	for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
Packit 7b22a4
		if (r >= units[i].thresh)
Packit 7b22a4
			break;
Packit 7b22a4
Packit 7b22a4
	if (cfg->burst > 0)
Packit 7b22a4
		xt_xlate_add(xl, " burst %llu %sbytes", r / units[i].thresh,
Packit 7b22a4
			     units[i].name);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void hashlimit_print_subnet_xlate(struct xt_xlate *xl,
Packit 7b22a4
					 uint32_t nsub, int family)
Packit 7b22a4
{
Packit 7b22a4
	char sep = (family == NFPROTO_IPV4) ? '.' : ':';
Packit 7b22a4
	char *fmt = (family == NFPROTO_IPV4) ? "%u" : "%04x";
Packit 7b22a4
	unsigned int nblocks = (family == NFPROTO_IPV4) ? 4 : 8;
Packit 7b22a4
	unsigned int nbits = (family == NFPROTO_IPV4) ? 8 : 16;
Packit 7b22a4
	unsigned int acm, i;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, " and ");
Packit 7b22a4
	while (nblocks--) {
Packit 7b22a4
		acm = 0;
Packit 7b22a4
Packit 7b22a4
		for (i = 0; i < nbits; i++) {
Packit 7b22a4
			acm <<= 1;
Packit 7b22a4
Packit 7b22a4
			if (nsub > 0) {
Packit 7b22a4
				acm++;
Packit 7b22a4
				nsub--;
Packit 7b22a4
			}
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		xt_xlate_add(xl, fmt, acm);
Packit 7b22a4
		if (nblocks > 0)
Packit 7b22a4
			xt_xlate_add(xl, "%c", sep);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *const hashlimit_modes4_xlate[] = {
Packit 7b22a4
	[XT_HASHLIMIT_HASH_DIP]	= "ip daddr",
Packit 7b22a4
	[XT_HASHLIMIT_HASH_DPT]	= "tcp dport",
Packit 7b22a4
	[XT_HASHLIMIT_HASH_SIP]	= "ip saddr",
Packit 7b22a4
	[XT_HASHLIMIT_HASH_SPT]	= "tcp sport",
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const char *const hashlimit_modes6_xlate[] = {
Packit 7b22a4
	[XT_HASHLIMIT_HASH_DIP]	= "ip6 daddr",
Packit 7b22a4
	[XT_HASHLIMIT_HASH_DPT]	= "tcp dport",
Packit 7b22a4
	[XT_HASHLIMIT_HASH_SIP]	= "ip6 saddr",
Packit 7b22a4
	[XT_HASHLIMIT_HASH_SPT]	= "tcp sport",
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mode_xlate(struct xt_xlate *xl,
Packit 7b22a4
				uint32_t mode, int family,
Packit 7b22a4
				unsigned int nsrc, unsigned int ndst)
Packit 7b22a4
{
Packit 7b22a4
	const char * const *_modes = (family == NFPROTO_IPV4) ?
Packit 7b22a4
		hashlimit_modes4_xlate : hashlimit_modes6_xlate;
Packit 7b22a4
	bool prevopt = false;
Packit 7b22a4
	unsigned int mask;
Packit 7b22a4
Packit 7b22a4
	mode &= ~XT_HASHLIMIT_INVERT & ~XT_HASHLIMIT_BYTES;
Packit 7b22a4
Packit 7b22a4
	for (mask = 1; mode > 0; mask <<= 1) {
Packit 7b22a4
		if (!(mode & mask))
Packit 7b22a4
			continue;
Packit 7b22a4
Packit 7b22a4
		if (!prevopt) {
Packit 7b22a4
			xt_xlate_add(xl, " ");
Packit 7b22a4
			prevopt = true;
Packit 7b22a4
		}
Packit 7b22a4
		else {
Packit 7b22a4
			xt_xlate_add(xl, " . ");
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		xt_xlate_add(xl, "%s", _modes[mask]);
Packit 7b22a4
Packit 7b22a4
		if (mask == XT_HASHLIMIT_HASH_DIP &&
Packit 7b22a4
		    ((family == NFPROTO_IPV4 && ndst != 32) ||
Packit 7b22a4
		     (family == NFPROTO_IPV6 && ndst != 128)))
Packit 7b22a4
			hashlimit_print_subnet_xlate(xl, ndst, family);
Packit 7b22a4
		else if (mask == XT_HASHLIMIT_HASH_SIP &&
Packit 7b22a4
			 ((family == NFPROTO_IPV4 && nsrc != 32) ||
Packit 7b22a4
			  (family == NFPROTO_IPV6 && nsrc != 128)))
Packit 7b22a4
			hashlimit_print_subnet_xlate(xl, nsrc, family);
Packit 7b22a4
Packit 7b22a4
		mode &= ~mask;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return prevopt;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt_xlate(struct xt_xlate *xl, const char *name,
Packit 7b22a4
			      const struct hashlimit_cfg3 *cfg,
Packit 7b22a4
			      int revision, int family)
Packit 7b22a4
{
Packit 7b22a4
	int ret = 1;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "meter %s {", name);
Packit 7b22a4
	ret = hashlimit_mode_xlate(xl, cfg->mode, family,
Packit 7b22a4
				   cfg->srcmask, cfg->dstmask);
Packit 7b22a4
	if (cfg->expire != 1000)
Packit 7b22a4
		xt_xlate_add(xl, " timeout %us", cfg->expire / 1000);
Packit 7b22a4
	xt_xlate_add(xl, " limit rate");
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & XT_HASHLIMIT_INVERT)
Packit 7b22a4
		xt_xlate_add(xl, " over");
Packit 7b22a4
Packit 7b22a4
	if (cfg->mode & XT_HASHLIMIT_BYTES)
Packit 7b22a4
		print_bytes_rate_xlate(xl, cfg);
Packit 7b22a4
	else {
Packit 7b22a4
		print_packets_rate_xlate(xl, cfg->avg, revision);
Packit 7b22a4
		if (cfg->burst != XT_HASHLIMIT_BURST)
Packit 7b22a4
			xt_xlate_add(xl, "burst %" PRIu64 " packets", (uint64_t)cfg->burst);
Packit 7b22a4
Packit 7b22a4
	}
Packit 7b22a4
	xt_xlate_add(xl, "}");
Packit 7b22a4
Packit 7b22a4
	return ret;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_xlate(struct xt_xlate *xl,
Packit 7b22a4
			   const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_info *info = (const void *)params->match->data;
Packit 7b22a4
	int ret = 1;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "meter %s {", info->name);
Packit 7b22a4
	ret = hashlimit_mode_xlate(xl, info->cfg.mode, NFPROTO_IPV4, 32, 32);
Packit 7b22a4
	xt_xlate_add(xl, " timeout %us limit rate", info->cfg.expire / 1000);
Packit 7b22a4
	print_packets_rate_xlate(xl, info->cfg.avg, 1);
Packit 7b22a4
	xt_xlate_add(xl, " burst %u packets", info->cfg.burst);
Packit 7b22a4
	xt_xlate_add(xl, "}");
Packit 7b22a4
Packit 7b22a4
	return ret;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt4_xlate_v1(struct xt_xlate *xl,
Packit 7b22a4
				  const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo1 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
Packit 7b22a4
	if (cfg_copy(&cfg, (const void *)&info->cfg, 1))
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV4);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt6_xlate_v1(struct xt_xlate *xl,
Packit 7b22a4
				  const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo1 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
Packit 7b22a4
	if (cfg_copy(&cfg, (const void *)&info->cfg, 1))
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV6);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt4_xlate_v2(struct xt_xlate *xl,
Packit 7b22a4
				  const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo2 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
Packit 7b22a4
	if (cfg_copy(&cfg, (const void *)&info->cfg, 2))
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV4);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt6_xlate_v2(struct xt_xlate *xl,
Packit 7b22a4
				  const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo2 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
	struct hashlimit_cfg3 cfg;
Packit 7b22a4
Packit 7b22a4
	if (cfg_copy(&cfg, (const void *)&info->cfg, 2))
Packit 7b22a4
		xtables_error(OTHER_PROBLEM, "unknown revision");
Packit 7b22a4
Packit 7b22a4
	return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV6);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt4_xlate(struct xt_xlate *xl,
Packit 7b22a4
			       const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo3 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
Packit 7b22a4
	return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV4);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int hashlimit_mt6_xlate(struct xt_xlate *xl,
Packit 7b22a4
			       const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_hashlimit_mtinfo3 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
Packit 7b22a4
	return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV6);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct xtables_match hashlimit_mt_reg[] = {
Packit 7b22a4
	{
Packit 7b22a4
		.family        = NFPROTO_UNSPEC,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.revision      = 0,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
Packit 7b22a4
		.help          = hashlimit_help,
Packit 7b22a4
		.init          = hashlimit_init,
Packit 7b22a4
		.x6_parse      = hashlimit_parse,
Packit 7b22a4
		.x6_fcheck     = hashlimit_check,
Packit 7b22a4
		.print         = hashlimit_print,
Packit 7b22a4
		.save          = hashlimit_save,
Packit 7b22a4
		.x6_options    = hashlimit_opts,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_xlate,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.revision      = 1,
Packit 7b22a4
		.family        = NFPROTO_IPV4,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
Packit 7b22a4
		.help          = hashlimit_mt_help,
Packit 7b22a4
		.init          = hashlimit_mt4_init_v1,
Packit 7b22a4
		.x6_parse      = hashlimit_mt_parse_v1,
Packit 7b22a4
		.x6_fcheck     = hashlimit_mt_check_v1,
Packit 7b22a4
		.print         = hashlimit_mt4_print_v1,
Packit 7b22a4
		.save          = hashlimit_mt4_save_v1,
Packit 7b22a4
		.x6_options    = hashlimit_mt_opts_v1,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_mt4_xlate_v1,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.revision      = 1,
Packit 7b22a4
		.family        = NFPROTO_IPV6,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
Packit 7b22a4
		.help          = hashlimit_mt_help,
Packit 7b22a4
		.init          = hashlimit_mt6_init_v1,
Packit 7b22a4
		.x6_parse      = hashlimit_mt_parse_v1,
Packit 7b22a4
		.x6_fcheck     = hashlimit_mt_check_v1,
Packit 7b22a4
		.print         = hashlimit_mt6_print_v1,
Packit 7b22a4
		.save          = hashlimit_mt6_save_v1,
Packit 7b22a4
		.x6_options    = hashlimit_mt_opts_v1,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_mt6_xlate_v1,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.revision      = 2,
Packit 7b22a4
		.family        = NFPROTO_IPV4,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
Packit 7b22a4
		.help          = hashlimit_mt_help,
Packit 7b22a4
		.init          = hashlimit_mt4_init_v2,
Packit 7b22a4
		.x6_parse      = hashlimit_mt_parse_v2,
Packit 7b22a4
		.x6_fcheck     = hashlimit_mt_check_v2,
Packit 7b22a4
		.print         = hashlimit_mt4_print_v2,
Packit 7b22a4
		.save          = hashlimit_mt4_save_v2,
Packit 7b22a4
		.x6_options    = hashlimit_mt_opts_v2,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_mt4_xlate_v2,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.revision      = 2,
Packit 7b22a4
		.family        = NFPROTO_IPV6,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
Packit 7b22a4
		.help          = hashlimit_mt_help,
Packit 7b22a4
		.init          = hashlimit_mt6_init_v2,
Packit 7b22a4
		.x6_parse      = hashlimit_mt_parse_v2,
Packit 7b22a4
		.x6_fcheck     = hashlimit_mt_check_v2,
Packit 7b22a4
		.print         = hashlimit_mt6_print_v2,
Packit 7b22a4
		.save          = hashlimit_mt6_save_v2,
Packit 7b22a4
		.x6_options    = hashlimit_mt_opts_v2,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_mt6_xlate_v2,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.revision      = 3,
Packit 7b22a4
		.family        = NFPROTO_IPV4,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo),
Packit 7b22a4
		.help          = hashlimit_mt_help_v3,
Packit 7b22a4
		.init          = hashlimit_mt4_init,
Packit 7b22a4
		.x6_parse      = hashlimit_mt_parse,
Packit 7b22a4
		.x6_fcheck     = hashlimit_mt_check,
Packit 7b22a4
		.print         = hashlimit_mt4_print,
Packit 7b22a4
		.save          = hashlimit_mt4_save,
Packit 7b22a4
		.x6_options    = hashlimit_mt_opts,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_mt4_xlate,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.name          = "hashlimit",
Packit 7b22a4
		.revision      = 3,
Packit 7b22a4
		.family        = NFPROTO_IPV6,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)),
Packit 7b22a4
		.userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo),
Packit 7b22a4
		.help          = hashlimit_mt_help_v3,
Packit 7b22a4
		.init          = hashlimit_mt6_init,
Packit 7b22a4
		.x6_parse      = hashlimit_mt_parse,
Packit 7b22a4
		.x6_fcheck     = hashlimit_mt_check,
Packit 7b22a4
		.print         = hashlimit_mt6_print,
Packit 7b22a4
		.save          = hashlimit_mt6_save,
Packit 7b22a4
		.x6_options    = hashlimit_mt_opts,
Packit 7b22a4
		.udata_size    = sizeof(struct hashlimit_mt_udata),
Packit 7b22a4
		.xlate         = hashlimit_mt6_xlate,
Packit 7b22a4
	},
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
void _init(void)
Packit 7b22a4
{
Packit 7b22a4
	xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
Packit 7b22a4
}