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