Blame extensions/libxt_addrtype.c

Packit 7b22a4
/* Shared library add-on to iptables to add addrtype matching support 
Packit 7b22a4
 *
Packit 7b22a4
 * Copyright (c) 2003-2013 Patrick McHardy <kaber@trash.net>
Packit 7b22a4
 * 
Packit 7b22a4
 * This program is released under the terms of GNU GPL */
Packit 7b22a4
#include <stdio.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <xtables.h>
Packit 7b22a4
#include <linux/netfilter/xt_addrtype.h>
Packit 7b22a4
Packit 7b22a4
enum {
Packit 7b22a4
	O_SRC_TYPE = 0,
Packit 7b22a4
	O_DST_TYPE,
Packit 7b22a4
	O_LIMIT_IFACE_IN,
Packit 7b22a4
	O_LIMIT_IFACE_OUT,
Packit 7b22a4
	F_SRC_TYPE        = 1 << O_SRC_TYPE,
Packit 7b22a4
	F_DST_TYPE        = 1 << O_DST_TYPE,
Packit 7b22a4
	F_LIMIT_IFACE_IN  = 1 << O_LIMIT_IFACE_IN,
Packit 7b22a4
	F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
/* from linux/rtnetlink.h, must match order of enumeration */
Packit 7b22a4
static const char *const rtn_names[] = {
Packit 7b22a4
	"UNSPEC",
Packit 7b22a4
	"UNICAST",
Packit 7b22a4
	"LOCAL",
Packit 7b22a4
	"BROADCAST",
Packit 7b22a4
	"ANYCAST",
Packit 7b22a4
	"MULTICAST",
Packit 7b22a4
	"BLACKHOLE",
Packit 7b22a4
	"UNREACHABLE",
Packit 7b22a4
	"PROHIBIT",
Packit 7b22a4
	"THROW",
Packit 7b22a4
	"NAT",
Packit 7b22a4
	"XRESOLVE",
Packit 7b22a4
	NULL
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void addrtype_help_types(void)
Packit 7b22a4
{
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; rtn_names[i]; i++)
Packit 7b22a4
		printf("                                %s\n", rtn_names[i]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_help_v0(void)
Packit 7b22a4
{
Packit 7b22a4
	printf(
Packit 7b22a4
"Address type match options:\n"
Packit 7b22a4
" [!] --src-type type[,...]      Match source address type\n"
Packit 7b22a4
" [!] --dst-type type[,...]      Match destination address type\n"
Packit 7b22a4
"\n"
Packit 7b22a4
"Valid types:           \n");
Packit 7b22a4
	addrtype_help_types();
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_help_v1(void)
Packit 7b22a4
{
Packit 7b22a4
	printf(
Packit 7b22a4
"Address type match options:\n"
Packit 7b22a4
" [!] --src-type type[,...]      Match source address type\n"
Packit 7b22a4
" [!] --dst-type type[,...]      Match destination address type\n"
Packit 7b22a4
"     --limit-iface-in           Match only on the packet's incoming device\n"
Packit 7b22a4
"     --limit-iface-out          Match only on the packet's outgoing device\n"
Packit 7b22a4
"\n"
Packit 7b22a4
"Valid types:           \n");
Packit 7b22a4
	addrtype_help_types();
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int
Packit 7b22a4
parse_type(const char *name, size_t len, uint16_t *mask)
Packit 7b22a4
{
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; rtn_names[i]; i++)
Packit 7b22a4
		if (strncasecmp(name, rtn_names[i], len) == 0) {
Packit 7b22a4
			/* build up bitmask for kernel module */
Packit 7b22a4
			*mask |= (1 << i);
Packit 7b22a4
			return 1;
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void parse_types(const char *arg, uint16_t *mask)
Packit 7b22a4
{
Packit 7b22a4
	const char *comma;
Packit 7b22a4
Packit 7b22a4
	while ((comma = strchr(arg, ',')) != NULL) {
Packit 7b22a4
		if (comma == arg || !parse_type(arg, comma-arg, mask))
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			           "addrtype: bad type `%s'", arg);
Packit 7b22a4
		arg = comma + 1;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
Packit 7b22a4
}
Packit 7b22a4
	
Packit 7b22a4
static void addrtype_parse_v0(struct xt_option_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_addrtype_info *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	xtables_option_parse(cb);
Packit 7b22a4
	switch (cb->entry->id) {
Packit 7b22a4
	case O_SRC_TYPE:
Packit 7b22a4
		parse_types(cb->arg, &info->source);
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->invert_source = 1;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_DST_TYPE:
Packit 7b22a4
		parse_types(cb->arg, &info->dest);
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->invert_dest = 1;
Packit 7b22a4
		break;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_parse_v1(struct xt_option_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	struct xt_addrtype_info_v1 *info = cb->data;
Packit 7b22a4
Packit 7b22a4
	xtables_option_parse(cb);
Packit 7b22a4
	switch (cb->entry->id) {
Packit 7b22a4
	case O_SRC_TYPE:
Packit 7b22a4
		parse_types(cb->arg, &info->source);
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_DST_TYPE:
Packit 7b22a4
		parse_types(cb->arg, &info->dest);
Packit 7b22a4
		if (cb->invert)
Packit 7b22a4
			info->flags |= XT_ADDRTYPE_INVERT_DEST;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_LIMIT_IFACE_IN:
Packit 7b22a4
		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
Packit 7b22a4
		break;
Packit 7b22a4
	case O_LIMIT_IFACE_OUT:
Packit 7b22a4
		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
Packit 7b22a4
		break;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_check(struct xt_fcheck_call *cb)
Packit 7b22a4
{
Packit 7b22a4
	if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			   "addrtype: you must specify --src-type or --dst-type");
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void print_types(uint16_t mask)
Packit 7b22a4
{
Packit 7b22a4
	const char *sep = "";
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	for (i = 0; rtn_names[i]; i++)
Packit 7b22a4
		if (mask & (1 << i)) {
Packit 7b22a4
			printf("%s%s", sep, rtn_names[i]);
Packit 7b22a4
			sep = ",";
Packit 7b22a4
		}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                              int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_addrtype_info *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	printf(" ADDRTYPE match");
Packit 7b22a4
	if (info->source) {
Packit 7b22a4
		printf(" src-type ");
Packit 7b22a4
		if (info->invert_source)
Packit 7b22a4
			printf("!");
Packit 7b22a4
		print_types(info->source);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->dest) {
Packit 7b22a4
		printf(" dst-type");
Packit 7b22a4
		if (info->invert_dest)
Packit 7b22a4
			printf("!");
Packit 7b22a4
		print_types(info->dest);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
                              int numeric)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	printf(" ADDRTYPE match");
Packit 7b22a4
	if (info->source) {
Packit 7b22a4
		printf(" src-type ");
Packit 7b22a4
		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
Packit 7b22a4
			printf("!");
Packit 7b22a4
		print_types(info->source);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->dest) {
Packit 7b22a4
		printf(" dst-type ");
Packit 7b22a4
		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
Packit 7b22a4
			printf("!");
Packit 7b22a4
		print_types(info->dest);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
Packit 7b22a4
		printf(" limit-in");
Packit 7b22a4
	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
Packit 7b22a4
		printf(" limit-out");
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_addrtype_info *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	if (info->source) {
Packit 7b22a4
		if (info->invert_source)
Packit 7b22a4
			printf(" !");
Packit 7b22a4
		printf(" --src-type ");
Packit 7b22a4
		print_types(info->source);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->dest) {
Packit 7b22a4
		if (info->invert_dest)
Packit 7b22a4
			printf(" !");
Packit 7b22a4
		printf(" --dst-type ");
Packit 7b22a4
		print_types(info->dest);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
Packit 7b22a4
Packit 7b22a4
	if (info->source) {
Packit 7b22a4
		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
Packit 7b22a4
			printf(" !");
Packit 7b22a4
		printf(" --src-type ");
Packit 7b22a4
		print_types(info->source);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->dest) {
Packit 7b22a4
		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
Packit 7b22a4
			printf(" !");
Packit 7b22a4
		printf(" --dst-type ");
Packit 7b22a4
		print_types(info->dest);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
Packit 7b22a4
		printf(" --limit-iface-in");
Packit 7b22a4
	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
Packit 7b22a4
		printf(" --limit-iface-out");
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *const rtn_lnames[] = {
Packit 7b22a4
	"unspec",
Packit 7b22a4
	"unicast",
Packit 7b22a4
	"local",
Packit 7b22a4
	"broadcast",
Packit 7b22a4
	"anycast",
Packit 7b22a4
	"multicast",
Packit 7b22a4
	"blackhole",
Packit 7b22a4
	"unreachable",
Packit 7b22a4
	"prohibit",
Packit 7b22a4
	NULL,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static bool multiple_bits_set(uint16_t val)
Packit 7b22a4
{
Packit 7b22a4
	int first = ffs(val);
Packit 7b22a4
Packit 7b22a4
	return first && (val >> first) > 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int addrtype_xlate(struct xt_xlate *xl,
Packit 7b22a4
			  const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct xt_addrtype_info_v1 *info =
Packit 7b22a4
		(const void *)params->match->data;
Packit 7b22a4
	const char *sep = "";
Packit 7b22a4
	bool need_braces;
Packit 7b22a4
	uint16_t val;
Packit 7b22a4
	int i;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "fib ");
Packit 7b22a4
Packit 7b22a4
	if (info->source) {
Packit 7b22a4
		xt_xlate_add(xl, "saddr ");
Packit 7b22a4
		val = info->source;
Packit 7b22a4
	} else {
Packit 7b22a4
		xt_xlate_add(xl, "daddr ");
Packit 7b22a4
		val = info->dest;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
Packit 7b22a4
		xt_xlate_add(xl, ". iif ");
Packit 7b22a4
	else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
Packit 7b22a4
		xt_xlate_add(xl, ". oif ");
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "type ");
Packit 7b22a4
Packit 7b22a4
	if (info->flags & (XT_ADDRTYPE_INVERT_SOURCE | XT_ADDRTYPE_INVERT_DEST))
Packit 7b22a4
			xt_xlate_add(xl, "!= ");
Packit 7b22a4
Packit 7b22a4
	need_braces = multiple_bits_set(val);
Packit 7b22a4
Packit 7b22a4
	if (need_braces)
Packit 7b22a4
		xt_xlate_add(xl, "{ ");
Packit 7b22a4
Packit 7b22a4
	for (i = 0; rtn_lnames[i]; i++) {
Packit 7b22a4
		if (val & (1 << i)) {
Packit 7b22a4
			xt_xlate_add(xl, "%s%s", sep, rtn_lnames[i]);
Packit 7b22a4
			sep = ", ";
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (need_braces)
Packit 7b22a4
		xt_xlate_add(xl, " }");
Packit 7b22a4
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const struct xt_option_entry addrtype_opts_v0[] = {
Packit 7b22a4
	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_INVERT},
Packit 7b22a4
	XTOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const struct xt_option_entry addrtype_opts_v1[] = {
Packit 7b22a4
	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
Packit 7b22a4
	 .flags = XTOPT_INVERT},
Packit 7b22a4
	{.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
Packit 7b22a4
	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
Packit 7b22a4
	{.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
Packit 7b22a4
	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
Packit 7b22a4
	XTOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static struct xtables_match addrtype_mt_reg[] = {
Packit 7b22a4
	{
Packit 7b22a4
		.name          = "addrtype",
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.family        = NFPROTO_IPV4,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info)),
Packit 7b22a4
		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
Packit 7b22a4
		.help          = addrtype_help_v0,
Packit 7b22a4
		.print         = addrtype_print_v0,
Packit 7b22a4
		.save          = addrtype_save_v0,
Packit 7b22a4
		.x6_parse      = addrtype_parse_v0,
Packit 7b22a4
		.x6_fcheck     = addrtype_check,
Packit 7b22a4
		.x6_options    = addrtype_opts_v0,
Packit 7b22a4
	},
Packit 7b22a4
	{
Packit 7b22a4
		.name          = "addrtype",
Packit 7b22a4
		.revision      = 1,
Packit 7b22a4
		.version       = XTABLES_VERSION,
Packit 7b22a4
		.family        = NFPROTO_UNSPEC,
Packit 7b22a4
		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
Packit 7b22a4
		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
Packit 7b22a4
		.help          = addrtype_help_v1,
Packit 7b22a4
		.print         = addrtype_print_v1,
Packit 7b22a4
		.save          = addrtype_save_v1,
Packit 7b22a4
		.x6_parse      = addrtype_parse_v1,
Packit 7b22a4
		.x6_fcheck     = addrtype_check,
Packit 7b22a4
		.x6_options    = addrtype_opts_v1,
Packit 7b22a4
		.xlate         = addrtype_xlate,
Packit 7b22a4
	},
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
Packit 7b22a4
void _init(void) 
Packit 7b22a4
{
Packit 7b22a4
	xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
Packit 7b22a4
}