blob: e1d6457d2fe3eb37a79d7022a5156c804753eb30 [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
Jan Engelhardt181dead2007-10-04 16:27:07 +000027static void dccp_init(struct xt_entry_match *m)
Harald Weltee40b11d2005-08-06 21:13:04 +000028{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000029 struct xt_dccp_info *einfo = (struct xt_dccp_info *)m->data;
Harald Weltee40b11d2005-08-06 21:13:04 +000030
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000031 memset(einfo, 0, sizeof(struct xt_dccp_info));
Harald Weltee40b11d2005-08-06 21:13:04 +000032}
33
Jan Engelhardt181dead2007-10-04 16:27:07 +000034static void dccp_help(void)
Harald Weltee40b11d2005-08-06 21:13:04 +000035{
36 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020037"dccp match options\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020038"[!] --source-port port[:port] match source port(s)\n"
Harald Weltee40b11d2005-08-06 21:13:04 +000039" --sport ...\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020040"[!] --destination-port port[:port] match destination port(s)\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020041" --dport ...\n");
Harald Weltee40b11d2005-08-06 21:13:04 +000042}
43
Jan Engelhardt181dead2007-10-04 16:27:07 +000044static const struct option dccp_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000045 { .name = "source-port", .has_arg = 1, .val = '1' },
46 { .name = "sport", .has_arg = 1, .val = '1' },
47 { .name = "destination-port", .has_arg = 1, .val = '2' },
48 { .name = "dport", .has_arg = 1, .val = '2' },
49 { .name = "dccp-types", .has_arg = 1, .val = '3' },
50 { .name = "dccp-option", .has_arg = 1, .val = '4' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000051 { .name = NULL }
Harald Weltee40b11d2005-08-06 21:13:04 +000052};
53
Harald Weltee40b11d2005-08-06 21:13:04 +000054static void
55parse_dccp_ports(const char *portstring,
56 u_int16_t *ports)
57{
58 char *buffer;
59 char *cp;
60
61 buffer = strdup(portstring);
62 DEBUGP("%s\n", portstring);
63 if ((cp = strchr(buffer, ':')) == NULL) {
Phil Oesterdbac8ad2006-07-20 17:01:54 +000064 ports[0] = ports[1] = parse_port(buffer, "dccp");
Harald Weltee40b11d2005-08-06 21:13:04 +000065 }
66 else {
67 *cp = '\0';
68 cp++;
69
Phil Oesterdbac8ad2006-07-20 17:01:54 +000070 ports[0] = buffer[0] ? parse_port(buffer, "dccp") : 0;
71 ports[1] = cp[0] ? parse_port(cp, "dccp") : 0xFFFF;
Harald Weltee40b11d2005-08-06 21:13:04 +000072
73 if (ports[0] > ports[1])
74 exit_error(PARAMETER_PROBLEM,
75 "invalid portrange (min > max)");
76 }
77 free(buffer);
78}
79
Jan Engelhardt0e2abed2007-10-04 16:25:58 +000080static const char *const dccp_pkt_types[] = {
Harald Weltee40b11d2005-08-06 21:13:04 +000081 [DCCP_PKT_REQUEST] = "REQUEST",
82 [DCCP_PKT_RESPONSE] = "RESPONSE",
83 [DCCP_PKT_DATA] = "DATA",
84 [DCCP_PKT_ACK] = "ACK",
85 [DCCP_PKT_DATAACK] = "DATAACK",
86 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
87 [DCCP_PKT_CLOSE] = "CLOSE",
88 [DCCP_PKT_RESET] = "RESET",
89 [DCCP_PKT_SYNC] = "SYNC",
90 [DCCP_PKT_SYNCACK] = "SYNCACK",
91 [DCCP_PKT_INVALID] = "INVALID",
92};
93
94static u_int16_t
95parse_dccp_types(const char *typestring)
96{
97 u_int16_t typemask = 0;
98 char *ptr, *buffer;
99
100 buffer = strdup(typestring);
101
102 for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
103 unsigned int i;
104 for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) {
105 if (!strcasecmp(dccp_pkt_types[i], ptr)) {
106 typemask |= (1 << i);
107 break;
108 }
109 }
110 if (i == sizeof(dccp_pkt_types)/sizeof(char *))
111 exit_error(PARAMETER_PROBLEM,
112 "Unknown DCCP type `%s'", ptr);
113 }
114
115 free(buffer);
116 return typemask;
117}
118
119static u_int8_t parse_dccp_option(char *optstring)
120{
121 unsigned int ret;
122
123 if (string_to_number(optstring, 1, 255, &ret) == -1)
124 exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'",
125 optstring);
126
127 return (u_int8_t)ret;
128}
129
130static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000131dccp_parse(int c, char **argv, int invert, unsigned int *flags,
132 const void *entry, struct xt_entry_match **match)
Harald Weltee40b11d2005-08-06 21:13:04 +0000133{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000134 struct xt_dccp_info *einfo
135 = (struct xt_dccp_info *)(*match)->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000136
137 switch (c) {
138 case '1':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000139 if (*flags & XT_DCCP_SRC_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000140 exit_error(PARAMETER_PROBLEM,
141 "Only one `--source-port' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000142 einfo->flags |= XT_DCCP_SRC_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000143 check_inverse(optarg, &invert, &optind, 0);
144 parse_dccp_ports(argv[optind-1], einfo->spts);
145 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000146 einfo->invflags |= XT_DCCP_SRC_PORTS;
147 *flags |= XT_DCCP_SRC_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000148 break;
149
150 case '2':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000151 if (*flags & XT_DCCP_DEST_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000152 exit_error(PARAMETER_PROBLEM,
153 "Only one `--destination-port' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000154 einfo->flags |= XT_DCCP_DEST_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000155 check_inverse(optarg, &invert, &optind, 0);
156 parse_dccp_ports(argv[optind-1], einfo->dpts);
157 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000158 einfo->invflags |= XT_DCCP_DEST_PORTS;
159 *flags |= XT_DCCP_DEST_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000160 break;
161
162 case '3':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000163 if (*flags & XT_DCCP_TYPE)
Harald Weltee40b11d2005-08-06 21:13:04 +0000164 exit_error(PARAMETER_PROBLEM,
165 "Only one `--dccp-types' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000166 einfo->flags |= XT_DCCP_TYPE;
Harald Weltee40b11d2005-08-06 21:13:04 +0000167 check_inverse(optarg, &invert, &optind, 0);
168 einfo->typemask = parse_dccp_types(argv[optind-1]);
169 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000170 einfo->invflags |= XT_DCCP_TYPE;
171 *flags |= XT_DCCP_TYPE;
Harald Weltee40b11d2005-08-06 21:13:04 +0000172 break;
173
174 case '4':
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000175 if (*flags & XT_DCCP_OPTION)
Harald Weltee40b11d2005-08-06 21:13:04 +0000176 exit_error(PARAMETER_PROBLEM,
177 "Only one `--dccp-option' allowed");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000178 einfo->flags |= XT_DCCP_OPTION;
Harald Weltee40b11d2005-08-06 21:13:04 +0000179 check_inverse(optarg, &invert, &optind, 0);
180 einfo->option = parse_dccp_option(argv[optind-1]);
181 if (invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000182 einfo->invflags |= XT_DCCP_OPTION;
183 *flags |= XT_DCCP_OPTION;
Harald Weltee40b11d2005-08-06 21:13:04 +0000184 break;
185 default:
186 return 0;
187 }
188 return 1;
189}
190
Harald Weltee40b11d2005-08-06 21:13:04 +0000191static char *
192port_to_service(int port)
193{
194 struct servent *service;
195
196 if ((service = getservbyport(htons(port), "dccp")))
197 return service->s_name;
198
199 return NULL;
200}
201
202static void
203print_port(u_int16_t port, int numeric)
204{
205 char *service;
206
207 if (numeric || (service = port_to_service(port)) == NULL)
208 printf("%u", port);
209 else
210 printf("%s", service);
211}
212
213static void
214print_ports(const char *name, u_int16_t min, u_int16_t max,
215 int invert, int numeric)
216{
217 const char *inv = invert ? "!" : "";
218
219 if (min != 0 || max != 0xFFFF || invert) {
220 printf("%s", name);
221 if (min == max) {
222 printf(":%s", inv);
223 print_port(min, numeric);
224 } else {
225 printf("s:%s", inv);
226 print_port(min, numeric);
227 printf(":");
228 print_port(max, numeric);
229 }
230 printf(" ");
231 }
232}
233
234static void
235print_types(u_int16_t types, int inverted, int numeric)
236{
237 int have_type = 0;
238
239 if (inverted)
240 printf("! ");
241
242 while (types) {
243 unsigned int i;
244
245 for (i = 0; !(types & (1 << i)); i++);
246
247 if (have_type)
248 printf(",");
249 else
250 have_type = 1;
251
252 if (numeric)
253 printf("%u", i);
254 else
255 printf("%s", dccp_pkt_types[i]);
256
257 types &= ~(1 << i);
258 }
259}
260
261static void
262print_option(u_int8_t option, int invert, int numeric)
263{
264 if (option || invert)
265 printf("option=%s%u ", invert ? "!" : "", option);
266}
267
Harald Weltee40b11d2005-08-06 21:13:04 +0000268static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000269dccp_print(const void *ip, const struct xt_entry_match *match, int numeric)
Harald Weltee40b11d2005-08-06 21:13:04 +0000270{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000271 const struct xt_dccp_info *einfo =
272 (const struct xt_dccp_info *)match->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000273
274 printf("dccp ");
275
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000276 if (einfo->flags & XT_DCCP_SRC_PORTS) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000277 print_ports("spt", einfo->spts[0], einfo->spts[1],
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000278 einfo->invflags & XT_DCCP_SRC_PORTS,
Harald Weltee40b11d2005-08-06 21:13:04 +0000279 numeric);
280 }
281
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000282 if (einfo->flags & XT_DCCP_DEST_PORTS) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000283 print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000284 einfo->invflags & XT_DCCP_DEST_PORTS,
Harald Weltee40b11d2005-08-06 21:13:04 +0000285 numeric);
286 }
287
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000288 if (einfo->flags & XT_DCCP_TYPE) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000289 print_types(einfo->typemask,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000290 einfo->invflags & XT_DCCP_TYPE,
Harald Weltee40b11d2005-08-06 21:13:04 +0000291 numeric);
292 }
293
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000294 if (einfo->flags & XT_DCCP_OPTION) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000295 print_option(einfo->option,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000296 einfo->invflags & XT_DCCP_OPTION, numeric);
Harald Weltee40b11d2005-08-06 21:13:04 +0000297 }
298}
299
Jan Engelhardt181dead2007-10-04 16:27:07 +0000300static void dccp_save(const void *ip, const struct xt_entry_match *match)
Harald Weltee40b11d2005-08-06 21:13:04 +0000301{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000302 const struct xt_dccp_info *einfo =
303 (const struct xt_dccp_info *)match->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000304
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000305 if (einfo->flags & XT_DCCP_SRC_PORTS) {
306 if (einfo->invflags & XT_DCCP_SRC_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000307 printf("! ");
308 if (einfo->spts[0] != einfo->spts[1])
309 printf("--sport %u:%u ",
310 einfo->spts[0], einfo->spts[1]);
311 else
312 printf("--sport %u ", einfo->spts[0]);
313 }
314
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000315 if (einfo->flags & XT_DCCP_DEST_PORTS) {
316 if (einfo->invflags & XT_DCCP_DEST_PORTS)
Harald Weltee40b11d2005-08-06 21:13:04 +0000317 printf("! ");
318 if (einfo->dpts[0] != einfo->dpts[1])
319 printf("--dport %u:%u ",
320 einfo->dpts[0], einfo->dpts[1]);
321 else
322 printf("--dport %u ", einfo->dpts[0]);
323 }
324
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000325 if (einfo->flags & XT_DCCP_TYPE) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000326 printf("--dccp-type ");
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000327 print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0);
Harald Weltee40b11d2005-08-06 21:13:04 +0000328 }
329
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000330 if (einfo->flags & XT_DCCP_OPTION) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000331 printf("--dccp-option %s%u ",
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000332 einfo->typemask & XT_DCCP_OPTION ? "! " : "",
Harald Weltee40b11d2005-08-06 21:13:04 +0000333 einfo->option);
334 }
335}
336
Jan Engelhardt181dead2007-10-04 16:27:07 +0000337static struct xtables_match dccp_match = {
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000338 .name = "dccp",
339 .family = AF_INET,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200340 .version = XTABLES_VERSION,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000341 .size = XT_ALIGN(sizeof(struct xt_dccp_info)),
342 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)),
Jan Engelhardt181dead2007-10-04 16:27:07 +0000343 .help = dccp_help,
344 .init = dccp_init,
345 .parse = dccp_parse,
346 .print = dccp_print,
347 .save = dccp_save,
348 .extra_opts = dccp_opts,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000349};
350
Jan Engelhardt181dead2007-10-04 16:27:07 +0000351static struct xtables_match dccp_match6 = {
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000352 .name = "dccp",
353 .family = AF_INET6,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200354 .version = XTABLES_VERSION,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000355 .size = XT_ALIGN(sizeof(struct xt_dccp_info)),
356 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)),
Jan Engelhardt181dead2007-10-04 16:27:07 +0000357 .help = dccp_help,
358 .init = dccp_init,
359 .parse = dccp_parse,
360 .print = dccp_print,
361 .save = dccp_save,
362 .extra_opts = dccp_opts,
Harald Weltee40b11d2005-08-06 21:13:04 +0000363};
364
365void _init(void)
366{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000367 xtables_register_match(&dccp_match);
368 xtables_register_match(&dccp_match6);
Harald Weltee40b11d2005-08-06 21:13:04 +0000369}