blob: dc43a3f57e54a1d26f27eacc3ea93f3a2ce15864 [file] [log] [blame]
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +00001/* 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>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01009#include <xtables.h>
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000010
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 */
Jan Engelhardt661f1122007-07-30 14:46:51 +000015static const char *const rtn_names[] = {
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000016 "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
László Attila Tóth14d5ebe2007-10-04 05:01:35 +000031static void addrtype_help_types(void)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000032{
33 int i;
34
35 for (i = 0; rtn_names[i]; i++)
36 printf(" %s\n", rtn_names[i]);
37}
38
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +020039static void addrtype_help_v0(void)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000040{
41 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020042"Address type match options:\n"
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000043" [!] --src-type type[,...] Match source address type\n"
44" [!] --dst-type type[,...] Match destination address type\n"
45"\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020046"Valid types: \n");
László Attila Tóth14d5ebe2007-10-04 05:01:35 +000047 addrtype_help_types();
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000048}
49
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +020050static void addrtype_help_v1(void)
51{
52 printf(
53"Address type match options:\n"
54" [!] --src-type type[,...] Match source address type\n"
55" [!] --dst-type type[,...] Match destination address type\n"
56" --limit-iface-in Match only on the packet's incoming device\n"
57" --limit-iface-out Match only on the packet's incoming device\n"
58"\n"
59"Valid types: \n");
60 addrtype_help_types();
61}
62
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000063static int
Jan Engelhardtdbb77542008-02-11 00:33:30 +010064parse_type(const char *name, size_t len, u_int16_t *mask)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000065{
66 int i;
67
68 for (i = 0; rtn_names[i]; i++)
Jan Engelhardtdbb77542008-02-11 00:33:30 +010069 if (strncasecmp(name, rtn_names[i], len) == 0) {
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000070 /* build up bitmask for kernel module */
71 *mask |= (1 << i);
72 return 1;
73 }
74
75 return 0;
76}
77
Jan Engelhardt59d16402007-10-04 16:28:39 +000078static void parse_types(const char *arg, u_int16_t *mask)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000079{
80 const char *comma;
81
82 while ((comma = strchr(arg, ',')) != NULL) {
Jan Engelhardt59d16402007-10-04 16:28:39 +000083 if (comma == arg || !parse_type(arg, comma-arg, mask))
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000084 exit_error(PARAMETER_PROBLEM,
85 "addrtype: bad type `%s'", arg);
86 arg = comma + 1;
87 }
88
Jan Engelhardt59d16402007-10-04 16:28:39 +000089 if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000090 exit_error(PARAMETER_PROBLEM, "addrtype: bad type `%s'", arg);
91}
92
93#define IPT_ADDRTYPE_OPT_SRCTYPE 0x1
94#define IPT_ADDRTYPE_OPT_DSTTYPE 0x2
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +020095#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN 0x4
96#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT 0x8
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +000097
Jan Engelhardt59d16402007-10-04 16:28:39 +000098static int
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +020099addrtype_parse_v0(int c, char **argv, int invert, unsigned int *flags,
100 const void *entry, struct xt_entry_match **match)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000101{
102 struct ipt_addrtype_info *info =
103 (struct ipt_addrtype_info *) (*match)->data;
104
105 switch (c) {
106 case '1':
107 if (*flags&IPT_ADDRTYPE_OPT_SRCTYPE)
108 exit_error(PARAMETER_PROBLEM,
109 "addrtype: can't specify src-type twice");
110 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardt59d16402007-10-04 16:28:39 +0000111 parse_types(argv[optind-1], &info->source);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000112 if (invert)
113 info->invert_source = 1;
114 *flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
115 break;
116 case '2':
117 if (*flags&IPT_ADDRTYPE_OPT_DSTTYPE)
118 exit_error(PARAMETER_PROBLEM,
119 "addrtype: can't specify dst-type twice");
120 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardt59d16402007-10-04 16:28:39 +0000121 parse_types(argv[optind-1], &info->dest);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000122 if (invert)
123 info->invert_dest = 1;
124 *flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
125 break;
126 default:
127 return 0;
128 }
129
130 return 1;
131}
132
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200133static int
134addrtype_parse_v1(int c, char **argv, int invert, unsigned int *flags,
135 const void *entry, struct xt_entry_match **match)
136{
137 struct ipt_addrtype_info_v1 *info =
138 (struct ipt_addrtype_info_v1 *) (*match)->data;
139
140 switch (c) {
141 case '1':
142 if (*flags & IPT_ADDRTYPE_OPT_SRCTYPE)
143 exit_error(PARAMETER_PROBLEM,
144 "addrtype: can't specify src-type twice");
145 check_inverse(optarg, &invert, &optind, 0);
146 parse_types(argv[optind-1], &info->source);
147 if (invert)
148 info->flags |= IPT_ADDRTYPE_INVERT_SOURCE;
149 *flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
150 break;
151 case '2':
152 if (*flags & IPT_ADDRTYPE_OPT_DSTTYPE)
153 exit_error(PARAMETER_PROBLEM,
154 "addrtype: can't specify dst-type twice");
155 check_inverse(optarg, &invert, &optind, 0);
156 parse_types(argv[optind-1], &info->dest);
157 if (invert)
158 info->flags |= IPT_ADDRTYPE_INVERT_DEST;
159 *flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
160 break;
161 case '3':
162 if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN)
163 exit_error(PARAMETER_PROBLEM,
164 "addrtype: can't specify limit-iface-in twice");
165 info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_IN;
166 *flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN;
167 break;
168 case '4':
169 if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT)
170 exit_error(PARAMETER_PROBLEM,
171 "addrtype: can't specify limit-iface-out twice");
172 info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_OUT;
173 *flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT;
174 break;
175 default:
176 return 0;
177 }
178
179 return 1;
180}
181
182static void addrtype_check_v0(unsigned int flags)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000183{
184 if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
185 exit_error(PARAMETER_PROBLEM,
186 "addrtype: you must specify --src-type or --dst-type");
187}
188
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200189static void addrtype_check_v1(unsigned int flags)
190{
191 if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
192 exit_error(PARAMETER_PROBLEM,
193 "addrtype: you must specify --src-type or --dst-type");
194 if (flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN &&
195 flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT)
196 exit_error(PARAMETER_PROBLEM,
197 "addrtype: you can't specify both --limit-iface-in "
198 "and --limit-iface-out");
199}
200
Jan Engelhardt59d16402007-10-04 16:28:39 +0000201static void print_types(u_int16_t mask)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000202{
203 const char *sep = "";
204 int i;
205
206 for (i = 0; rtn_names[i]; i++)
207 if (mask & (1 << i)) {
208 printf("%s%s", sep, rtn_names[i]);
209 sep = ",";
210 }
211
212 printf(" ");
213}
214
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200215static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
216 int numeric)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000217{
218 const struct ipt_addrtype_info *info =
219 (struct ipt_addrtype_info *) match->data;
220
221 printf("ADDRTYPE match ");
222 if (info->source) {
223 printf("src-type ");
224 if (info->invert_source)
225 printf("!");
Jan Engelhardt59d16402007-10-04 16:28:39 +0000226 print_types(info->source);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000227 }
228 if (info->dest) {
229 printf("dst-type ");
230 if (info->invert_dest)
231 printf("!");
Jan Engelhardt59d16402007-10-04 16:28:39 +0000232 print_types(info->dest);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000233 }
234}
235
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200236static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
237 int numeric)
238{
239 const struct ipt_addrtype_info_v1 *info =
240 (struct ipt_addrtype_info_v1 *) match->data;
241
242 printf("ADDRTYPE match ");
243 if (info->source) {
244 printf("src-type ");
245 if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
246 printf("!");
247 print_types(info->source);
248 }
249 if (info->dest) {
250 printf("dst-type ");
251 if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
252 printf("!");
253 print_types(info->dest);
254 }
255 if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
256 printf("limit-in ");
257 }
258 if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
259 printf("limit-out ");
260 }
261}
262
263static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000264{
265 const struct ipt_addrtype_info *info =
266 (struct ipt_addrtype_info *) match->data;
267
268 if (info->source) {
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000269 if (info->invert_source)
270 printf("! ");
Jan Engelhardtcea9f712008-12-09 15:06:20 +0100271 printf("--src-type ");
Jan Engelhardt59d16402007-10-04 16:28:39 +0000272 print_types(info->source);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000273 }
274 if (info->dest) {
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000275 if (info->invert_dest)
276 printf("! ");
Jan Engelhardtcea9f712008-12-09 15:06:20 +0100277 printf("--dst-type ");
Jan Engelhardt59d16402007-10-04 16:28:39 +0000278 print_types(info->dest);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000279 }
280}
281
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200282static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
283{
284 const struct ipt_addrtype_info_v1 *info =
285 (struct ipt_addrtype_info_v1 *) match->data;
286
287 if (info->source) {
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200288 if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
289 printf("! ");
Jan Engelhardtcea9f712008-12-09 15:06:20 +0100290 printf("--src-type ");
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200291 print_types(info->source);
292 }
293 if (info->dest) {
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200294 if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
295 printf("! ");
Jan Engelhardtcea9f712008-12-09 15:06:20 +0100296 printf("--dst-type ");
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200297 print_types(info->dest);
298 }
299 if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
300 printf("--limit-iface-in ");
301 }
302 if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
303 printf("--limit-iface-out ");
304 }
305}
306
Jan Engelhardt59d16402007-10-04 16:28:39 +0000307static const struct option addrtype_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +0000308 { "src-type", 1, NULL, '1' },
309 { "dst-type", 1, NULL, '2' },
Max Kellermann9ee386a2008-01-29 13:48:05 +0000310 { .name = NULL }
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000311};
312
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200313static const struct option addrtype_opts_v0[] = {
314 { "src-type", 1, NULL, '1' },
315 { "dst-type", 1, NULL, '2' },
316 { .name = NULL }
317};
318
319static const struct option addrtype_opts_v1[] = {
320 { "src-type", 1, NULL, '1' },
321 { "dst-type", 1, NULL, '2' },
322 { "limit-iface-in", 0, NULL, '3' },
323 { "limit-iface-out", 0, NULL, '4' },
324 { .name = NULL }
325};
326
327static struct xtables_match addrtype_mt_reg_v0 = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000328 .name = "addrtype",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200329 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100330 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200331 .size = XT_ALIGN(sizeof(struct ipt_addrtype_info)),
332 .userspacesize = XT_ALIGN(sizeof(struct ipt_addrtype_info)),
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200333 .help = addrtype_help_v0,
334 .parse = addrtype_parse_v0,
335 .final_check = addrtype_check_v0,
336 .print = addrtype_print_v0,
337 .save = addrtype_save_v0,
338 .extra_opts = addrtype_opts_v0,
339};
340
341static struct xtables_match addrtype_mt_reg_v1 = {
342 .name = "addrtype",
343 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100344 .family = NFPROTO_IPV4,
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200345 .size = XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)),
346 .userspacesize = XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)),
347 .help = addrtype_help_v1,
348 .parse = addrtype_parse_v1,
349 .final_check = addrtype_check_v1,
350 .print = addrtype_print_v1,
351 .save = addrtype_save_v1,
352 .extra_opts = addrtype_opts_v1,
353 .revision = 1,
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000354};
355
356
357void _init(void)
358{
Laszlo Attila Toth4dfd25a2008-06-06 14:17:53 +0200359 xtables_register_match(&addrtype_mt_reg_v0);
360 xtables_register_match(&addrtype_mt_reg_v1);
Patrick McHardy6e0e0ed2003-05-07 16:51:40 +0000361}