blob: d794c2dd745694d28483cafc30bd17e2f2bc877a [file] [log] [blame]
Harald Weltee40b11d2005-08-06 21:13:04 +00001/* 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
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000015#include <xtables.h>
Harald Weltee40b11d2005-08-06 21:13:04 +000016#include <linux/dccp.h>
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000017#include <linux/netfilter/x_tables.h>
18#include <linux/netfilter/xt_dccp.h>
Harald Weltee40b11d2005-08-06 21:13:04 +000019
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. */
28static void
Peter Rileyea146a92007-09-02 13:09:07 +000029init(struct xt_entry_match *m)
Harald Weltee40b11d2005-08-06 21:13:04 +000030{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000031 struct xt_dccp_info *einfo = (struct xt_dccp_info *)m->data;
Harald Weltee40b11d2005-08-06 21:13:04 +000032
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000033 memset(einfo, 0, sizeof(struct xt_dccp_info));
Harald Weltee40b11d2005-08-06 21:13:04 +000034}
35
36static void help(void)
37{
38 printf(
39"DCCP match v%s options\n"
40" --source-port [!] port[:port] match source port(s)\n"
41" --sport ...\n"
42" --destination-port [!] port[:port] match destination port(s)\n"
43" --dport ...\n"
44,
45 IPTABLES_VERSION);
46}
47
Jan Engelhardt661f1122007-07-30 14:46:51 +000048static const struct option opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000049 { .name = "source-port", .has_arg = 1, .val = '1' },
50 { .name = "sport", .has_arg = 1, .val = '1' },
51 { .name = "destination-port", .has_arg = 1, .val = '2' },
52 { .name = "dport", .has_arg = 1, .val = '2' },
53 { .name = "dccp-types", .has_arg = 1, .val = '3' },
54 { .name = "dccp-option", .has_arg = 1, .val = '4' },
55 { }
Harald Weltee40b11d2005-08-06 21:13:04 +000056};
57
Harald Weltee40b11d2005-08-06 21:13:04 +000058static void
59parse_dccp_ports(const char *portstring,
60 u_int16_t *ports)
61{
62 char *buffer;
63 char *cp;
64
65 buffer = strdup(portstring);
66 DEBUGP("%s\n", portstring);
67 if ((cp = strchr(buffer, ':')) == NULL) {
Phil Oesterdbac8ad2006-07-20 17:01:54 +000068 ports[0] = ports[1] = parse_port(buffer, "dccp");
Harald Weltee40b11d2005-08-06 21:13:04 +000069 }
70 else {
71 *cp = '\0';
72 cp++;
73
Phil Oesterdbac8ad2006-07-20 17:01:54 +000074 ports[0] = buffer[0] ? parse_port(buffer, "dccp") : 0;
75 ports[1] = cp[0] ? parse_port(cp, "dccp") : 0xFFFF;
Harald Weltee40b11d2005-08-06 21:13:04 +000076
77 if (ports[0] > ports[1])
78 exit_error(PARAMETER_PROBLEM,
79 "invalid portrange (min > max)");
80 }
81 free(buffer);
82}
83
Jan Engelhardt0e2abed2007-10-04 16:25:58 +000084static const char *const dccp_pkt_types[] = {
Harald Weltee40b11d2005-08-06 21:13:04 +000085 [DCCP_PKT_REQUEST] = "REQUEST",
86 [DCCP_PKT_RESPONSE] = "RESPONSE",
87 [DCCP_PKT_DATA] = "DATA",
88 [DCCP_PKT_ACK] = "ACK",
89 [DCCP_PKT_DATAACK] = "DATAACK",
90 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
91 [DCCP_PKT_CLOSE] = "CLOSE",
92 [DCCP_PKT_RESET] = "RESET",
93 [DCCP_PKT_SYNC] = "SYNC",
94 [DCCP_PKT_SYNCACK] = "SYNCACK",
95 [DCCP_PKT_INVALID] = "INVALID",
96};
97
98static u_int16_t
99parse_dccp_types(const char *typestring)
100{
101 u_int16_t typemask = 0;
102 char *ptr, *buffer;
103
104 buffer = strdup(typestring);
105
106 for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
107 unsigned int i;
108 for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) {
109 if (!strcasecmp(dccp_pkt_types[i], ptr)) {
110 typemask |= (1 << i);
111 break;
112 }
113 }
114 if (i == sizeof(dccp_pkt_types)/sizeof(char *))
115 exit_error(PARAMETER_PROBLEM,
116 "Unknown DCCP type `%s'", ptr);
117 }
118
119 free(buffer);
120 return typemask;
121}
122
123static u_int8_t parse_dccp_option(char *optstring)
124{
125 unsigned int ret;
126
127 if (string_to_number(optstring, 1, 255, &ret) == -1)
128 exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'",
129 optstring);
130
131 return (u_int8_t)ret;
132}
133
134static int
135parse(int c, char **argv, int invert, unsigned int *flags,
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000136 const void *entry,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +0000137 struct xt_entry_match **match)
Harald Weltee40b11d2005-08-06 21:13:04 +0000138{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000139 struct xt_dccp_info *einfo
140 = (struct xt_dccp_info *)(*match)->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000141
142 switch (c) {
143 case '1':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000144 if (*flags & XT_DCCP_SRC_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000145 exit_error(PARAMETER_PROBLEM,
146 "Only one `--source-port' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000147 einfo->flags |= XT_DCCP_SRC_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000148 check_inverse(optarg, &invert, &optind, 0);
149 parse_dccp_ports(argv[optind-1], einfo->spts);
150 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000151 einfo->invflags |= XT_DCCP_SRC_PORTS;
152 *flags |= XT_DCCP_SRC_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000153 break;
154
155 case '2':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000156 if (*flags & XT_DCCP_DEST_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000157 exit_error(PARAMETER_PROBLEM,
158 "Only one `--destination-port' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000159 einfo->flags |= XT_DCCP_DEST_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000160 check_inverse(optarg, &invert, &optind, 0);
161 parse_dccp_ports(argv[optind-1], einfo->dpts);
162 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000163 einfo->invflags |= XT_DCCP_DEST_PORTS;
164 *flags |= XT_DCCP_DEST_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000165 break;
166
167 case '3':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000168 if (*flags & XT_DCCP_TYPE)
Harald Weltee40b11d2005-08-06 21:13:04 +0000169 exit_error(PARAMETER_PROBLEM,
170 "Only one `--dccp-types' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000171 einfo->flags |= XT_DCCP_TYPE;
Harald Weltee40b11d2005-08-06 21:13:04 +0000172 check_inverse(optarg, &invert, &optind, 0);
173 einfo->typemask = parse_dccp_types(argv[optind-1]);
174 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000175 einfo->invflags |= XT_DCCP_TYPE;
176 *flags |= XT_DCCP_TYPE;
Harald Weltee40b11d2005-08-06 21:13:04 +0000177 break;
178
179 case '4':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000180 if (*flags & XT_DCCP_OPTION)
Harald Weltee40b11d2005-08-06 21:13:04 +0000181 exit_error(PARAMETER_PROBLEM,
182 "Only one `--dccp-option' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000183 einfo->flags |= XT_DCCP_OPTION;
Harald Weltee40b11d2005-08-06 21:13:04 +0000184 check_inverse(optarg, &invert, &optind, 0);
185 einfo->option = parse_dccp_option(argv[optind-1]);
186 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000187 einfo->invflags |= XT_DCCP_OPTION;
188 *flags |= XT_DCCP_OPTION;
Harald Weltee40b11d2005-08-06 21:13:04 +0000189 break;
190 default:
191 return 0;
192 }
193 return 1;
194}
195
Harald Weltee40b11d2005-08-06 21:13:04 +0000196static char *
197port_to_service(int port)
198{
199 struct servent *service;
200
201 if ((service = getservbyport(htons(port), "dccp")))
202 return service->s_name;
203
204 return NULL;
205}
206
207static void
208print_port(u_int16_t port, int numeric)
209{
210 char *service;
211
212 if (numeric || (service = port_to_service(port)) == NULL)
213 printf("%u", port);
214 else
215 printf("%s", service);
216}
217
218static void
219print_ports(const char *name, u_int16_t min, u_int16_t max,
220 int invert, int numeric)
221{
222 const char *inv = invert ? "!" : "";
223
224 if (min != 0 || max != 0xFFFF || invert) {
225 printf("%s", name);
226 if (min == max) {
227 printf(":%s", inv);
228 print_port(min, numeric);
229 } else {
230 printf("s:%s", inv);
231 print_port(min, numeric);
232 printf(":");
233 print_port(max, numeric);
234 }
235 printf(" ");
236 }
237}
238
239static void
240print_types(u_int16_t types, int inverted, int numeric)
241{
242 int have_type = 0;
243
244 if (inverted)
245 printf("! ");
246
247 while (types) {
248 unsigned int i;
249
250 for (i = 0; !(types & (1 << i)); i++);
251
252 if (have_type)
253 printf(",");
254 else
255 have_type = 1;
256
257 if (numeric)
258 printf("%u", i);
259 else
260 printf("%s", dccp_pkt_types[i]);
261
262 types &= ~(1 << i);
263 }
264}
265
266static void
267print_option(u_int8_t option, int invert, int numeric)
268{
269 if (option || invert)
270 printf("option=%s%u ", invert ? "!" : "", option);
271}
272
273/* Prints out the matchinfo. */
274static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000275print(const void *ip,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +0000276 const struct xt_entry_match *match,
Harald Weltee40b11d2005-08-06 21:13:04 +0000277 int numeric)
278{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000279 const struct xt_dccp_info *einfo =
280 (const struct xt_dccp_info *)match->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000281
282 printf("dccp ");
283
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000284 if (einfo->flags & XT_DCCP_SRC_PORTS) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000285 print_ports("spt", einfo->spts[0], einfo->spts[1],
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000286 einfo->invflags & XT_DCCP_SRC_PORTS,
Harald Weltee40b11d2005-08-06 21:13:04 +0000287 numeric);
288 }
289
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000290 if (einfo->flags & XT_DCCP_DEST_PORTS) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000291 print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000292 einfo->invflags & XT_DCCP_DEST_PORTS,
Harald Weltee40b11d2005-08-06 21:13:04 +0000293 numeric);
294 }
295
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000296 if (einfo->flags & XT_DCCP_TYPE) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000297 print_types(einfo->typemask,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000298 einfo->invflags & XT_DCCP_TYPE,
Harald Weltee40b11d2005-08-06 21:13:04 +0000299 numeric);
300 }
301
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000302 if (einfo->flags & XT_DCCP_OPTION) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000303 print_option(einfo->option,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000304 einfo->invflags & XT_DCCP_OPTION, numeric);
Harald Weltee40b11d2005-08-06 21:13:04 +0000305 }
306}
307
308/* Saves the union ipt_matchinfo in parsable form to stdout. */
309static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000310save(const void *ip,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +0000311 const struct xt_entry_match *match)
Harald Weltee40b11d2005-08-06 21:13:04 +0000312{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000313 const struct xt_dccp_info *einfo =
314 (const struct xt_dccp_info *)match->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000315
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000316 if (einfo->flags & XT_DCCP_SRC_PORTS) {
317 if (einfo->invflags & XT_DCCP_SRC_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000318 printf("! ");
319 if (einfo->spts[0] != einfo->spts[1])
320 printf("--sport %u:%u ",
321 einfo->spts[0], einfo->spts[1]);
322 else
323 printf("--sport %u ", einfo->spts[0]);
324 }
325
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000326 if (einfo->flags & XT_DCCP_DEST_PORTS) {
327 if (einfo->invflags & XT_DCCP_DEST_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000328 printf("! ");
329 if (einfo->dpts[0] != einfo->dpts[1])
330 printf("--dport %u:%u ",
331 einfo->dpts[0], einfo->dpts[1]);
332 else
333 printf("--dport %u ", einfo->dpts[0]);
334 }
335
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000336 if (einfo->flags & XT_DCCP_TYPE) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000337 printf("--dccp-type ");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000338 print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0);
Harald Weltee40b11d2005-08-06 21:13:04 +0000339 }
340
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000341 if (einfo->flags & XT_DCCP_OPTION) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000342 printf("--dccp-option %s%u ",
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000343 einfo->typemask & XT_DCCP_OPTION ? "! " : "",
Harald Weltee40b11d2005-08-06 21:13:04 +0000344 einfo->option);
345 }
346}
347
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000348static struct xtables_match dccp =
349{
350 .name = "dccp",
351 .family = AF_INET,
352 .version = IPTABLES_VERSION,
353 .size = XT_ALIGN(sizeof(struct xt_dccp_info)),
354 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)),
355 .help = &help,
356 .init = &init,
357 .parse = &parse,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000358 .print = &print,
359 .save = &save,
360 .extra_opts = opts
361};
362
363static struct xtables_match dccp6 =
364{
365 .name = "dccp",
366 .family = AF_INET6,
367 .version = IPTABLES_VERSION,
368 .size = XT_ALIGN(sizeof(struct xt_dccp_info)),
369 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)),
370 .help = &help,
371 .init = &init,
372 .parse = &parse,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000373 .print = &print,
374 .save = &save,
375 .extra_opts = opts
Harald Weltee40b11d2005-08-06 21:13:04 +0000376};
377
378void _init(void)
379{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000380 xtables_register_match(&dccp);
381 xtables_register_match(&dccp6);
Harald Weltee40b11d2005-08-06 21:13:04 +0000382}
383