fix for f12, gcc4.4
[iptables.git] / extensions / libipt_dccp.c
1 /* Shared library add-on to iptables for DCCP matching
2  *
3  * (C) 2005 by Harald Welte <laforge@netfilter.org>
4  *
5  * This program is distributed under the terms of GNU GPL v2, 1991
6  *
7  */
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <getopt.h>
12 #include <netdb.h>
13 #include <ctype.h>
14
15 #include <iptables.h>
16 #include <linux/dccp.h>
17 #include <linux/netfilter_ipv4/ip_tables.h>
18 #include <linux/netfilter_ipv4/ipt_dccp.h>
19
20 #if 0
21 #define DEBUGP(format, first...) printf(format, ##first)
22 #define static
23 #else
24 #define DEBUGP(format, fist...) 
25 #endif
26
27 /* Initialize the match. */
28 static void
29 init(struct ipt_entry_match *m, 
30      unsigned int *nfcache)
31 {
32         struct ipt_dccp_info *einfo = (struct ipt_dccp_info *)m->data;
33
34         memset(einfo, 0, sizeof(struct ipt_dccp_info));
35 }
36
37 static void help(void)
38 {
39         printf(
40 "DCCP match v%s options\n"
41 " --source-port [!] port[:port]                          match source port(s)\n"
42 " --sport ...\n"
43 " --destination-port [!] port[:port]                     match destination port(s)\n"
44 " --dport ...\n"
45 ,
46         IPTABLES_VERSION);
47 }
48
49 static struct option opts[] = {
50         { .name = "source-port", .has_arg = 1, .flag = 0, .val = '1' },
51         { .name = "sport", .has_arg = 1, .flag = 0, .val = '1' },
52         { .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' },
53         { .name = "dport", .has_arg = 1, .flag = 0, .val = '2' },
54         { .name = "dccp-types", .has_arg = 1, .flag = 0, .val = '3' },
55         { .name = "dccp-option", .has_arg = 1, .flag = 0, .val = '4' },
56         { .name = 0 }
57 };
58
59 static void
60 parse_dccp_ports(const char *portstring, 
61                  u_int16_t *ports)
62 {
63         char *buffer;
64         char *cp;
65
66         buffer = strdup(portstring);
67         DEBUGP("%s\n", portstring);
68         if ((cp = strchr(buffer, ':')) == NULL) {
69                 ports[0] = ports[1] = parse_port(buffer, "dccp");
70         }
71         else {
72                 *cp = '\0';
73                 cp++;
74
75                 ports[0] = buffer[0] ? parse_port(buffer, "dccp") : 0;
76                 ports[1] = cp[0] ? parse_port(cp, "dccp") : 0xFFFF;
77
78                 if (ports[0] > ports[1])
79                         exit_error(PARAMETER_PROBLEM,
80                                    "invalid portrange (min > max)");
81         }
82         free(buffer);
83 }
84
85 static char *dccp_pkt_types[] = {
86         [DCCP_PKT_REQUEST]      = "REQUEST",
87         [DCCP_PKT_RESPONSE]     = "RESPONSE",
88         [DCCP_PKT_DATA]         = "DATA",
89         [DCCP_PKT_ACK]          = "ACK",
90         [DCCP_PKT_DATAACK]      = "DATAACK",
91         [DCCP_PKT_CLOSEREQ]     = "CLOSEREQ",
92         [DCCP_PKT_CLOSE]        = "CLOSE",
93         [DCCP_PKT_RESET]        = "RESET",
94         [DCCP_PKT_SYNC]         = "SYNC",
95         [DCCP_PKT_SYNCACK]      = "SYNCACK",
96         [DCCP_PKT_INVALID]      = "INVALID",
97 };
98
99 static u_int16_t
100 parse_dccp_types(const char *typestring)
101 {
102         u_int16_t typemask = 0;
103         char *ptr, *buffer;
104
105         buffer = strdup(typestring);
106
107         for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
108                 unsigned int i;
109                 for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) {
110                         if (!strcasecmp(dccp_pkt_types[i], ptr)) {
111                                 typemask |= (1 << i);
112                                 break;
113                         }
114                 }
115                 if (i == sizeof(dccp_pkt_types)/sizeof(char *))
116                         exit_error(PARAMETER_PROBLEM,
117                                    "Unknown DCCP type `%s'", ptr);
118         }
119
120         free(buffer);
121         return typemask;
122 }
123
124 static u_int8_t parse_dccp_option(char *optstring)
125 {
126         unsigned int ret;
127
128         if (string_to_number(optstring, 1, 255, &ret) == -1)
129                 exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'",
130                            optstring);
131
132         return (u_int8_t)ret;
133 }
134
135 static int
136 parse(int c, char **argv, int invert, unsigned int *flags,
137       const struct ipt_entry *entry,
138       unsigned int *nfcache,
139       struct ipt_entry_match **match)
140 {
141         struct ipt_dccp_info *einfo
142                 = (struct ipt_dccp_info *)(*match)->data;
143
144         switch (c) {
145         case '1':
146                 if (*flags & IPT_DCCP_SRC_PORTS)
147                         exit_error(PARAMETER_PROBLEM,
148                                    "Only one `--source-port' allowed");
149                 einfo->flags |= IPT_DCCP_SRC_PORTS;
150                 check_inverse(optarg, &invert, &optind, 0);
151                 parse_dccp_ports(argv[optind-1], einfo->spts);
152                 if (invert)
153                         einfo->invflags |= IPT_DCCP_SRC_PORTS;
154                 *flags |= IPT_DCCP_SRC_PORTS;
155                 break;
156
157         case '2':
158                 if (*flags & IPT_DCCP_DEST_PORTS)
159                         exit_error(PARAMETER_PROBLEM,
160                                    "Only one `--destination-port' allowed");
161                 einfo->flags |= IPT_DCCP_DEST_PORTS;
162                 check_inverse(optarg, &invert, &optind, 0);
163                 parse_dccp_ports(argv[optind-1], einfo->dpts);
164                 if (invert)
165                         einfo->invflags |= IPT_DCCP_DEST_PORTS;
166                 *flags |= IPT_DCCP_DEST_PORTS;
167                 break;
168
169         case '3':
170                 if (*flags & IPT_DCCP_TYPE)
171                         exit_error(PARAMETER_PROBLEM,
172                                    "Only one `--dccp-types' allowed");
173                 einfo->flags |= IPT_DCCP_TYPE;
174                 check_inverse(optarg, &invert, &optind, 0);
175                 einfo->typemask = parse_dccp_types(argv[optind-1]);
176                 if (invert)
177                         einfo->invflags |= IPT_DCCP_TYPE;
178                 *flags |= IPT_DCCP_TYPE;
179                 break;
180
181         case '4':
182                 if (*flags & IPT_DCCP_OPTION)
183                         exit_error(PARAMETER_PROBLEM,
184                                    "Only one `--dccp-option' allowed");
185                 einfo->flags |= IPT_DCCP_OPTION;
186                 check_inverse(optarg, &invert, &optind, 0);
187                 einfo->option = parse_dccp_option(argv[optind-1]);
188                 if (invert)
189                         einfo->invflags |= IPT_DCCP_OPTION;
190                 *flags |= IPT_DCCP_OPTION;
191                 break;
192         default:
193                 return 0;
194         }
195         return 1;
196 }
197
198 static void
199 final_check(unsigned int flags)
200 {
201 }
202
203 static char *
204 port_to_service(int port)
205 {
206         struct servent *service;
207
208         if ((service = getservbyport(htons(port), "dccp")))
209                 return service->s_name;
210
211         return NULL;
212 }
213
214 static void
215 print_port(u_int16_t port, int numeric)
216 {
217         char *service;
218
219         if (numeric || (service = port_to_service(port)) == NULL)
220                 printf("%u", port);
221         else
222                 printf("%s", service);
223 }
224
225 static void
226 print_ports(const char *name, u_int16_t min, u_int16_t max,
227             int invert, int numeric)
228 {
229         const char *inv = invert ? "!" : "";
230
231         if (min != 0 || max != 0xFFFF || invert) {
232                 printf("%s", name);
233                 if (min == max) {
234                         printf(":%s", inv);
235                         print_port(min, numeric);
236                 } else {
237                         printf("s:%s", inv);
238                         print_port(min, numeric);
239                         printf(":");
240                         print_port(max, numeric);
241                 }
242                 printf(" ");
243         }
244 }
245
246 static void
247 print_types(u_int16_t types, int inverted, int numeric)
248 {
249         int have_type = 0;
250
251         if (inverted)
252                 printf("! ");
253
254         while (types) {
255                 unsigned int i;
256
257                 for (i = 0; !(types & (1 << i)); i++);
258
259                 if (have_type)
260                         printf(",");
261                 else
262                         have_type = 1;
263
264                 if (numeric)
265                         printf("%u", i);
266                 else
267                         printf("%s", dccp_pkt_types[i]);
268
269                 types &= ~(1 << i);
270         }
271 }
272
273 static void
274 print_option(u_int8_t option, int invert, int numeric)
275 {
276         if (option || invert)
277                 printf("option=%s%u ", invert ? "!" : "", option);
278 }
279
280 /* Prints out the matchinfo. */
281 static void
282 print(const struct ipt_ip *ip,
283       const struct ipt_entry_match *match,
284       int numeric)
285 {
286         const struct ipt_dccp_info *einfo =
287                 (const struct ipt_dccp_info *)match->data;
288
289         printf("dccp ");
290
291         if (einfo->flags & IPT_DCCP_SRC_PORTS) {
292                 print_ports("spt", einfo->spts[0], einfo->spts[1],
293                         einfo->invflags & IPT_DCCP_SRC_PORTS,
294                         numeric);
295         }
296
297         if (einfo->flags & IPT_DCCP_DEST_PORTS) {
298                 print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
299                         einfo->invflags & IPT_DCCP_DEST_PORTS,
300                         numeric);
301         }
302
303         if (einfo->flags & IPT_DCCP_TYPE) {
304                 print_types(einfo->typemask,
305                            einfo->invflags & IPT_DCCP_TYPE,
306                            numeric);
307         }
308
309         if (einfo->flags & IPT_DCCP_OPTION) {
310                 print_option(einfo->option,
311                              einfo->invflags & IPT_DCCP_OPTION, numeric);
312         }
313 }
314
315 /* Saves the union ipt_matchinfo in parsable form to stdout. */
316 static void
317 save(const struct ipt_ip *ip, 
318      const struct ipt_entry_match *match)
319 {
320         const struct ipt_dccp_info *einfo =
321                 (const struct ipt_dccp_info *)match->data;
322
323         if (einfo->flags & IPT_DCCP_SRC_PORTS) {
324                 if (einfo->invflags & IPT_DCCP_SRC_PORTS)
325                         printf("! ");
326                 if (einfo->spts[0] != einfo->spts[1])
327                         printf("--sport %u:%u ", 
328                                einfo->spts[0], einfo->spts[1]);
329                 else
330                         printf("--sport %u ", einfo->spts[0]);
331         }
332
333         if (einfo->flags & IPT_DCCP_DEST_PORTS) {
334                 if (einfo->invflags & IPT_DCCP_DEST_PORTS)
335                         printf("! ");
336                 if (einfo->dpts[0] != einfo->dpts[1])
337                         printf("--dport %u:%u ",
338                                einfo->dpts[0], einfo->dpts[1]);
339                 else
340                         printf("--dport %u ", einfo->dpts[0]);
341         }
342
343         if (einfo->flags & IPT_DCCP_TYPE) {
344                 printf("--dccp-type ");
345                 print_types(einfo->typemask, einfo->invflags & IPT_DCCP_TYPE,0);
346         }
347
348         if (einfo->flags & IPT_DCCP_OPTION) {
349                 printf("--dccp-option %s%u ", 
350                         einfo->typemask & IPT_DCCP_OPTION ? "! " : "",
351                         einfo->option);
352         }
353 }
354
355 static
356 struct iptables_match dccp
357 = { .name          = "dccp",
358     .version       = IPTABLES_VERSION,
359     .size          = IPT_ALIGN(sizeof(struct ipt_dccp_info)),
360     .userspacesize = IPT_ALIGN(sizeof(struct ipt_dccp_info)),
361     .help          = &help,
362     .init          = &init,
363     .parse         = &parse,
364     .final_check   = &final_check,
365     .print         = &print,
366     .save          = &save,
367     .extra_opts    = opts
368 };
369
370 void _init(void)
371 {
372         register_match(&dccp);
373 }
374