1 /* Shared library add-on to iptables to add multiple TCP port support. */
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. */
16 "multiport v%s options:\n"
17 " --source-ports port[,port,port...]\n"
19 " match source port(s)\n"
20 " --destination-ports port[,port,port...]\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",
33 "multiport v%s options:\n"
34 " --source-ports [!] port[,port:port,port...]\n"
36 " match source port(s)\n"
37 " --destination-ports [!] port[,port:port,port...]\n"
39 " match destination port(s)\n"
40 " --ports [!] port[,port:port,port]\n"
41 " match both source and destination port(s)\n",
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' },
55 service_to_port(const char *name, const char *proto)
57 struct servent *service;
59 if ((service = getservbyname(name, proto)) != NULL)
60 return ntohs((unsigned short) service->s_port);
66 parse_port(const char *port, const char *proto)
70 if (string_to_number(port, 0, 65535, &portnum) != -1 ||
71 (portnum = service_to_port(port, proto)) != -1)
72 return (u_int16_t)portnum;
74 exit_error(PARAMETER_PROBLEM,
75 "invalid port/service `%s' specified", port);
79 parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
81 char *buffer, *cp, *next;
84 buffer = strdup(portstring);
85 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
87 for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next,i++)
90 if (next) *next++='\0';
91 ports[i] = parse_port(cp, proto);
93 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
99 parse_multi_ports_v1(const char *portstring,
100 struct ipt_multiport_v1 *multiinfo,
103 char *buffer, *cp, *next, *range;
107 buffer = strdup(portstring);
108 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
110 for (i=0; i<IPT_MULTI_PORTS; i++)
111 multiinfo->pflags[i] = 0;
113 for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next, i++) {
114 next=strchr(cp, ',');
115 if (next) *next++='\0';
116 range = strchr(cp, ':');
118 if (i == IPT_MULTI_PORTS-1)
119 exit_error(PARAMETER_PROBLEM,
120 "too many ports specified");
123 multiinfo->ports[i] = parse_port(cp, proto);
125 multiinfo->pflags[i] = 1;
126 multiinfo->ports[++i] = parse_port(range, proto);
127 if (multiinfo->ports[i-1] >= multiinfo->ports[i])
128 exit_error(PARAMETER_PROBLEM,
129 "invalid portrange specified");
133 multiinfo->count = i;
134 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
138 /* Initialize the match. */
140 init(struct ipt_entry_match *m, unsigned int *nfcache)
145 check_proto(const struct ipt_entry *entry)
147 if (entry->ip.invflags & IPT_INV_PROTO)
148 exit_error(PARAMETER_PROBLEM,
149 "multiport only works with TCP or UDP");
151 if (entry->ip.proto == IPPROTO_TCP)
153 else if (entry->ip.proto == IPPROTO_UDP)
155 else if (!entry->ip.proto)
156 exit_error(PARAMETER_PROBLEM,
157 "multiport needs `-p tcp' or `-p udp'");
159 exit_error(PARAMETER_PROBLEM,
160 "multiport only works with TCP or UDP");
163 /* Function which parses command options; returns true if it
166 parse(int c, char **argv, int invert, unsigned int *flags,
167 const struct ipt_entry *entry,
168 unsigned int *nfcache,
169 struct ipt_entry_match **match)
172 struct ipt_multiport *multiinfo
173 = (struct ipt_multiport *)(*match)->data;
177 check_inverse(argv[optind-1], &invert, &optind, 0);
178 proto = check_proto(entry);
179 multiinfo->count = parse_multi_ports(argv[optind-1],
180 multiinfo->ports, proto);
181 multiinfo->flags = IPT_MULTIPORT_SOURCE;
185 check_inverse(argv[optind-1], &invert, &optind, 0);
186 proto = check_proto(entry);
187 multiinfo->count = parse_multi_ports(argv[optind-1],
188 multiinfo->ports, proto);
189 multiinfo->flags = IPT_MULTIPORT_DESTINATION;
193 check_inverse(argv[optind-1], &invert, &optind, 0);
194 proto = check_proto(entry);
195 multiinfo->count = parse_multi_ports(argv[optind-1],
196 multiinfo->ports, proto);
197 multiinfo->flags = IPT_MULTIPORT_EITHER;
205 exit_error(PARAMETER_PROBLEM,
206 "multiport does not support invert");
209 exit_error(PARAMETER_PROBLEM,
210 "multiport can only have one option");
216 parse_v1(int c, char **argv, int invert, unsigned int *flags,
217 const struct ipt_entry *entry,
218 unsigned int *nfcache,
219 struct ipt_entry_match **match)
222 struct ipt_multiport_v1 *multiinfo
223 = (struct ipt_multiport_v1 *)(*match)->data;
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_SOURCE;
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_DESTINATION;
241 check_inverse(argv[optind-1], &invert, &optind, 0);
242 proto = check_proto(entry);
243 parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
244 multiinfo->flags = IPT_MULTIPORT_EITHER;
252 multiinfo->invert = 1;
255 exit_error(PARAMETER_PROBLEM,
256 "multiport can only have one option");
261 /* Final check; must specify something. */
263 final_check(unsigned int flags)
266 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
270 port_to_service(int port, u_int8_t proto)
272 struct servent *service;
274 if ((service = getservbyport(htons(port),
275 proto == IPPROTO_TCP ? "tcp" : "udp")))
276 return service->s_name;
282 print_port(u_int16_t port, u_int8_t protocol, int numeric)
286 if (numeric || (service = port_to_service(port, protocol)) == NULL)
289 printf("%s", service);
292 /* Prints out the matchinfo. */
294 print(const struct ipt_ip *ip,
295 const struct ipt_entry_match *match,
298 const struct ipt_multiport *multiinfo
299 = (const struct ipt_multiport *)match->data;
302 printf("multiport ");
304 switch (multiinfo->flags) {
305 case IPT_MULTIPORT_SOURCE:
309 case IPT_MULTIPORT_DESTINATION:
313 case IPT_MULTIPORT_EITHER:
322 for (i=0; i < multiinfo->count; i++) {
323 printf("%s", i ? "," : "");
324 print_port(multiinfo->ports[i], ip->proto, numeric);
330 print_v1(const struct ipt_ip *ip,
331 const struct ipt_entry_match *match,
334 const struct ipt_multiport_v1 *multiinfo
335 = (const struct ipt_multiport_v1 *)match->data;
338 printf("multiport ");
340 switch (multiinfo->flags) {
341 case IPT_MULTIPORT_SOURCE:
345 case IPT_MULTIPORT_DESTINATION:
349 case IPT_MULTIPORT_EITHER:
358 if (multiinfo->invert)
361 for (i=0; i < multiinfo->count; i++) {
362 printf("%s", i ? "," : "");
363 print_port(multiinfo->ports[i], ip->proto, numeric);
364 if (multiinfo->pflags[i]) {
366 print_port(multiinfo->ports[++i], ip->proto, numeric);
372 /* Saves the union ipt_matchinfo in parsable form to stdout. */
373 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
375 const struct ipt_multiport *multiinfo
376 = (const struct ipt_multiport *)match->data;
379 switch (multiinfo->flags) {
380 case IPT_MULTIPORT_SOURCE:
384 case IPT_MULTIPORT_DESTINATION:
388 case IPT_MULTIPORT_EITHER:
393 for (i=0; i < multiinfo->count; i++) {
394 printf("%s", i ? "," : "");
395 print_port(multiinfo->ports[i], ip->proto, 1);
400 static void save_v1(const struct ipt_ip *ip,
401 const struct ipt_entry_match *match)
403 const struct ipt_multiport_v1 *multiinfo
404 = (const struct ipt_multiport_v1 *)match->data;
407 switch (multiinfo->flags) {
408 case IPT_MULTIPORT_SOURCE:
412 case IPT_MULTIPORT_DESTINATION:
416 case IPT_MULTIPORT_EITHER:
421 if (multiinfo->invert)
424 for (i=0; i < multiinfo->count; i++) {
425 printf("%s", i ? "," : "");
426 print_port(multiinfo->ports[i], ip->proto, 1);
427 if (multiinfo->pflags[i]) {
429 print_port(multiinfo->ports[++i], ip->proto, 1);
435 static struct iptables_match multiport = {
439 .version = IPTABLES_VERSION,
440 .size = IPT_ALIGN(sizeof(struct ipt_multiport)),
441 .userspacesize = IPT_ALIGN(sizeof(struct ipt_multiport)),
445 .final_check = &final_check,
451 static struct iptables_match multiport_v1 = {
454 .version = IPTABLES_VERSION,
456 .size = IPT_ALIGN(sizeof(struct ipt_multiport_v1)),
457 .userspacesize = IPT_ALIGN(sizeof(struct ipt_multiport_v1)),
461 .final_check = &final_check,
470 register_match(&multiport);
471 register_match(&multiport_v1);