Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables to add addrtype matching support
      2  *
      3  * Copyright (c) 2003-2013 Patrick McHardy <kaber (at) trash.net>
      4  *
      5  * This program is released under the terms of GNU GPL */
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <xtables.h>
      9 #include <linux/netfilter/xt_addrtype.h>
     10 
     11 enum {
     12 	O_SRC_TYPE = 0,
     13 	O_DST_TYPE,
     14 	O_LIMIT_IFACE_IN,
     15 	O_LIMIT_IFACE_OUT,
     16 	F_SRC_TYPE        = 1 << O_SRC_TYPE,
     17 	F_DST_TYPE        = 1 << O_DST_TYPE,
     18 	F_LIMIT_IFACE_IN  = 1 << O_LIMIT_IFACE_IN,
     19 	F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
     20 };
     21 
     22 /* from linux/rtnetlink.h, must match order of enumeration */
     23 static const char *const rtn_names[] = {
     24 	"UNSPEC",
     25 	"UNICAST",
     26 	"LOCAL",
     27 	"BROADCAST",
     28 	"ANYCAST",
     29 	"MULTICAST",
     30 	"BLACKHOLE",
     31 	"UNREACHABLE",
     32 	"PROHIBIT",
     33 	"THROW",
     34 	"NAT",
     35 	"XRESOLVE",
     36 	NULL
     37 };
     38 
     39 static void addrtype_help_types(void)
     40 {
     41 	int i;
     42 
     43 	for (i = 0; rtn_names[i]; i++)
     44 		printf("                                %s\n", rtn_names[i]);
     45 }
     46 
     47 static void addrtype_help_v0(void)
     48 {
     49 	printf(
     50 "Address type match options:\n"
     51 " [!] --src-type type[,...]      Match source address type\n"
     52 " [!] --dst-type type[,...]      Match destination address type\n"
     53 "\n"
     54 "Valid types:           \n");
     55 	addrtype_help_types();
     56 }
     57 
     58 static void addrtype_help_v1(void)
     59 {
     60 	printf(
     61 "Address type match options:\n"
     62 " [!] --src-type type[,...]      Match source address type\n"
     63 " [!] --dst-type type[,...]      Match destination address type\n"
     64 "     --limit-iface-in           Match only on the packet's incoming device\n"
     65 "     --limit-iface-out          Match only on the packet's outgoing device\n"
     66 "\n"
     67 "Valid types:           \n");
     68 	addrtype_help_types();
     69 }
     70 
     71 static int
     72 parse_type(const char *name, size_t len, uint16_t *mask)
     73 {
     74 	int i;
     75 
     76 	for (i = 0; rtn_names[i]; i++)
     77 		if (strncasecmp(name, rtn_names[i], len) == 0) {
     78 			/* build up bitmask for kernel module */
     79 			*mask |= (1 << i);
     80 			return 1;
     81 		}
     82 
     83 	return 0;
     84 }
     85 
     86 static void parse_types(const char *arg, uint16_t *mask)
     87 {
     88 	const char *comma;
     89 
     90 	while ((comma = strchr(arg, ',')) != NULL) {
     91 		if (comma == arg || !parse_type(arg, comma-arg, mask))
     92 			xtables_error(PARAMETER_PROBLEM,
     93 			           "addrtype: bad type `%s'", arg);
     94 		arg = comma + 1;
     95 	}
     96 
     97 	if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
     98 		xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
     99 }
    100 
    101 static void addrtype_parse_v0(struct xt_option_call *cb)
    102 {
    103 	struct xt_addrtype_info *info = cb->data;
    104 
    105 	xtables_option_parse(cb);
    106 	switch (cb->entry->id) {
    107 	case O_SRC_TYPE:
    108 		parse_types(cb->arg, &info->source);
    109 		if (cb->invert)
    110 			info->invert_source = 1;
    111 		break;
    112 	case O_DST_TYPE:
    113 		parse_types(cb->arg, &info->dest);
    114 		if (cb->invert)
    115 			info->invert_dest = 1;
    116 		break;
    117 	}
    118 }
    119 
    120 static void addrtype_parse_v1(struct xt_option_call *cb)
    121 {
    122 	struct xt_addrtype_info_v1 *info = cb->data;
    123 
    124 	xtables_option_parse(cb);
    125 	switch (cb->entry->id) {
    126 	case O_SRC_TYPE:
    127 		parse_types(cb->arg, &info->source);
    128 		if (cb->invert)
    129 			info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
    130 		break;
    131 	case O_DST_TYPE:
    132 		parse_types(cb->arg, &info->dest);
    133 		if (cb->invert)
    134 			info->flags |= XT_ADDRTYPE_INVERT_DEST;
    135 		break;
    136 	case O_LIMIT_IFACE_IN:
    137 		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
    138 		break;
    139 	case O_LIMIT_IFACE_OUT:
    140 		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
    141 		break;
    142 	}
    143 }
    144 
    145 static void addrtype_check(struct xt_fcheck_call *cb)
    146 {
    147 	if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
    148 		xtables_error(PARAMETER_PROBLEM,
    149 			   "addrtype: you must specify --src-type or --dst-type");
    150 }
    151 
    152 static void print_types(uint16_t mask)
    153 {
    154 	const char *sep = "";
    155 	int i;
    156 
    157 	for (i = 0; rtn_names[i]; i++)
    158 		if (mask & (1 << i)) {
    159 			printf("%s%s", sep, rtn_names[i]);
    160 			sep = ",";
    161 		}
    162 }
    163 
    164 static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
    165                               int numeric)
    166 {
    167 	const struct xt_addrtype_info *info = (const void *)match->data;
    168 
    169 	printf(" ADDRTYPE match");
    170 	if (info->source) {
    171 		printf(" src-type ");
    172 		if (info->invert_source)
    173 			printf("!");
    174 		print_types(info->source);
    175 	}
    176 	if (info->dest) {
    177 		printf(" dst-type");
    178 		if (info->invert_dest)
    179 			printf("!");
    180 		print_types(info->dest);
    181 	}
    182 }
    183 
    184 static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
    185                               int numeric)
    186 {
    187 	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
    188 
    189 	printf(" ADDRTYPE match");
    190 	if (info->source) {
    191 		printf(" src-type ");
    192 		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
    193 			printf("!");
    194 		print_types(info->source);
    195 	}
    196 	if (info->dest) {
    197 		printf(" dst-type ");
    198 		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
    199 			printf("!");
    200 		print_types(info->dest);
    201 	}
    202 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
    203 		printf(" limit-in");
    204 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
    205 		printf(" limit-out");
    206 }
    207 
    208 static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
    209 {
    210 	const struct xt_addrtype_info *info = (const void *)match->data;
    211 
    212 	if (info->source) {
    213 		if (info->invert_source)
    214 			printf(" !");
    215 		printf(" --src-type ");
    216 		print_types(info->source);
    217 	}
    218 	if (info->dest) {
    219 		if (info->invert_dest)
    220 			printf(" !");
    221 		printf(" --dst-type ");
    222 		print_types(info->dest);
    223 	}
    224 }
    225 
    226 static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
    227 {
    228 	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
    229 
    230 	if (info->source) {
    231 		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
    232 			printf(" !");
    233 		printf(" --src-type ");
    234 		print_types(info->source);
    235 	}
    236 	if (info->dest) {
    237 		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
    238 			printf(" !");
    239 		printf(" --dst-type ");
    240 		print_types(info->dest);
    241 	}
    242 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
    243 		printf(" --limit-iface-in");
    244 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
    245 		printf(" --limit-iface-out");
    246 }
    247 
    248 static const struct xt_option_entry addrtype_opts_v0[] = {
    249 	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
    250 	 .flags = XTOPT_INVERT},
    251 	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
    252 	 .flags = XTOPT_INVERT},
    253 	XTOPT_TABLEEND,
    254 };
    255 
    256 static const struct xt_option_entry addrtype_opts_v1[] = {
    257 	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
    258 	 .flags = XTOPT_INVERT},
    259 	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
    260 	 .flags = XTOPT_INVERT},
    261 	{.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
    262 	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
    263 	{.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
    264 	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
    265 	XTOPT_TABLEEND,
    266 };
    267 
    268 static struct xtables_match addrtype_mt_reg[] = {
    269 	{
    270 		.name          = "addrtype",
    271 		.version       = XTABLES_VERSION,
    272 		.family        = NFPROTO_IPV4,
    273 		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info)),
    274 		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
    275 		.help          = addrtype_help_v0,
    276 		.print         = addrtype_print_v0,
    277 		.save          = addrtype_save_v0,
    278 		.x6_parse      = addrtype_parse_v0,
    279 		.x6_fcheck     = addrtype_check,
    280 		.x6_options    = addrtype_opts_v0,
    281 	},
    282 	{
    283 		.name          = "addrtype",
    284 		.revision      = 1,
    285 		.version       = XTABLES_VERSION,
    286 		.family        = NFPROTO_UNSPEC,
    287 		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
    288 		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
    289 		.help          = addrtype_help_v1,
    290 		.print         = addrtype_print_v1,
    291 		.save          = addrtype_save_v1,
    292 		.x6_parse      = addrtype_parse_v1,
    293 		.x6_fcheck     = addrtype_check,
    294 		.x6_options    = addrtype_opts_v1,
    295 	},
    296 };
    297 
    298 
    299 void _init(void)
    300 {
    301 	xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
    302 }
    303