Tomato 1.28
[tomato.git] / release / src / router / iptables / extensions / libipt_multiport.c
blob2a10abd4f3a2f35048600fb856012b3d8e7d4bc2
1 /* 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 <iptables.h>
8 /* To ensure that iptables compiles with an old kernel */
9 #include "../include/linux/netfilter_ipv4/ipt_multiport.h"
11 /* Function which prints out usage message. */
12 static void
13 help(void)
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"
24 " match both source and destination port(s)\n"
25 " NOTE: this kernel does not support port ranges in multiport.\n",
26 IPTABLES_VERSION);
29 static void
30 help_v1(void)
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"
41 " match both source and destination port(s)\n",
42 IPTABLES_VERSION);
45 static 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}
54 static char *
55 proto_to_name(u_int8_t proto)
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;
71 static unsigned int
72 parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
74 char *buffer, *cp, *next;
75 unsigned int i;
77 buffer = strdup(portstring);
78 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
80 for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next,i++)
82 next=strchr(cp, ',');
83 if (next) *next++='\0';
84 ports[i] = parse_port(cp, proto);
86 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
87 free(buffer);
88 return i;
91 static void
92 parse_multi_ports_v1(const char *portstring,
93 struct ipt_multiport_v1 *multiinfo,
94 const char *proto)
96 char *buffer, *cp, *next, *range;
97 unsigned int i;
98 u_int16_t m;
100 buffer = strdup(portstring);
101 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
103 for (i=0; i<IPT_MULTI_PORTS; i++)
104 multiinfo->pflags[i] = 0;
106 for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next, i++) {
107 next=strchr(cp, ',');
108 if (next) *next++='\0';
109 range = strchr(cp, ':');
110 if (range) {
111 if (i == IPT_MULTI_PORTS-1)
112 exit_error(PARAMETER_PROBLEM,
113 "too many ports specified");
114 *range++ = '\0';
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;
126 multiinfo->count = i;
127 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
128 free(buffer);
131 /* Initialize the match. */
132 static void
133 init(struct ipt_entry_match *m, unsigned int *nfcache)
137 static const char *
138 check_proto(const struct ipt_entry *entry)
140 char *proto;
142 if (entry->ip.invflags & IPT_INV_PROTO)
143 exit_error(PARAMETER_PROBLEM,
144 "multiport only works with TCP or UDP");
146 if ((proto = proto_to_name(entry->ip.proto)) != NULL)
147 return proto;
148 else if (!entry->ip.proto)
149 exit_error(PARAMETER_PROBLEM,
150 "multiport needs `-p tcp', `-p udp', `-p sctp' or `-p dccp'");
151 else
152 exit_error(PARAMETER_PROBLEM,
153 "multiport only works with TCP, UDP, SCTP and DCCP");
156 /* Function which parses command options; returns true if it
157 ate an option */
158 static int
159 parse(int c, char **argv, int invert, unsigned int *flags,
160 const struct ipt_entry *entry,
161 unsigned int *nfcache,
162 struct ipt_entry_match **match)
164 const char *proto;
165 struct ipt_multiport *multiinfo
166 = (struct ipt_multiport *)(*match)->data;
168 switch (c) {
169 case '1':
170 check_inverse(argv[optind-1], &invert, &optind, 0);
171 proto = check_proto(entry);
172 multiinfo->count = parse_multi_ports(argv[optind-1],
173 multiinfo->ports, proto);
174 multiinfo->flags = IPT_MULTIPORT_SOURCE;
175 break;
177 case '2':
178 check_inverse(argv[optind-1], &invert, &optind, 0);
179 proto = check_proto(entry);
180 multiinfo->count = parse_multi_ports(argv[optind-1],
181 multiinfo->ports, proto);
182 multiinfo->flags = IPT_MULTIPORT_DESTINATION;
183 break;
185 case '3':
186 check_inverse(argv[optind-1], &invert, &optind, 0);
187 proto = check_proto(entry);
188 multiinfo->count = parse_multi_ports(argv[optind-1],
189 multiinfo->ports, proto);
190 multiinfo->flags = IPT_MULTIPORT_EITHER;
191 break;
193 default:
194 return 0;
197 if (invert)
198 exit_error(PARAMETER_PROBLEM,
199 "multiport does not support invert");
201 if (*flags)
202 exit_error(PARAMETER_PROBLEM,
203 "multiport can only have one option");
204 *flags = 1;
205 return 1;
208 static int
209 parse_v1(int c, char **argv, int invert, unsigned int *flags,
210 const struct ipt_entry *entry,
211 unsigned int *nfcache,
212 struct ipt_entry_match **match)
214 const char *proto;
215 struct ipt_multiport_v1 *multiinfo
216 = (struct ipt_multiport_v1 *)(*match)->data;
218 switch (c) {
219 case '1':
220 check_inverse(argv[optind-1], &invert, &optind, 0);
221 proto = check_proto(entry);
222 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
223 multiinfo->flags = IPT_MULTIPORT_SOURCE;
224 break;
226 case '2':
227 check_inverse(argv[optind-1], &invert, &optind, 0);
228 proto = check_proto(entry);
229 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
230 multiinfo->flags = IPT_MULTIPORT_DESTINATION;
231 break;
233 case '3':
234 check_inverse(argv[optind-1], &invert, &optind, 0);
235 proto = check_proto(entry);
236 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
237 multiinfo->flags = IPT_MULTIPORT_EITHER;
238 break;
240 default:
241 return 0;
244 if (invert)
245 multiinfo->invert = 1;
247 if (*flags)
248 exit_error(PARAMETER_PROBLEM,
249 "multiport can only have one option");
250 *flags = 1;
251 return 1;
254 /* Final check; must specify something. */
255 static void
256 final_check(unsigned int flags)
258 if (!flags)
259 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
262 static char *
263 port_to_service(int port, u_int8_t proto)
265 struct servent *service;
267 if ((service = getservbyport(htons(port), proto_to_name(proto))))
268 return service->s_name;
270 return NULL;
273 static void
274 print_port(u_int16_t port, u_int8_t protocol, int numeric)
276 char *service;
278 if (numeric || (service = port_to_service(port, protocol)) == NULL)
279 printf("%u", port);
280 else
281 printf("%s", service);
284 /* Prints out the matchinfo. */
285 static void
286 print(const struct ipt_ip *ip,
287 const struct ipt_entry_match *match,
288 int numeric)
290 const struct ipt_multiport *multiinfo
291 = (const struct ipt_multiport *)match->data;
292 unsigned int i;
294 printf("multiport ");
296 switch (multiinfo->flags) {
297 case IPT_MULTIPORT_SOURCE:
298 printf("sports ");
299 break;
301 case IPT_MULTIPORT_DESTINATION:
302 printf("dports ");
303 break;
305 case IPT_MULTIPORT_EITHER:
306 printf("ports ");
307 break;
309 default:
310 printf("ERROR ");
311 break;
314 for (i=0; i < multiinfo->count; i++) {
315 printf("%s", i ? "," : "");
316 print_port(multiinfo->ports[i], ip->proto, numeric);
318 printf(" ");
321 static void
322 print_v1(const struct ipt_ip *ip,
323 const struct ipt_entry_match *match,
324 int numeric)
326 const struct ipt_multiport_v1 *multiinfo
327 = (const struct ipt_multiport_v1 *)match->data;
328 unsigned int i;
330 printf("multiport ");
332 switch (multiinfo->flags) {
333 case IPT_MULTIPORT_SOURCE:
334 printf("sports ");
335 break;
337 case IPT_MULTIPORT_DESTINATION:
338 printf("dports ");
339 break;
341 case IPT_MULTIPORT_EITHER:
342 printf("ports ");
343 break;
345 default:
346 printf("ERROR ");
347 break;
350 if (multiinfo->invert)
351 printf("! ");
353 for (i=0; i < multiinfo->count; i++) {
354 printf("%s", i ? "," : "");
355 print_port(multiinfo->ports[i], ip->proto, numeric);
356 if (multiinfo->pflags[i]) {
357 printf(":");
358 print_port(multiinfo->ports[++i], ip->proto, numeric);
361 printf(" ");
364 /* Saves the union ipt_matchinfo in parsable form to stdout. */
365 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
367 const struct ipt_multiport *multiinfo
368 = (const struct ipt_multiport *)match->data;
369 unsigned int i;
371 switch (multiinfo->flags) {
372 case IPT_MULTIPORT_SOURCE:
373 printf("--sports ");
374 break;
376 case IPT_MULTIPORT_DESTINATION:
377 printf("--dports ");
378 break;
380 case IPT_MULTIPORT_EITHER:
381 printf("--ports ");
382 break;
385 for (i=0; i < multiinfo->count; i++) {
386 printf("%s", i ? "," : "");
387 print_port(multiinfo->ports[i], ip->proto, 1);
389 printf(" ");
392 static void save_v1(const struct ipt_ip *ip,
393 const struct ipt_entry_match *match)
395 const struct ipt_multiport_v1 *multiinfo
396 = (const struct ipt_multiport_v1 *)match->data;
397 unsigned int i;
399 switch (multiinfo->flags) {
400 case IPT_MULTIPORT_SOURCE:
401 printf("--sports ");
402 break;
404 case IPT_MULTIPORT_DESTINATION:
405 printf("--dports ");
406 break;
408 case IPT_MULTIPORT_EITHER:
409 printf("--ports ");
410 break;
413 if (multiinfo->invert)
414 printf("! ");
416 for (i=0; i < multiinfo->count; i++) {
417 printf("%s", i ? "," : "");
418 print_port(multiinfo->ports[i], ip->proto, 1);
419 if (multiinfo->pflags[i]) {
420 printf(":");
421 print_port(multiinfo->ports[++i], ip->proto, 1);
424 printf(" ");
427 static struct iptables_match multiport = {
428 .next = NULL,
429 .name = "multiport",
430 .revision = 0,
431 .version = IPTABLES_VERSION,
432 .size = IPT_ALIGN(sizeof(struct ipt_multiport)),
433 .userspacesize = IPT_ALIGN(sizeof(struct ipt_multiport)),
434 .help = &help,
435 .init = &init,
436 .parse = &parse,
437 .final_check = &final_check,
438 .print = &print,
439 .save = &save,
440 .extra_opts = opts
443 static struct iptables_match multiport_v1 = {
444 .next = NULL,
445 .name = "multiport",
446 .version = IPTABLES_VERSION,
447 .revision = 1,
448 .size = IPT_ALIGN(sizeof(struct ipt_multiport_v1)),
449 .userspacesize = IPT_ALIGN(sizeof(struct ipt_multiport_v1)),
450 .help = &help_v1,
451 .init = &init,
452 .parse = &parse_v1,
453 .final_check = &final_check,
454 .print = &print_v1,
455 .save = &save_v1,
456 .extra_opts = opts
459 void
460 _init(void)
462 register_match(&multiport);
463 register_match(&multiport_v1);