Blame extensions/libxt_addrtype.c

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