• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
help_types(void)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 
help(void)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
parse_type(const char * name,size_t strlen,u_int16_t * mask)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 
parse_types(const char * arg,u_int16_t * mask)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 
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,unsigned int * nfcache,struct ipt_entry_match ** match)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 
final_check(unsigned int flags)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 
print_types(u_int16_t mask)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 
print(const struct ipt_ip * ip,const struct ipt_entry_match * match,int numeric)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 
save(const struct ipt_ip * ip,const struct ipt_entry_match * match)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 
ipt_addrtype_init(void)204 void ipt_addrtype_init(void)
205 {
206 	register_match(&addrtype);
207 }
208