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 
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <getopt.h>
      9 #include <iptables.h>
     10 
     11 #include <linux/netfilter_ipv4/ip_tables.h>
     12 #include <linux/netfilter_ipv4/ipt_addrtype.h>
     13 
     14 /* from linux/rtnetlink.h, must match order of enumeration */
     15 static char *rtn_names[] = {
     16 	"UNSPEC",
     17 	"UNICAST",
     18 	"LOCAL",
     19 	"BROADCAST",
     20 	"ANYCAST",
     21 	"MULTICAST",
     22 	"BLACKHOLE",
     23 	"UNREACHABLE",
     24 	"PROHIBIT",
     25 	"THROW",
     26 	"NAT",
     27 	"XRESOLVE",
     28 	NULL
     29 };
     30 
     31 static void help_types(void)
     32 {
     33 	int i;
     34 
     35 	for (i = 0; rtn_names[i]; i++)
     36 		printf("                                %s\n", rtn_names[i]);
     37 }
     38 
     39 static void help(void)
     40 {
     41 	printf(
     42 "Address type match v%s options:\n"
     43 " [!] --src-type type[,...]      Match source address type\n"
     44 " [!] --dst-type type[,...]      Match destination address type\n"
     45 "\n"
     46 "Valid types:           \n"
     47 , IPTABLES_VERSION);
     48 	help_types();
     49 }
     50 
     51 static int
     52 parse_type(const char *name, size_t strlen, u_int16_t *mask)
     53 {
     54 	int i;
     55 
     56 	for (i = 0; rtn_names[i]; i++)
     57 		if (strncasecmp(name, rtn_names[i], strlen) == 0) {
     58 			/* build up bitmask for kernel module */
     59 			*mask |= (1 << i);
     60 			return 1;
     61 		}
     62 
     63 	return 0;
     64 }
     65 
     66 static void parse_types(const char *arg, u_int16_t *mask)
     67 {
     68 	const char *comma;
     69 
     70 	while ((comma = strchr(arg, ',')) != NULL) {
     71 		if (comma == arg || !parse_type(arg, comma-arg, mask))
     72 			exit_error(PARAMETER_PROBLEM,
     73 			           "addrtype: bad type `%s'", arg);
     74 		arg = comma + 1;
     75 	}
     76 
     77 	if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
     78 		exit_error(PARAMETER_PROBLEM, "addrtype: bad type `%s'", arg);
     79 }
     80 
     81 #define IPT_ADDRTYPE_OPT_SRCTYPE	0x1
     82 #define IPT_ADDRTYPE_OPT_DSTTYPE	0x2
     83 
     84 static int parse(int c, char **argv, int invert, unsigned int *flags,
     85 		const struct ipt_entry *entry, unsigned int *nfcache,
     86 		struct ipt_entry_match **match)
     87 {
     88 	struct ipt_addrtype_info *info =
     89 		(struct ipt_addrtype_info *) (*match)->data;
     90 
     91 	switch (c) {
     92 	case '1':
     93 		if (*flags&IPT_ADDRTYPE_OPT_SRCTYPE)
     94 			exit_error(PARAMETER_PROBLEM,
     95 			           "addrtype: can't specify src-type twice");
     96 		check_inverse(optarg, &invert, &optind, 0);
     97 		parse_types(argv[optind-1], &info->source);
     98 		if (invert)
     99 			info->invert_source = 1;
    100 		*flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
    101 		break;
    102 	case '2':
    103 		if (*flags&IPT_ADDRTYPE_OPT_DSTTYPE)
    104 			exit_error(PARAMETER_PROBLEM,
    105 			           "addrtype: can't specify dst-type twice");
    106 		check_inverse(optarg, &invert, &optind, 0);
    107 		parse_types(argv[optind-1], &info->dest);
    108 		if (invert)
    109 			info->invert_dest = 1;
    110 		*flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
    111 		break;
    112 	default:
    113 		return 0;
    114 	}
    115 
    116 	return 1;
    117 }
    118 
    119 static void final_check(unsigned int flags)
    120 {
    121 	if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
    122 		exit_error(PARAMETER_PROBLEM,
    123 			   "addrtype: you must specify --src-type or --dst-type");
    124 }
    125 
    126 static void print_types(u_int16_t mask)
    127 {
    128 	const char *sep = "";
    129 	int i;
    130 
    131 	for (i = 0; rtn_names[i]; i++)
    132 		if (mask & (1 << i)) {
    133 			printf("%s%s", sep, rtn_names[i]);
    134 			sep = ",";
    135 		}
    136 
    137 	printf(" ");
    138 }
    139 
    140 static void print(const struct ipt_ip *ip,
    141 		const struct ipt_entry_match *match,
    142 		int numeric)
    143 {
    144 	const struct ipt_addrtype_info *info =
    145 		(struct ipt_addrtype_info *) match->data;
    146 
    147 	printf("ADDRTYPE match ");
    148 	if (info->source) {
    149 		printf("src-type ");
    150 		if (info->invert_source)
    151 			printf("!");
    152 		print_types(info->source);
    153 	}
    154 	if (info->dest) {
    155 		printf("dst-type ");
    156 		if (info->invert_dest)
    157 			printf("!");
    158 		print_types(info->dest);
    159 	}
    160 }
    161 
    162 static void save(const struct ipt_ip *ip,
    163 		const struct ipt_entry_match *match)
    164 {
    165 	const struct ipt_addrtype_info *info =
    166 		(struct ipt_addrtype_info *) match->data;
    167 
    168 	if (info->source) {
    169 		printf("--src-type ");
    170 		if (info->invert_source)
    171 			printf("! ");
    172 		print_types(info->source);
    173 	}
    174 	if (info->dest) {
    175 		printf("--dst-type ");
    176 		if (info->invert_dest)
    177 			printf("! ");
    178 		print_types(info->dest);
    179 	}
    180 }
    181 
    182 static struct option opts[] = {
    183 	{ "src-type", 1, 0, '1' },
    184 	{ "dst-type", 1, 0, '2' },
    185 	{ 0 }
    186 };
    187 
    188 static
    189 struct iptables_match addrtype = {
    190 	.next 		= NULL,
    191 	.name 		= "addrtype",
    192 	.version 	= IPTABLES_VERSION,
    193 	.size 		= IPT_ALIGN(sizeof(struct ipt_addrtype_info)),
    194 	.userspacesize 	= IPT_ALIGN(sizeof(struct ipt_addrtype_info)),
    195 	.help 		= &help,
    196 	.parse 		= &parse,
    197 	.final_check 	= &final_check,
    198 	.print 		= &print,
    199 	.save 		= &save,
    200 	.extra_opts 	= opts
    201 };
    202 
    203 
    204 void ipt_addrtype_init(void)
    205 {
    206 	register_match(&addrtype);
    207 }
    208