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 proto_to_name(u_int8_t proto
)
72 parse_multi_ports(const char *portstring
, u_int16_t
*ports
, const char *proto
)
74 char *buffer
, *cp
, *next
;
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
++)
83 if (next
) *next
++='\0';
84 ports
[i
] = parse_port(cp
, proto
);
86 if (cp
) exit_error(PARAMETER_PROBLEM
, "too many ports specified");
92 parse_multi_ports_v1(const char *portstring
,
93 struct ipt_multiport_v1
*multiinfo
,
96 char *buffer
, *cp
, *next
, *range
;
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
, ':');
111 if (i
== IPT_MULTI_PORTS
-1)
112 exit_error(PARAMETER_PROBLEM
,
113 "too many ports specified");
116 multiinfo
->ports
[i
] = parse_port(cp
, proto
);
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");
126 multiinfo
->count
= i
;
127 if (cp
) exit_error(PARAMETER_PROBLEM
, "too many ports specified");
131 /* Initialize the match. */
133 init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
138 check_proto(const struct ipt_entry
*entry
)
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
)
148 else if (!entry
->ip
.proto
)
149 exit_error(PARAMETER_PROBLEM
,
150 "multiport needs `-p tcp', `-p udp', `-p sctp' or `-p dccp'");
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
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
)
165 struct ipt_multiport
*multiinfo
166 = (struct ipt_multiport
*)(*match
)->data
;
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
;
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
;
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
;
198 exit_error(PARAMETER_PROBLEM
,
199 "multiport does not support invert");
202 exit_error(PARAMETER_PROBLEM
,
203 "multiport can only have one option");
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
)
215 struct ipt_multiport_v1
*multiinfo
216 = (struct ipt_multiport_v1
*)(*match
)->data
;
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
;
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
;
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
;
245 multiinfo
->invert
= 1;
248 exit_error(PARAMETER_PROBLEM
,
249 "multiport can only have one option");
254 /* Final check; must specify something. */
256 final_check(unsigned int flags
)
259 exit_error(PARAMETER_PROBLEM
, "multiport expection an option");
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
;
274 print_port(u_int16_t port
, u_int8_t protocol
, int numeric
)
278 if (numeric
|| (service
= port_to_service(port
, protocol
)) == NULL
)
281 printf("%s", service
);
284 /* Prints out the matchinfo. */
286 print(const struct ipt_ip
*ip
,
287 const struct ipt_entry_match
*match
,
290 const struct ipt_multiport
*multiinfo
291 = (const struct ipt_multiport
*)match
->data
;
294 printf("multiport ");
296 switch (multiinfo
->flags
) {
297 case IPT_MULTIPORT_SOURCE
:
301 case IPT_MULTIPORT_DESTINATION
:
305 case IPT_MULTIPORT_EITHER
:
314 for (i
=0; i
< multiinfo
->count
; i
++) {
315 printf("%s", i
? "," : "");
316 print_port(multiinfo
->ports
[i
], ip
->proto
, numeric
);
322 print_v1(const struct ipt_ip
*ip
,
323 const struct ipt_entry_match
*match
,
326 const struct ipt_multiport_v1
*multiinfo
327 = (const struct ipt_multiport_v1
*)match
->data
;
330 printf("multiport ");
332 switch (multiinfo
->flags
) {
333 case IPT_MULTIPORT_SOURCE
:
337 case IPT_MULTIPORT_DESTINATION
:
341 case IPT_MULTIPORT_EITHER
:
350 if (multiinfo
->invert
)
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
]) {
358 print_port(multiinfo
->ports
[++i
], ip
->proto
, numeric
);
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
;
371 switch (multiinfo
->flags
) {
372 case IPT_MULTIPORT_SOURCE
:
376 case IPT_MULTIPORT_DESTINATION
:
380 case IPT_MULTIPORT_EITHER
:
385 for (i
=0; i
< multiinfo
->count
; i
++) {
386 printf("%s", i
? "," : "");
387 print_port(multiinfo
->ports
[i
], ip
->proto
, 1);
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
;
399 switch (multiinfo
->flags
) {
400 case IPT_MULTIPORT_SOURCE
:
404 case IPT_MULTIPORT_DESTINATION
:
408 case IPT_MULTIPORT_EITHER
:
413 if (multiinfo
->invert
)
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
]) {
421 print_port(multiinfo
->ports
[++i
], ip
->proto
, 1);
427 static struct iptables_match multiport
= {
431 .version
= IPTABLES_VERSION
,
432 .size
= IPT_ALIGN(sizeof(struct ipt_multiport
)),
433 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_multiport
)),
437 .final_check
= &final_check
,
443 static struct iptables_match multiport_v1
= {
446 .version
= IPTABLES_VERSION
,
448 .size
= IPT_ALIGN(sizeof(struct ipt_multiport_v1
)),
449 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_multiport_v1
)),
453 .final_check
= &final_check
,
462 register_match(&multiport
);
463 register_match(&multiport_v1
);