blob: 166abce167d58752e4992310cca3b8b3df167b34 [file] [log] [blame]
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +00001/* Shared library add-on to iptables to add multiple TCP port support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <ip6tables.h>
Rémi Denis-Courmont06652172006-10-20 12:24:34 +00008/* To ensure that iptables compiles with an old kernel */
9#include "../include/linux/netfilter_ipv6/ip6t_multiport.h"
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +000010
11/* Function which prints out usage message. */
12static void
13help(void)
14{
15 printf(
16"multiport v%s options:\n"
17" --source-ports port[,port,port...]\n"
18" --sports ...\n"
19" match source port(s)\n"
20" --destination-ports port[,port,port...]\n"
21" --dports ...\n"
22" match destination port(s)\n"
23" --ports port[,port,port]\n"
Rémi Denis-Courmont06652172006-10-20 12:24:34 +000024" match both source and destination port(s)\n"
25" NOTE: this kernel does not support port ranges in multiport.\n",
26IPTABLES_VERSION);
27}
28
29static void
30help_v1(void)
31{
32 printf(
33"multiport v%s options:\n"
34" --source-ports [!] port[,port:port,port...]\n"
35" --sports ...\n"
36" match source port(s)\n"
37" --destination-ports [!] port[,port:port,port...]\n"
38" --dports ...\n"
39" match destination port(s)\n"
40" --ports [!] port[,port:port,port]\n"
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +000041" match both source and destination port(s)\n",
Harald Welte80fe35d2002-05-29 13:08:15 +000042IPTABLES_VERSION);
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +000043}
44
45static struct option opts[] = {
46 { "source-ports", 1, 0, '1' },
47 { "sports", 1, 0, '1' }, /* synonym */
48 { "destination-ports", 1, 0, '2' },
49 { "dports", 1, 0, '2' }, /* synonym */
50 { "ports", 1, 0, '3' },
51 {0}
52};
53
Patrick McHardy2452baf2006-04-28 08:10:08 +000054static char *
55proto_to_name(u_int8_t proto)
56{
57 switch (proto) {
58 case IPPROTO_TCP:
59 return "tcp";
60 case IPPROTO_UDP:
61 return "udp";
62 case IPPROTO_SCTP:
63 return "sctp";
64 case IPPROTO_DCCP:
65 return "dccp";
66 default:
67 return NULL;
68 }
69}
70
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +000071static unsigned int
72parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
73{
74 char *buffer, *cp, *next;
75 unsigned int i;
76
77 buffer = strdup(portstring);
78 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
79
80 for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next,i++)
81 {
82 next=strchr(cp, ',');
83 if (next) *next++='\0';
84 ports[i] = parse_port(cp, proto);
85 }
86 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
87 free(buffer);
88 return i;
89}
90
Rémi Denis-Courmont06652172006-10-20 12:24:34 +000091static void
92parse_multi_ports_v1(const char *portstring,
93 struct ip6t_multiport_v1 *multiinfo,
94 const char *proto)
95{
96 char *buffer, *cp, *next, *range;
97 unsigned int i;
98 u_int16_t m;
99
100 buffer = strdup(portstring);
101 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
102
103 for (i=0; i<IP6T_MULTI_PORTS; i++)
104 multiinfo->pflags[i] = 0;
105
106 for (cp=buffer, i=0; cp && i<IP6T_MULTI_PORTS; cp=next, i++) {
107 next=strchr(cp, ',');
108 if (next) *next++='\0';
109 range = strchr(cp, ':');
110 if (range) {
111 if (i == IP6T_MULTI_PORTS-1)
112 exit_error(PARAMETER_PROBLEM,
113 "too many ports specified");
114 *range++ = '\0';
115 }
116 multiinfo->ports[i] = parse_port(cp, proto);
117 if (range) {
118 multiinfo->pflags[i] = 1;
119 multiinfo->ports[++i] = parse_port(range, proto);
120 if (multiinfo->ports[i-1] >= multiinfo->ports[i])
121 exit_error(PARAMETER_PROBLEM,
122 "invalid portrange specified");
123 m <<= 1;
124 }
125 }
126 multiinfo->count = i;
127 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
128 free(buffer);
129}
130
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000131/* Initialize the match. */
132static void
133init(struct ip6t_entry_match *m, unsigned int *nfcache)
134{
135}
136
137static const char *
138check_proto(const struct ip6t_entry *entry)
139{
Patrick McHardy2452baf2006-04-28 08:10:08 +0000140 char *proto;
141
142 if ((proto = proto_to_name(entry->ipv6.proto)) != NULL)
143 return proto;
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000144 else if (!entry->ipv6.proto)
145 exit_error(PARAMETER_PROBLEM,
Patrick McHardy2452baf2006-04-28 08:10:08 +0000146 "multiport needs `-p tcp', `-p udp', `-p sctp' or `-p dccp'");
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000147 else
148 exit_error(PARAMETER_PROBLEM,
Patrick McHardy2452baf2006-04-28 08:10:08 +0000149 "multiport only works with TCP, UDP, SCTP and DCCP");
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000150}
151
152/* Function which parses command options; returns true if it
153 ate an option */
154static int
155parse(int c, char **argv, int invert, unsigned int *flags,
156 const struct ip6t_entry *entry,
157 unsigned int *nfcache,
158 struct ip6t_entry_match **match)
159{
160 const char *proto;
161 struct ip6t_multiport *multiinfo
162 = (struct ip6t_multiport *)(*match)->data;
163
164 switch (c) {
165 case '1':
Patrick McHardyd0a2e8a2004-09-18 17:43:36 +0000166 check_inverse(argv[optind-1], &invert, &optind, 0);
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000167 proto = check_proto(entry);
168 multiinfo->count = parse_multi_ports(argv[optind-1],
169 multiinfo->ports, proto);
170 multiinfo->flags = IP6T_MULTIPORT_SOURCE;
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000171 break;
172
173 case '2':
Patrick McHardyd0a2e8a2004-09-18 17:43:36 +0000174 check_inverse(argv[optind-1], &invert, &optind, 0);
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000175 proto = check_proto(entry);
176 multiinfo->count = parse_multi_ports(argv[optind-1],
177 multiinfo->ports, proto);
178 multiinfo->flags = IP6T_MULTIPORT_DESTINATION;
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000179 break;
180
181 case '3':
Patrick McHardyd0a2e8a2004-09-18 17:43:36 +0000182 check_inverse(argv[optind-1], &invert, &optind, 0);
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000183 proto = check_proto(entry);
184 multiinfo->count = parse_multi_ports(argv[optind-1],
185 multiinfo->ports, proto);
186 multiinfo->flags = IP6T_MULTIPORT_EITHER;
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000187 break;
188
189 default:
190 return 0;
191 }
192
Patrick McHardyd0a2e8a2004-09-18 17:43:36 +0000193 if (invert)
194 exit_error(PARAMETER_PROBLEM,
195 "multiport does not support invert");
196
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000197 if (*flags)
198 exit_error(PARAMETER_PROBLEM,
199 "multiport can only have one option");
200 *flags = 1;
201 return 1;
202}
203
Rémi Denis-Courmont06652172006-10-20 12:24:34 +0000204static int
205parse_v1(int c, char **argv, int invert, unsigned int *flags,
206 const struct ip6t_entry *entry,
207 unsigned int *nfcache,
208 struct ip6t_entry_match **match)
209{
210 const char *proto;
211 struct ip6t_multiport_v1 *multiinfo
212 = (struct ip6t_multiport_v1 *)(*match)->data;
213
214 switch (c) {
215 case '1':
216 check_inverse(argv[optind-1], &invert, &optind, 0);
217 proto = check_proto(entry);
218 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
219 multiinfo->flags = IP6T_MULTIPORT_SOURCE;
220 break;
221
222 case '2':
223 check_inverse(argv[optind-1], &invert, &optind, 0);
224 proto = check_proto(entry);
225 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
226 multiinfo->flags = IP6T_MULTIPORT_DESTINATION;
227 break;
228
229 case '3':
230 check_inverse(argv[optind-1], &invert, &optind, 0);
231 proto = check_proto(entry);
232 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
233 multiinfo->flags = IP6T_MULTIPORT_EITHER;
234 break;
235
236 default:
237 return 0;
238 }
239
240 if (invert)
241 multiinfo->invert = 1;
242
243 if (*flags)
244 exit_error(PARAMETER_PROBLEM,
245 "multiport can only have one option");
246 *flags = 1;
247 return 1;
248}
249
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000250/* Final check; must specify something. */
251static void
252final_check(unsigned int flags)
253{
254 if (!flags)
255 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
256}
257
258static char *
259port_to_service(int port, u_int8_t proto)
260{
261 struct servent *service;
262
Patrick McHardy2452baf2006-04-28 08:10:08 +0000263 if ((service = getservbyport(htons(port), proto_to_name(proto))))
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000264 return service->s_name;
265
266 return NULL;
267}
268
269static void
270print_port(u_int16_t port, u_int8_t protocol, int numeric)
271{
272 char *service;
273
274 if (numeric || (service = port_to_service(port, protocol)) == NULL)
275 printf("%u", port);
276 else
277 printf("%s", service);
278}
279
280/* Prints out the matchinfo. */
281static void
282print(const struct ip6t_ip6 *ip,
283 const struct ip6t_entry_match *match,
284 int numeric)
285{
286 const struct ip6t_multiport *multiinfo
287 = (const struct ip6t_multiport *)match->data;
288 unsigned int i;
289
290 printf("multiport ");
291
292 switch (multiinfo->flags) {
293 case IP6T_MULTIPORT_SOURCE:
294 printf("sports ");
295 break;
296
297 case IP6T_MULTIPORT_DESTINATION:
298 printf("dports ");
299 break;
300
301 case IP6T_MULTIPORT_EITHER:
302 printf("ports ");
303 break;
304
305 default:
306 printf("ERROR ");
307 break;
308 }
309
310 for (i=0; i < multiinfo->count; i++) {
311 printf("%s", i ? "," : "");
312 print_port(multiinfo->ports[i], ip->proto, numeric);
313 }
314 printf(" ");
315}
316
Rémi Denis-Courmont06652172006-10-20 12:24:34 +0000317static void
318print_v1(const struct ip6t_ip6 *ip,
319 const struct ip6t_entry_match *match,
320 int numeric)
321{
322 const struct ip6t_multiport_v1 *multiinfo
323 = (const struct ip6t_multiport_v1 *)match->data;
324 unsigned int i;
325
326 printf("multiport ");
327
328 switch (multiinfo->flags) {
329 case IP6T_MULTIPORT_SOURCE:
330 printf("sports ");
331 break;
332
333 case IP6T_MULTIPORT_DESTINATION:
334 printf("dports ");
335 break;
336
337 case IP6T_MULTIPORT_EITHER:
338 printf("ports ");
339 break;
340
341 default:
342 printf("ERROR ");
343 break;
344 }
345
346 if (multiinfo->invert)
347 printf("! ");
348
349 for (i=0; i < multiinfo->count; i++) {
350 printf("%s", i ? "," : "");
351 print_port(multiinfo->ports[i], ip->proto, numeric);
352 if (multiinfo->pflags[i]) {
353 printf(":");
354 print_port(multiinfo->ports[++i], ip->proto, numeric);
355 }
356 }
357 printf(" ");
358}
359
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000360/* Saves the union ip6t_matchinfo in parsable form to stdout. */
361static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
362{
363 const struct ip6t_multiport *multiinfo
364 = (const struct ip6t_multiport *)match->data;
365 unsigned int i;
366
367 switch (multiinfo->flags) {
368 case IP6T_MULTIPORT_SOURCE:
369 printf("--sports ");
370 break;
371
372 case IP6T_MULTIPORT_DESTINATION:
373 printf("--dports ");
374 break;
375
376 case IP6T_MULTIPORT_EITHER:
377 printf("--ports ");
378 break;
379 }
380
381 for (i=0; i < multiinfo->count; i++) {
382 printf("%s", i ? "," : "");
Thomas Woerner01cbaa62003-07-14 20:01:29 +0000383 print_port(multiinfo->ports[i], ip->proto, 1);
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000384 }
385 printf(" ");
386}
387
Rémi Denis-Courmont06652172006-10-20 12:24:34 +0000388static void save_v1(const struct ip6t_ip6 *ip,
389 const struct ip6t_entry_match *match)
390{
391 const struct ip6t_multiport_v1 *multiinfo
392 = (const struct ip6t_multiport_v1 *)match->data;
393 unsigned int i;
394
395 switch (multiinfo->flags) {
396 case IP6T_MULTIPORT_SOURCE:
397 printf("--sports ");
398 break;
399
400 case IP6T_MULTIPORT_DESTINATION:
401 printf("--dports ");
402 break;
403
404 case IP6T_MULTIPORT_EITHER:
405 printf("--ports ");
406 break;
407 }
408
409 if (multiinfo->invert)
410 printf("! ");
411
412 for (i=0; i < multiinfo->count; i++) {
413 printf("%s", i ? "," : "");
414 print_port(multiinfo->ports[i], ip->proto, 1);
415 if (multiinfo->pflags[i]) {
416 printf(":");
417 print_port(multiinfo->ports[++i], ip->proto, 1);
418 }
419 }
420 printf(" ");
421}
422
Harald Welte02aa7332005-02-01 15:38:20 +0000423static struct ip6tables_match multiport = {
424 .name = "multiport",
425 .version = IPTABLES_VERSION,
426 .size = IP6T_ALIGN(sizeof(struct ip6t_multiport)),
427 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_multiport)),
428 .help = &help,
429 .init = &init,
Harald Welte3d121872005-02-01 15:41:07 +0000430 .parse = &parse,
Harald Welte02aa7332005-02-01 15:38:20 +0000431 .final_check = &final_check,
432 .print = &print,
433 .save = &save,
434 .extra_opts = opts,
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000435};
436
Rémi Denis-Courmont06652172006-10-20 12:24:34 +0000437static struct ip6tables_match multiport_v1 = {
438 .next = NULL,
439 .name = "multiport",
440 .revision = 1,
441 .version = IPTABLES_VERSION,
442 .size = IP6T_ALIGN(sizeof(struct ip6t_multiport_v1)),
443 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_multiport_v1)),
444 .help = &help_v1,
445 .init = &init,
446 .parse = &parse_v1,
447 .final_check = &final_check,
448 .print = &print_v1,
449 .save = &save_v1,
450 .extra_opts = opts
451};
452
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000453void
454_init(void)
455{
456 register_match6(&multiport);
Rémi Denis-Courmont06652172006-10-20 12:24:34 +0000457 register_match6(&multiport_v1);
Jan Rekorajskidc8af0f2001-02-16 15:19:51 +0000458}