1 #include <stdio.h>
2 #include <netdb.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <xtables.h>
6 #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
7 #include <linux/netfilter_ipv4/ip_tables.h>
8 #include <linux/netfilter_ipv6/ip6_tables.h>
9 #include <linux/netfilter/xt_multiport.h>
10
11 enum {
12 O_SOURCE_PORTS = 0,
13 O_DEST_PORTS,
14 O_SD_PORTS,
15 F_SOURCE_PORTS = 1 << O_SOURCE_PORTS,
16 F_DEST_PORTS = 1 << O_DEST_PORTS,
17 F_SD_PORTS = 1 << O_SD_PORTS,
18 F_ANY = F_SOURCE_PORTS | F_DEST_PORTS | F_SD_PORTS,
19 };
20
21 /* Function which prints out usage message. */
multiport_help(void)22 static void multiport_help(void)
23 {
24 printf(
25 "multiport match options:\n"
26 " --source-ports port[,port,port...]\n"
27 " --sports ...\n"
28 " match source port(s)\n"
29 " --destination-ports port[,port,port...]\n"
30 " --dports ...\n"
31 " match destination port(s)\n"
32 " --ports port[,port,port]\n"
33 " match both source and destination port(s)\n"
34 " NOTE: this kernel does not support port ranges in multiport.\n");
35 }
36
multiport_help_v1(void)37 static void multiport_help_v1(void)
38 {
39 printf(
40 "multiport match options:\n"
41 "[!] --source-ports port[,port:port,port...]\n"
42 " --sports ...\n"
43 " match source port(s)\n"
44 "[!] --destination-ports port[,port:port,port...]\n"
45 " --dports ...\n"
46 " match destination port(s)\n"
47 "[!] --ports port[,port:port,port]\n"
48 " match both source and destination port(s)\n");
49 }
50
51 static const struct xt_option_entry multiport_opts[] = {
52 {.name = "source-ports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING,
53 .excl = F_ANY, .flags = XTOPT_INVERT},
54 {.name = "sports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING,
55 .excl = F_ANY, .flags = XTOPT_INVERT},
56 {.name = "destination-ports", .id = O_DEST_PORTS,
57 .type = XTTYPE_STRING, .excl = F_ANY, .flags = XTOPT_INVERT},
58 {.name = "dports", .id = O_DEST_PORTS, .type = XTTYPE_STRING,
59 .excl = F_ANY, .flags = XTOPT_INVERT},
60 {.name = "ports", .id = O_SD_PORTS, .type = XTTYPE_STRING,
61 .excl = F_ANY, .flags = XTOPT_INVERT},
62 XTOPT_TABLEEND,
63 };
64
65 static const char *
proto_to_name(uint8_t proto)66 proto_to_name(uint8_t proto)
67 {
68 switch (proto) {
69 case IPPROTO_TCP:
70 return "tcp";
71 case IPPROTO_UDP:
72 return "udp";
73 case IPPROTO_UDPLITE:
74 return "udplite";
75 case IPPROTO_SCTP:
76 return "sctp";
77 case IPPROTO_DCCP:
78 return "dccp";
79 default:
80 return NULL;
81 }
82 }
83
84 static unsigned int
parse_multi_ports(const char * portstring,uint16_t * ports,const char * proto)85 parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto)
86 {
87 char *buffer, *cp, *next;
88 unsigned int i;
89
90 buffer = strdup(portstring);
91 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
92
93 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
94 {
95 next=strchr(cp, ',');
96 if (next) *next++='\0';
97 ports[i] = xtables_parse_port(cp, proto);
98 }
99 if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
100 free(buffer);
101 return i;
102 }
103
104 static void
parse_multi_ports_v1(const char * portstring,struct xt_multiport_v1 * multiinfo,const char * proto)105 parse_multi_ports_v1(const char *portstring,
106 struct xt_multiport_v1 *multiinfo,
107 const char *proto)
108 {
109 char *buffer, *cp, *next, *range;
110 unsigned int i;
111 uint16_t m;
112
113 buffer = strdup(portstring);
114 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
115
116 for (i=0; i<XT_MULTI_PORTS; i++)
117 multiinfo->pflags[i] = 0;
118
119 for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
120 next=strchr(cp, ',');
121 if (next) *next++='\0';
122 range = strchr(cp, ':');
123 if (range) {
124 if (i == XT_MULTI_PORTS-1)
125 xtables_error(PARAMETER_PROBLEM,
126 "too many ports specified");
127 *range++ = '\0';
128 }
129 multiinfo->ports[i] = xtables_parse_port(cp, proto);
130 if (range) {
131 multiinfo->pflags[i] = 1;
132 multiinfo->ports[++i] = xtables_parse_port(range, proto);
133 if (multiinfo->ports[i-1] >= multiinfo->ports[i])
134 xtables_error(PARAMETER_PROBLEM,
135 "invalid portrange specified");
136 m <<= 1;
137 }
138 }
139 multiinfo->count = i;
140 if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
141 free(buffer);
142 }
143
144 static const char *
check_proto(uint16_t pnum,uint8_t invflags)145 check_proto(uint16_t pnum, uint8_t invflags)
146 {
147 const char *proto;
148
149 if (invflags & XT_INV_PROTO)
150 xtables_error(PARAMETER_PROBLEM,
151 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
152
153 if ((proto = proto_to_name(pnum)) != NULL)
154 return proto;
155 else if (!pnum)
156 xtables_error(PARAMETER_PROBLEM,
157 "multiport needs `-p tcp', `-p udp', `-p udplite', "
158 "`-p sctp' or `-p dccp'");
159 else
160 xtables_error(PARAMETER_PROBLEM,
161 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
162 }
163
__multiport_parse(struct xt_option_call * cb,uint16_t pnum,uint8_t invflags)164 static void __multiport_parse(struct xt_option_call *cb, uint16_t pnum,
165 uint8_t invflags)
166 {
167 const char *proto;
168 struct xt_multiport *multiinfo = cb->data;
169
170 xtables_option_parse(cb);
171 switch (cb->entry->id) {
172 case O_SOURCE_PORTS:
173 proto = check_proto(pnum, invflags);
174 multiinfo->count = parse_multi_ports(cb->arg,
175 multiinfo->ports, proto);
176 multiinfo->flags = XT_MULTIPORT_SOURCE;
177 break;
178 case O_DEST_PORTS:
179 proto = check_proto(pnum, invflags);
180 multiinfo->count = parse_multi_ports(cb->arg,
181 multiinfo->ports, proto);
182 multiinfo->flags = XT_MULTIPORT_DESTINATION;
183 break;
184 case O_SD_PORTS:
185 proto = check_proto(pnum, invflags);
186 multiinfo->count = parse_multi_ports(cb->arg,
187 multiinfo->ports, proto);
188 multiinfo->flags = XT_MULTIPORT_EITHER;
189 break;
190 }
191 if (cb->invert)
192 xtables_error(PARAMETER_PROBLEM,
193 "multiport.0 does not support invert");
194 }
195
multiport_parse(struct xt_option_call * cb)196 static void multiport_parse(struct xt_option_call *cb)
197 {
198 const struct ipt_entry *entry = cb->xt_entry;
199 return __multiport_parse(cb,
200 entry->ip.proto, entry->ip.invflags);
201 }
202
multiport_parse6(struct xt_option_call * cb)203 static void multiport_parse6(struct xt_option_call *cb)
204 {
205 const struct ip6t_entry *entry = cb->xt_entry;
206 return __multiport_parse(cb,
207 entry->ipv6.proto, entry->ipv6.invflags);
208 }
209
__multiport_parse_v1(struct xt_option_call * cb,uint16_t pnum,uint8_t invflags)210 static void __multiport_parse_v1(struct xt_option_call *cb, uint16_t pnum,
211 uint8_t invflags)
212 {
213 const char *proto;
214 struct xt_multiport_v1 *multiinfo = cb->data;
215
216 xtables_option_parse(cb);
217 switch (cb->entry->id) {
218 case O_SOURCE_PORTS:
219 proto = check_proto(pnum, invflags);
220 parse_multi_ports_v1(cb->arg, multiinfo, proto);
221 multiinfo->flags = XT_MULTIPORT_SOURCE;
222 break;
223 case O_DEST_PORTS:
224 proto = check_proto(pnum, invflags);
225 parse_multi_ports_v1(cb->arg, multiinfo, proto);
226 multiinfo->flags = XT_MULTIPORT_DESTINATION;
227 break;
228 case O_SD_PORTS:
229 proto = check_proto(pnum, invflags);
230 parse_multi_ports_v1(cb->arg, multiinfo, proto);
231 multiinfo->flags = XT_MULTIPORT_EITHER;
232 break;
233 }
234 if (cb->invert)
235 multiinfo->invert = 1;
236 }
237
multiport_parse_v1(struct xt_option_call * cb)238 static void multiport_parse_v1(struct xt_option_call *cb)
239 {
240 const struct ipt_entry *entry = cb->xt_entry;
241 return __multiport_parse_v1(cb,
242 entry->ip.proto, entry->ip.invflags);
243 }
244
multiport_parse6_v1(struct xt_option_call * cb)245 static void multiport_parse6_v1(struct xt_option_call *cb)
246 {
247 const struct ip6t_entry *entry = cb->xt_entry;
248 return __multiport_parse_v1(cb,
249 entry->ipv6.proto, entry->ipv6.invflags);
250 }
251
multiport_check(struct xt_fcheck_call * cb)252 static void multiport_check(struct xt_fcheck_call *cb)
253 {
254 if (cb->xflags == 0)
255 xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
256 }
257
258 static const char *
port_to_service(int port,uint8_t proto)259 port_to_service(int port, uint8_t proto)
260 {
261 const struct servent *service;
262
263 if ((service = getservbyport(htons(port), proto_to_name(proto))))
264 return service->s_name;
265
266 return NULL;
267 }
268
269 static void
print_port(uint16_t port,uint8_t protocol,int numeric)270 print_port(uint16_t port, uint8_t protocol, int numeric)
271 {
272 const 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 static void
__multiport_print(const struct xt_entry_match * match,int numeric,uint16_t proto)281 __multiport_print(const struct xt_entry_match *match, int numeric,
282 uint16_t proto)
283 {
284 const struct xt_multiport *multiinfo
285 = (const struct xt_multiport *)match->data;
286 unsigned int i;
287
288 printf(" multiport ");
289
290 switch (multiinfo->flags) {
291 case XT_MULTIPORT_SOURCE:
292 printf("sports ");
293 break;
294
295 case XT_MULTIPORT_DESTINATION:
296 printf("dports ");
297 break;
298
299 case XT_MULTIPORT_EITHER:
300 printf("ports ");
301 break;
302
303 default:
304 printf("ERROR ");
305 break;
306 }
307
308 for (i=0; i < multiinfo->count; i++) {
309 printf("%s", i ? "," : "");
310 print_port(multiinfo->ports[i], proto, numeric);
311 }
312 }
313
multiport_print(const void * ip_void,const struct xt_entry_match * match,int numeric)314 static void multiport_print(const void *ip_void,
315 const struct xt_entry_match *match, int numeric)
316 {
317 const struct ipt_ip *ip = ip_void;
318 __multiport_print(match, numeric, ip->proto);
319 }
320
multiport_print6(const void * ip_void,const struct xt_entry_match * match,int numeric)321 static void multiport_print6(const void *ip_void,
322 const struct xt_entry_match *match, int numeric)
323 {
324 const struct ip6t_ip6 *ip = ip_void;
325 __multiport_print(match, numeric, ip->proto);
326 }
327
__multiport_print_v1(const struct xt_entry_match * match,int numeric,uint16_t proto)328 static void __multiport_print_v1(const struct xt_entry_match *match,
329 int numeric, uint16_t proto)
330 {
331 const struct xt_multiport_v1 *multiinfo
332 = (const struct xt_multiport_v1 *)match->data;
333 unsigned int i;
334
335 printf(" multiport ");
336
337 switch (multiinfo->flags) {
338 case XT_MULTIPORT_SOURCE:
339 printf("sports ");
340 break;
341
342 case XT_MULTIPORT_DESTINATION:
343 printf("dports ");
344 break;
345
346 case XT_MULTIPORT_EITHER:
347 printf("ports ");
348 break;
349
350 default:
351 printf("ERROR ");
352 break;
353 }
354
355 if (multiinfo->invert)
356 printf(" !");
357
358 for (i=0; i < multiinfo->count; i++) {
359 printf("%s", i ? "," : "");
360 print_port(multiinfo->ports[i], proto, numeric);
361 if (multiinfo->pflags[i]) {
362 printf(":");
363 print_port(multiinfo->ports[++i], proto, numeric);
364 }
365 }
366 }
367
multiport_print_v1(const void * ip_void,const struct xt_entry_match * match,int numeric)368 static void multiport_print_v1(const void *ip_void,
369 const struct xt_entry_match *match, int numeric)
370 {
371 const struct ipt_ip *ip = ip_void;
372 __multiport_print_v1(match, numeric, ip->proto);
373 }
374
multiport_print6_v1(const void * ip_void,const struct xt_entry_match * match,int numeric)375 static void multiport_print6_v1(const void *ip_void,
376 const struct xt_entry_match *match, int numeric)
377 {
378 const struct ip6t_ip6 *ip = ip_void;
379 __multiport_print_v1(match, numeric, ip->proto);
380 }
381
__multiport_save(const struct xt_entry_match * match,uint16_t proto)382 static void __multiport_save(const struct xt_entry_match *match,
383 uint16_t proto)
384 {
385 const struct xt_multiport *multiinfo
386 = (const struct xt_multiport *)match->data;
387 unsigned int i;
388
389 switch (multiinfo->flags) {
390 case XT_MULTIPORT_SOURCE:
391 printf(" --sports ");
392 break;
393
394 case XT_MULTIPORT_DESTINATION:
395 printf(" --dports ");
396 break;
397
398 case XT_MULTIPORT_EITHER:
399 printf(" --ports ");
400 break;
401 }
402
403 for (i=0; i < multiinfo->count; i++) {
404 printf("%s", i ? "," : "");
405 print_port(multiinfo->ports[i], proto, 1);
406 }
407 }
408
multiport_save(const void * ip_void,const struct xt_entry_match * match)409 static void multiport_save(const void *ip_void,
410 const struct xt_entry_match *match)
411 {
412 const struct ipt_ip *ip = ip_void;
413 __multiport_save(match, ip->proto);
414 }
415
multiport_save6(const void * ip_void,const struct xt_entry_match * match)416 static void multiport_save6(const void *ip_void,
417 const struct xt_entry_match *match)
418 {
419 const struct ip6t_ip6 *ip = ip_void;
420 __multiport_save(match, ip->proto);
421 }
422
__multiport_save_v1(const struct xt_entry_match * match,uint16_t proto)423 static void __multiport_save_v1(const struct xt_entry_match *match,
424 uint16_t proto)
425 {
426 const struct xt_multiport_v1 *multiinfo
427 = (const struct xt_multiport_v1 *)match->data;
428 unsigned int i;
429
430 if (multiinfo->invert)
431 printf(" !");
432
433 switch (multiinfo->flags) {
434 case XT_MULTIPORT_SOURCE:
435 printf(" --sports ");
436 break;
437
438 case XT_MULTIPORT_DESTINATION:
439 printf(" --dports ");
440 break;
441
442 case XT_MULTIPORT_EITHER:
443 printf(" --ports ");
444 break;
445 }
446
447 for (i=0; i < multiinfo->count; i++) {
448 printf("%s", i ? "," : "");
449 print_port(multiinfo->ports[i], proto, 1);
450 if (multiinfo->pflags[i]) {
451 printf(":");
452 print_port(multiinfo->ports[++i], proto, 1);
453 }
454 }
455 }
456
multiport_save_v1(const void * ip_void,const struct xt_entry_match * match)457 static void multiport_save_v1(const void *ip_void,
458 const struct xt_entry_match *match)
459 {
460 const struct ipt_ip *ip = ip_void;
461 __multiport_save_v1(match, ip->proto);
462 }
463
multiport_save6_v1(const void * ip_void,const struct xt_entry_match * match)464 static void multiport_save6_v1(const void *ip_void,
465 const struct xt_entry_match *match)
466 {
467 const struct ip6t_ip6 *ip = ip_void;
468 __multiport_save_v1(match, ip->proto);
469 }
470
471 static struct xtables_match multiport_mt_reg[] = {
472 {
473 .family = NFPROTO_IPV4,
474 .name = "multiport",
475 .revision = 0,
476 .version = XTABLES_VERSION,
477 .size = XT_ALIGN(sizeof(struct xt_multiport)),
478 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
479 .help = multiport_help,
480 .x6_parse = multiport_parse,
481 .x6_fcheck = multiport_check,
482 .print = multiport_print,
483 .save = multiport_save,
484 .x6_options = multiport_opts,
485 },
486 {
487 .family = NFPROTO_IPV6,
488 .name = "multiport",
489 .revision = 0,
490 .version = XTABLES_VERSION,
491 .size = XT_ALIGN(sizeof(struct xt_multiport)),
492 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
493 .help = multiport_help,
494 .x6_parse = multiport_parse6,
495 .x6_fcheck = multiport_check,
496 .print = multiport_print6,
497 .save = multiport_save6,
498 .x6_options = multiport_opts,
499 },
500 {
501 .family = NFPROTO_IPV4,
502 .name = "multiport",
503 .version = XTABLES_VERSION,
504 .revision = 1,
505 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
506 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
507 .help = multiport_help_v1,
508 .x6_parse = multiport_parse_v1,
509 .x6_fcheck = multiport_check,
510 .print = multiport_print_v1,
511 .save = multiport_save_v1,
512 .x6_options = multiport_opts,
513 },
514 {
515 .family = NFPROTO_IPV6,
516 .name = "multiport",
517 .version = XTABLES_VERSION,
518 .revision = 1,
519 .size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
520 .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
521 .help = multiport_help_v1,
522 .x6_parse = multiport_parse6_v1,
523 .x6_fcheck = multiport_check,
524 .print = multiport_print6_v1,
525 .save = multiport_save6_v1,
526 .x6_options = multiport_opts,
527 },
528 };
529
530 void
_init(void)531 _init(void)
532 {
533 xtables_register_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
534 }
535