changing trunk/trunk to trunk
[iptables.git] / extensions / libipt_addrtype.c
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 const char *const 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 addrtype_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 addrtype_help_v0(void)
40 {
41         printf(
42 "Address type match 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         addrtype_help_types();
48 }
49
50 static 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
63 static int
64 parse_type(const char *name, size_t len, u_int16_t *mask)
65 {
66         int i;
67
68         for (i = 0; rtn_names[i]; i++)
69                 if (strncasecmp(name, rtn_names[i], len) == 0) {
70                         /* build up bitmask for kernel module */
71                         *mask |= (1 << i);
72                         return 1;
73                 }
74
75         return 0;
76 }
77
78 static void parse_types(const char *arg, u_int16_t *mask)
79 {
80         const char *comma;
81
82         while ((comma = strchr(arg, ',')) != NULL) {
83                 if (comma == arg || !parse_type(arg, comma-arg, mask))
84                         exit_error(PARAMETER_PROBLEM,
85                                    "addrtype: bad type `%s'", arg);
86                 arg = comma + 1;
87         }
88
89         if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
90                 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
95 #define IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN         0x4
96 #define IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT        0x8
97
98 static int
99 addrtype_parse_v0(int c, char **argv, int invert, unsigned int *flags,
100                   const void *entry, struct xt_entry_match **match)
101 {
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);
111                 parse_types(argv[optind-1], &info->source);
112                 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);
121                 parse_types(argv[optind-1], &info->dest);
122                 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
133 static int
134 addrtype_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
182 static void addrtype_check_v0(unsigned int flags)
183 {
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
189 static 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
201 static void print_types(u_int16_t mask)
202 {
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
215 static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
216                               int numeric)
217 {
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("!");
226                 print_types(info->source);
227         }
228         if (info->dest) {
229                 printf("dst-type ");
230                 if (info->invert_dest)
231                         printf("!");
232                 print_types(info->dest);
233         }
234 }
235
236 static 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
263 static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
264 {
265         const struct ipt_addrtype_info *info =
266                 (struct ipt_addrtype_info *) match->data;
267
268         if (info->source) {
269                 printf("--src-type ");
270                 if (info->invert_source)
271                         printf("! ");
272                 print_types(info->source);
273         }
274         if (info->dest) {
275                 printf("--dst-type ");
276                 if (info->invert_dest)
277                         printf("! ");
278                 print_types(info->dest);
279         }
280 }
281
282 static 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) {
288                 printf("--src-type ");
289                 if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
290                         printf("! ");
291                 print_types(info->source);
292         }
293         if (info->dest) {
294                 printf("--dst-type ");
295                 if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
296                         printf("! ");
297                 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
307 static const struct option addrtype_opts[] = {
308         { "src-type", 1, NULL, '1' },
309         { "dst-type", 1, NULL, '2' },
310         { .name = NULL }
311 };
312
313 static const struct option addrtype_opts_v0[] = {
314         { "src-type", 1, NULL, '1' },
315         { "dst-type", 1, NULL, '2' },
316         { .name = NULL }
317 };
318
319 static 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
327 static struct xtables_match addrtype_mt_reg_v0 = {
328         .name           = "addrtype",
329         .version        = XTABLES_VERSION,
330         .family         = PF_INET,
331         .size           = XT_ALIGN(sizeof(struct ipt_addrtype_info)),
332         .userspacesize  = XT_ALIGN(sizeof(struct ipt_addrtype_info)),
333         .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
341 static struct xtables_match addrtype_mt_reg_v1 = {
342         .name           = "addrtype",
343         .version        = XTABLES_VERSION,
344         .family         = PF_INET,
345         .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,
354 };
355
356
357 void _init(void) 
358 {
359         xtables_register_match(&addrtype_mt_reg_v0);
360         xtables_register_match(&addrtype_mt_reg_v1);
361 }