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. */
17 "multiport v%s options:\n"
18 " --source-ports port[,port,port...]\n"
20 " match source port(s)\n"
21 " --destination-ports port[,port,port...]\n"
23 " match destination port(s)\n"
24 " --ports port[,port,port]\n"
25 " match both source and destination port(s)\n"
26 " NOTE: this kernel does not support port ranges in multiport.\n",
35 "multiport v%s options:\n"
36 " --source-ports [!] port[,port:port,port...]\n"
38 " match source port(s)\n"
39 " --destination-ports [!] port[,port:port,port...]\n"
41 " match destination port(s)\n"
42 " --ports [!] port[,port:port,port]\n"
43 " match both source and destination port(s)\n",
47 static struct option opts
[] = {
48 { "source-ports", 1, 0, '1' },
49 { "sports", 1, 0, '1' }, /* synonym */
50 { "destination-ports", 1, 0, '2' },
51 { "dports", 1, 0, '2' }, /* synonym */
52 { "ports", 1, 0, '3' },
57 proto_to_name(u_int8_t proto
)
77 parse_multi_ports(const char *portstring
, u_int16_t
*ports
, const char *proto
)
79 char *buffer
, *cp
, *next
;
82 buffer
= strdup(portstring
);
83 if (!buffer
) exit_error(OTHER_PROBLEM
, "strdup failed");
85 for (cp
=buffer
, i
=0; cp
&& i
<IPT_MULTI_PORTS
; cp
=next
,i
++)
88 if (next
) *next
++='\0';
89 ports
[i
] = parse_port(cp
, proto
);
91 if (cp
) exit_error(PARAMETER_PROBLEM
, "too many ports specified");
98 parse_multi_ports_v1(const char *portstring
,
99 struct ipt_multiport_v1
*multiinfo
,
102 char *buffer
, *cp
, *next
, *range
;
106 buffer
= strdup(portstring
);
107 if (!buffer
) exit_error(OTHER_PROBLEM
, "strdup failed");
109 for (i
=0; i
<IPT_MULTI_PORTS
; i
++)
110 multiinfo
->pflags
[i
] = 0;
112 for (cp
=buffer
, i
=0; cp
&& i
<IPT_MULTI_PORTS
; cp
=next
, i
++) {
113 next
=strchr(cp
, ',');
114 if (next
) *next
++='\0';
115 range
= strchr(cp
, ':');
117 if (i
== IPT_MULTI_PORTS
-1)
118 exit_error(PARAMETER_PROBLEM
,
119 "too many ports specified");
122 multiinfo
->ports
[i
] = parse_port(cp
, proto
);
124 multiinfo
->pflags
[i
] = 1;
125 multiinfo
->ports
[++i
] = parse_port(range
, proto
);
126 if (multiinfo
->ports
[i
-1] >= multiinfo
->ports
[i
])
127 exit_error(PARAMETER_PROBLEM
,
128 "invalid portrange specified");
132 multiinfo
->count
= i
;
133 if (cp
) exit_error(PARAMETER_PROBLEM
, "too many ports specified");
137 /* Initialize the match. */
139 init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
144 check_proto(const struct ipt_entry
*entry
)
148 if (entry
->ip
.invflags
& IPT_INV_PROTO
)
149 exit_error(PARAMETER_PROBLEM
,
150 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
152 if ((proto
= proto_to_name(entry
->ip
.proto
)) != NULL
)
154 else if (!entry
->ip
.proto
)
155 exit_error(PARAMETER_PROBLEM
,
156 "multiport needs `-p tcp', `-p udp', `-p udplite', "
157 "`-p sctp' or `-p dccp'");
159 exit_error(PARAMETER_PROBLEM
,
160 "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
163 /* Function which parses command options; returns true if it
167 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
168 const struct ipt_entry
*entry
,
169 unsigned int *nfcache
,
170 struct ipt_entry_match
**match
)
173 struct ipt_multiport
*multiinfo
174 = (struct ipt_multiport
*)(*match
)->data
;
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_SOURCE
;
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_DESTINATION
;
194 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
195 proto
= check_proto(entry
);
196 multiinfo
->count
= parse_multi_ports(argv
[optind
-1],
197 multiinfo
->ports
, proto
);
198 multiinfo
->flags
= IPT_MULTIPORT_EITHER
;
206 exit_error(PARAMETER_PROBLEM
,
207 "multiport does not support invert");
210 exit_error(PARAMETER_PROBLEM
,
211 "multiport can only have one option");
218 parse_v1(int c
, char **argv
, int invert
, unsigned int *flags
,
219 const struct ipt_entry
*entry
,
220 unsigned int *nfcache
,
221 struct ipt_entry_match
**match
)
224 struct ipt_multiport_v1
*multiinfo
225 = (struct ipt_multiport_v1
*)(*match
)->data
;
229 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
230 proto
= check_proto(entry
);
231 parse_multi_ports_v1(argv
[optind
-1], multiinfo
, proto
);
232 multiinfo
->flags
= IPT_MULTIPORT_SOURCE
;
236 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
237 proto
= check_proto(entry
);
238 parse_multi_ports_v1(argv
[optind
-1], multiinfo
, proto
);
239 multiinfo
->flags
= IPT_MULTIPORT_DESTINATION
;
243 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
244 proto
= check_proto(entry
);
245 parse_multi_ports_v1(argv
[optind
-1], multiinfo
, proto
);
246 multiinfo
->flags
= IPT_MULTIPORT_EITHER
;
254 multiinfo
->invert
= 1;
257 exit_error(PARAMETER_PROBLEM
,
258 "multiport can only have one option");
263 /* Final check; must specify something. */
265 final_check(unsigned int flags
)
268 exit_error(PARAMETER_PROBLEM
, "multiport expection an option");
272 port_to_service(int port
, u_int8_t proto
)
274 struct servent
*service
;
276 if ((service
= getservbyport(htons(port
), proto_to_name(proto
))))
277 return service
->s_name
;
283 print_port(u_int16_t port
, u_int8_t protocol
, int numeric
)
287 if (numeric
|| (service
= port_to_service(port
, protocol
)) == NULL
)
290 printf("%s", service
);
293 /* Prints out the matchinfo. */
296 print(const struct ipt_ip
*ip
,
297 const struct ipt_entry_match
*match
,
300 const struct ipt_multiport
*multiinfo
301 = (const struct ipt_multiport
*)match
->data
;
304 printf("multiport ");
306 switch (multiinfo
->flags
) {
307 case IPT_MULTIPORT_SOURCE
:
311 case IPT_MULTIPORT_DESTINATION
:
315 case IPT_MULTIPORT_EITHER
:
324 for (i
=0; i
< multiinfo
->count
; i
++) {
325 printf("%s", i
? "," : "");
326 print_port(multiinfo
->ports
[i
], ip
->proto
, numeric
);
333 print_v1(const struct ipt_ip
*ip
,
334 const struct ipt_entry_match
*match
,
337 const struct ipt_multiport_v1
*multiinfo
338 = (const struct ipt_multiport_v1
*)match
->data
;
341 printf("multiport ");
343 switch (multiinfo
->flags
) {
344 case IPT_MULTIPORT_SOURCE
:
348 case IPT_MULTIPORT_DESTINATION
:
352 case IPT_MULTIPORT_EITHER
:
361 if (multiinfo
->invert
)
364 for (i
=0; i
< multiinfo
->count
; i
++) {
365 printf("%s", i
? "," : "");
366 print_port(multiinfo
->ports
[i
], ip
->proto
, numeric
);
367 if (multiinfo
->pflags
[i
]) {
369 print_port(multiinfo
->ports
[++i
], ip
->proto
, numeric
);
375 /* Saves the union ipt_matchinfo in parsable form to stdout. */
377 static void save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
379 const struct ipt_multiport
*multiinfo
380 = (const struct ipt_multiport
*)match
->data
;
383 switch (multiinfo
->flags
) {
384 case IPT_MULTIPORT_SOURCE
:
388 case IPT_MULTIPORT_DESTINATION
:
392 case IPT_MULTIPORT_EITHER
:
397 for (i
=0; i
< multiinfo
->count
; i
++) {
398 printf("%s", i
? "," : "");
399 print_port(multiinfo
->ports
[i
], ip
->proto
, 1);
405 static void save_v1(const struct ipt_ip
*ip
,
406 const struct ipt_entry_match
*match
)
408 const struct ipt_multiport_v1
*multiinfo
409 = (const struct ipt_multiport_v1
*)match
->data
;
412 switch (multiinfo
->flags
) {
413 case IPT_MULTIPORT_SOURCE
:
417 case IPT_MULTIPORT_DESTINATION
:
421 case IPT_MULTIPORT_EITHER
:
426 if (multiinfo
->invert
)
429 for (i
=0; i
< multiinfo
->count
; i
++) {
430 printf("%s", i
? "," : "");
431 print_port(multiinfo
->ports
[i
], ip
->proto
, 1);
432 if (multiinfo
->pflags
[i
]) {
434 print_port(multiinfo
->ports
[++i
], ip
->proto
, 1);
441 static struct iptables_match multiport
= {
445 .version
= IPTABLES_VERSION
,
446 .size
= IPT_ALIGN(sizeof(struct ipt_multiport
)),
447 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_multiport
)),
451 .final_check
= &final_check
,
458 static struct iptables_match multiport_v1
= {
461 .version
= IPTABLES_VERSION
,
463 .size
= IPT_ALIGN(sizeof(struct ipt_multiport_v1
)),
464 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_multiport_v1
)),
468 .final_check
= &final_check
,
478 register_match(&multiport
);
480 register_match(&multiport_v1
);