Blame bootstrap_ver/extensions/libxt_limit.c

Packit Service 1ec7f4
/* Shared library add-on to iptables to add limit support.
Packit Service 1ec7f4
 *
Packit Service 1ec7f4
 * Jérôme de Vivie   <devivie@info.enserb.u-bordeaux.fr>
Packit Service 1ec7f4
 * Hervé Eychenne    <rv@wallfire.org>
Packit Service 1ec7f4
 */
Packit Service 1ec7f4
#define _BSD_SOURCE 1
Packit Service 1ec7f4
#define _DEFAULT_SOURCE 1
Packit Service 1ec7f4
#define _ISOC99_SOURCE 1
Packit Service 1ec7f4
#include <errno.h>
Packit Service 1ec7f4
#include <getopt.h>
Packit Service 1ec7f4
#include <math.h>
Packit Service 1ec7f4
#include <stdio.h>
Packit Service 1ec7f4
#include <string.h>
Packit Service 1ec7f4
#include <stdlib.h>
Packit Service 1ec7f4
#include <xtables.h>
Packit Service 1ec7f4
#include <linux/netfilter/x_tables.h>
Packit Service 1ec7f4
#include <linux/netfilter/xt_limit.h>
Packit Service 1ec7f4
#include "iptables/nft-bridge.h"
Packit Service 1ec7f4
Packit Service 1ec7f4
#define XT_LIMIT_AVG	"3/hour"
Packit Service 1ec7f4
#define XT_LIMIT_BURST	5
Packit Service 1ec7f4
Packit Service 1ec7f4
enum {
Packit Service 1ec7f4
	O_LIMIT = 0,
Packit Service 1ec7f4
	O_BURST,
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static void limit_help(void)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	printf(
Packit Service 1ec7f4
"limit match options:\n"
Packit Service 1ec7f4
"--limit avg			max average match rate: default "XT_LIMIT_AVG"\n"
Packit Service 1ec7f4
"                                [Packets per second unless followed by \n"
Packit Service 1ec7f4
"                                /sec /minute /hour /day postfixes]\n"
Packit Service 1ec7f4
"--limit-burst number		number to match in a burst, default %u\n",
Packit Service 1ec7f4
XT_LIMIT_BURST);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static const struct xt_option_entry limit_opts[] = {
Packit Service 1ec7f4
	{.name = "limit", .id = O_LIMIT, .type = XTTYPE_STRING},
Packit Service 1ec7f4
	{.name = "limit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
Packit Service 1ec7f4
	 .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_rateinfo, burst),
Packit Service 1ec7f4
	 .min = 0, .max = 10000},
Packit Service 1ec7f4
	XTOPT_TABLEEND,
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static
Packit Service 1ec7f4
int parse_rate(const char *rate, uint32_t *val)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *delim;
Packit Service 1ec7f4
	uint32_t r;
Packit Service 1ec7f4
	uint32_t mult = 1;  /* Seconds by default. */
Packit Service 1ec7f4
Packit Service 1ec7f4
	delim = strchr(rate, '/');
Packit Service 1ec7f4
	if (delim) {
Packit Service 1ec7f4
		if (strlen(delim+1) == 0)
Packit Service 1ec7f4
			return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
Packit Service 1ec7f4
			mult = 1;
Packit Service 1ec7f4
		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
Packit Service 1ec7f4
			mult = 60;
Packit Service 1ec7f4
		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
Packit Service 1ec7f4
			mult = 60*60;
Packit Service 1ec7f4
		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
Packit Service 1ec7f4
			mult = 24*60*60;
Packit Service 1ec7f4
		else
Packit Service 1ec7f4
			return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	r = atoi(rate);
Packit Service 1ec7f4
	if (!r)
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
Packit Service 1ec7f4
	*val = XT_LIMIT_SCALE * mult / r;
Packit Service 1ec7f4
	if (*val == 0)
Packit Service 1ec7f4
		/*
Packit Service 1ec7f4
		 * The rate maps to infinity. (1/day is the minimum they can
Packit Service 1ec7f4
		 * specify, so we are ok at that end).
Packit Service 1ec7f4
		 */
Packit Service 1ec7f4
		xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void limit_init(struct xt_entry_match *m)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	parse_rate(XT_LIMIT_AVG, &r->avg);
Packit Service 1ec7f4
	r->burst = XT_LIMIT_BURST;
Packit Service 1ec7f4
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
/* FIXME: handle overflow:
Packit Service 1ec7f4
	if (r->avg*r->burst/r->burst != r->avg)
Packit Service 1ec7f4
		xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
			   "Sorry: burst too large for that avg rate.\n");
Packit Service 1ec7f4
*/
Packit Service 1ec7f4
Packit Service 1ec7f4
static void limit_parse(struct xt_option_call *cb)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct xt_rateinfo *r = cb->data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	xtables_option_parse(cb);
Packit Service 1ec7f4
	switch (cb->entry->id) {
Packit Service 1ec7f4
	case O_LIMIT:
Packit Service 1ec7f4
		if (!parse_rate(cb->arg, &r->avg))
Packit Service 1ec7f4
			xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
				   "bad rate \"%s\"'", cb->arg);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
	if (cb->invert)
Packit Service 1ec7f4
		xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
			   "limit does not support invert");
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static const struct rates
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const char *name;
Packit Service 1ec7f4
	uint32_t mult;
Packit Service 1ec7f4
} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
Packit Service 1ec7f4
	      { "hour", XT_LIMIT_SCALE*60*60 },
Packit Service 1ec7f4
	      { "min", XT_LIMIT_SCALE*60 },
Packit Service 1ec7f4
	      { "sec", XT_LIMIT_SCALE } };
Packit Service 1ec7f4
Packit Service 1ec7f4
static void print_rate(uint32_t period)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	unsigned int i;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (period == 0) {
Packit Service 1ec7f4
		printf(" %f", INFINITY);
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 1; i < ARRAY_SIZE(rates); ++i)
Packit Service 1ec7f4
		if (period > rates[i].mult
Packit Service 1ec7f4
            || rates[i].mult/period < rates[i].mult%period)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
	printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void
Packit Service 1ec7f4
limit_print(const void *ip, const struct xt_entry_match *match, int numeric)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct xt_rateinfo *r = (const void *)match->data;
Packit Service 1ec7f4
	printf(" limit: avg"); print_rate(r->avg);
Packit Service 1ec7f4
	printf(" burst %u", r->burst);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void limit_save(const void *ip, const struct xt_entry_match *match)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct xt_rateinfo *r = (const void *)match->data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	printf(" --limit"); print_rate(r->avg);
Packit Service 1ec7f4
	if (r->burst != XT_LIMIT_BURST)
Packit Service 1ec7f4
		printf(" --limit-burst %u", r->burst);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static const struct rates rates_xlate[] = {
Packit Service 1ec7f4
	{ "day",	XT_LIMIT_SCALE * 24 * 60 * 60 },
Packit Service 1ec7f4
	{ "hour",	XT_LIMIT_SCALE * 60 * 60 },
Packit Service 1ec7f4
	{ "minute",	XT_LIMIT_SCALE * 60 },
Packit Service 1ec7f4
	{ "second",	XT_LIMIT_SCALE }
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static void print_rate_xlate(uint32_t period, struct xt_xlate *xl)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	unsigned int i;
Packit Service 1ec7f4
Packit Service 1ec7f4
	if (period == 0) {
Packit Service 1ec7f4
		xt_xlate_add(xl, " %f", INFINITY);
Packit Service 1ec7f4
		return;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	for (i = 1; i < ARRAY_SIZE(rates); ++i)
Packit Service 1ec7f4
		if (period > rates_xlate[i].mult ||
Packit Service 1ec7f4
		    rates_xlate[i].mult / period < rates_xlate[i].mult % period)
Packit Service 1ec7f4
			break;
Packit Service 1ec7f4
Packit Service 1ec7f4
	xt_xlate_add(xl, " %u/%s", rates_xlate[i - 1].mult / period,
Packit Service 1ec7f4
		   rates_xlate[i - 1].name);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int limit_xlate(struct xt_xlate *xl,
Packit Service 1ec7f4
		       const struct xt_xlate_mt_params *params)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct xt_rateinfo *r = (const void *)params->match->data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	xt_xlate_add(xl, "limit rate");
Packit Service 1ec7f4
	print_rate_xlate(r->avg, xl);
Packit Service 1ec7f4
	if (r->burst != 0)
Packit Service 1ec7f4
		xt_xlate_add(xl, " burst %u packets", r->burst);
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static int limit_xlate_eb(struct xt_xlate *xl,
Packit Service 1ec7f4
			  const struct xt_xlate_mt_params *params)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	limit_xlate(xl, params);
Packit Service 1ec7f4
	xt_xlate_add(xl, " ");
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
#define FLAG_LIMIT		0x01
Packit Service 1ec7f4
#define FLAG_LIMIT_BURST	0x02
Packit Service 1ec7f4
#define ARG_LIMIT		'1'
Packit Service 1ec7f4
#define ARG_LIMIT_BURST		'2'
Packit Service 1ec7f4
Packit Service 1ec7f4
static int brlimit_parse(int c, char **argv, int invert, unsigned int *flags,
Packit Service 1ec7f4
			 const void *entry, struct xt_entry_match **match)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data;
Packit Service 1ec7f4
	uintmax_t num;
Packit Service 1ec7f4
Packit Service 1ec7f4
	switch (c) {
Packit Service 1ec7f4
	case ARG_LIMIT:
Packit Service 1ec7f4
		EBT_CHECK_OPTION(flags, FLAG_LIMIT);
Packit Service 1ec7f4
		if (invert)
Packit Service 1ec7f4
			xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
				      "Unexpected `!' after --limit");
Packit Service 1ec7f4
		if (!parse_rate(optarg, &r->avg))
Packit Service 1ec7f4
			xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
				      "bad rate `%s'", optarg);
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	case ARG_LIMIT_BURST:
Packit Service 1ec7f4
		EBT_CHECK_OPTION(flags, FLAG_LIMIT_BURST);
Packit Service 1ec7f4
		if (invert)
Packit Service 1ec7f4
			xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
				      "Unexpected `!' after --limit-burst");
Packit Service 1ec7f4
		if (!xtables_strtoul(optarg, NULL, &num, 0, 10000))
Packit Service 1ec7f4
			xtables_error(PARAMETER_PROBLEM,
Packit Service 1ec7f4
				      "bad --limit-burst `%s'", optarg);
Packit Service 1ec7f4
		r->burst = num;
Packit Service 1ec7f4
		break;
Packit Service 1ec7f4
	default:
Packit Service 1ec7f4
		return 0;
Packit Service 1ec7f4
	}
Packit Service 1ec7f4
Packit Service 1ec7f4
	return 1;
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static void brlimit_print(const void *ip, const struct xt_entry_match *match,
Packit Service 1ec7f4
			  int numeric)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	const struct xt_rateinfo *r = (struct xt_rateinfo *)match->data;
Packit Service 1ec7f4
Packit Service 1ec7f4
	printf("--limit");
Packit Service 1ec7f4
	print_rate(r->avg);
Packit Service 1ec7f4
	printf(" --limit-burst %u ", r->burst);
Packit Service 1ec7f4
}
Packit Service 1ec7f4
Packit Service 1ec7f4
static const struct option brlimit_opts[] =
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	{ .name = "limit",	.has_arg = true,	.val = ARG_LIMIT },
Packit Service 1ec7f4
	{ .name = "limit-burst",.has_arg = true,	.val = ARG_LIMIT_BURST },
Packit Service 1ec7f4
	XT_GETOPT_TABLEEND,
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
static struct xtables_match limit_match[] = {
Packit Service 1ec7f4
	{
Packit Service 1ec7f4
		.family		= NFPROTO_UNSPEC,
Packit Service 1ec7f4
		.name		= "limit",
Packit Service 1ec7f4
		.version	= XTABLES_VERSION,
Packit Service 1ec7f4
		.size		= XT_ALIGN(sizeof(struct xt_rateinfo)),
Packit Service 1ec7f4
		.userspacesize	= offsetof(struct xt_rateinfo, prev),
Packit Service 1ec7f4
		.help		= limit_help,
Packit Service 1ec7f4
		.init		= limit_init,
Packit Service 1ec7f4
		.x6_parse	= limit_parse,
Packit Service 1ec7f4
		.print		= limit_print,
Packit Service 1ec7f4
		.save		= limit_save,
Packit Service 1ec7f4
		.x6_options	= limit_opts,
Packit Service 1ec7f4
		.xlate		= limit_xlate,
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
	{
Packit Service 1ec7f4
		.family		= NFPROTO_BRIDGE,
Packit Service 1ec7f4
		.name		= "limit",
Packit Service 1ec7f4
		.version	= XTABLES_VERSION,
Packit Service 1ec7f4
		.size		= XT_ALIGN(sizeof(struct xt_rateinfo)),
Packit Service 1ec7f4
		.userspacesize	= offsetof(struct xt_rateinfo, prev),
Packit Service 1ec7f4
		.help		= limit_help,
Packit Service 1ec7f4
		.init		= limit_init,
Packit Service 1ec7f4
		.parse		= brlimit_parse,
Packit Service 1ec7f4
		.print		= brlimit_print,
Packit Service 1ec7f4
		.extra_opts	= brlimit_opts,
Packit Service 1ec7f4
		.xlate		= limit_xlate_eb,
Packit Service 1ec7f4
	},
Packit Service 1ec7f4
};
Packit Service 1ec7f4
Packit Service 1ec7f4
void _init(void)
Packit Service 1ec7f4
{
Packit Service 1ec7f4
	xtables_register_matches(limit_match, ARRAY_SIZE(limit_match));
Packit Service 1ec7f4
}