1 /* Shared library add-on to iptables to add multiple TCP port support. */
8 #include <linux/netfilter_ipv4/ipt_mport.h>
10 /* Function which prints out usage message. */
15 "mport v%s options:\n"
16 " --source-ports port[,port:port,port...]\n"
18 " match source port(s)\n"
19 " --destination-ports port[,port:port,port...]\n"
21 " match destination port(s)\n"
22 " --ports port[,port:port,port]\n"
23 " match both source and destination port(s)\n",
27 static struct option opts
[] = {
28 { "source-ports", 1, 0, '1' },
29 { "sports", 1, 0, '1' }, /* synonym */
30 { "destination-ports", 1, 0, '2' },
31 { "dports", 1, 0, '2' }, /* synonym */
32 { "ports", 1, 0, '3' },
37 parse_multi_ports(const char *portstring
, struct ipt_mport
*minfo
,
40 char *buffer
, *cp
, *next
, *range
;
44 buffer
= strdup(portstring
);
45 if (!buffer
) exit_error(OTHER_PROBLEM
, "strdup failed");
49 for (cp
=buffer
, i
=0, m
=1; cp
&& i
<IPT_MULTI_PORTS
; cp
=next
,i
++,m
<<=1)
52 if (next
) *next
++='\0';
53 range
= strchr(cp
, ':');
55 if (i
== IPT_MULTI_PORTS
-1)
56 exit_error(PARAMETER_PROBLEM
,
57 "too many ports specified");
60 minfo
->ports
[i
] = parse_port(cp
, proto
);
63 minfo
->ports
[++i
] = parse_port(range
, proto
);
64 if (minfo
->ports
[i
-1] >= minfo
->ports
[i
])
65 exit_error(PARAMETER_PROBLEM
,
66 "invalid portrange specified");
70 if (cp
) exit_error(PARAMETER_PROBLEM
, "too many ports specified");
71 if (i
== IPT_MULTI_PORTS
-1)
72 minfo
->ports
[i
] = minfo
->ports
[i
-1];
73 else if (i
< IPT_MULTI_PORTS
-1) {
75 minfo
->pflags
|= 1<<i
;
80 /* Initialize the match. */
82 init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
87 check_proto(const struct ipt_entry
*entry
)
89 if (entry
->ip
.proto
== IPPROTO_TCP
)
91 else if (entry
->ip
.proto
== IPPROTO_UDP
)
93 else if (!entry
->ip
.proto
)
94 exit_error(PARAMETER_PROBLEM
,
95 "multiport needs `-p tcp' or `-p udp'");
97 exit_error(PARAMETER_PROBLEM
,
98 "multiport only works with TCP or UDP");
101 /* Function which parses command options; returns true if it
104 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
105 const struct ipt_entry
*entry
,
106 unsigned int *nfcache
,
107 struct ipt_entry_match
**match
)
110 struct ipt_mport
*minfo
111 = (struct ipt_mport
*)(*match
)->data
;
115 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
116 proto
= check_proto(entry
);
117 parse_multi_ports(argv
[optind
-1], minfo
, proto
);
118 minfo
->flags
= IPT_MPORT_SOURCE
;
122 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
123 proto
= check_proto(entry
);
124 parse_multi_ports(argv
[optind
-1], minfo
, proto
);
125 minfo
->flags
= IPT_MPORT_DESTINATION
;
129 check_inverse(argv
[optind
-1], &invert
, &optind
, 0);
130 proto
= check_proto(entry
);
131 parse_multi_ports(argv
[optind
-1], minfo
, proto
);
132 minfo
->flags
= IPT_MPORT_EITHER
;
140 exit_error(PARAMETER_PROBLEM
,
141 "multiport does not support invert");
144 exit_error(PARAMETER_PROBLEM
,
145 "multiport can only have one option");
150 /* Final check; must specify something. */
152 final_check(unsigned int flags
)
155 exit_error(PARAMETER_PROBLEM
, "mport expects an option");
159 port_to_service(int port
, u_int8_t proto
)
161 struct servent
*service
;
163 if ((service
= getservbyport(htons(port
),
164 proto
== IPPROTO_TCP
? "tcp" : "udp")))
165 return service
->s_name
;
171 print_port(u_int16_t port
, u_int8_t protocol
, int numeric
)
175 if (numeric
|| (service
= port_to_service(port
, protocol
)) == NULL
)
178 printf("%s", service
);
181 /* Prints out the matchinfo. */
183 print(const struct ipt_ip
*ip
,
184 const struct ipt_entry_match
*match
,
187 const struct ipt_mport
*minfo
188 = (const struct ipt_mport
*)match
->data
;
190 u_int16_t pflags
= minfo
->pflags
;
194 switch (minfo
->flags
) {
195 case IPT_MPORT_SOURCE
:
199 case IPT_MPORT_DESTINATION
:
203 case IPT_MPORT_EITHER
:
212 for (i
=0; i
< IPT_MULTI_PORTS
; i
++) {
214 && minfo
->ports
[i
] == 65535)
216 if (i
== IPT_MULTI_PORTS
-1
217 && minfo
->ports
[i
-1] == minfo
->ports
[i
])
219 printf("%s", i
? "," : "");
220 print_port(minfo
->ports
[i
], ip
->proto
, numeric
);
221 if (pflags
& (1<<i
)) {
223 print_port(minfo
->ports
[++i
], ip
->proto
, numeric
);
229 /* Saves the union ipt_matchinfo in parsable form to stdout. */
230 static void save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
232 const struct ipt_mport
*minfo
233 = (const struct ipt_mport
*)match
->data
;
235 u_int16_t pflags
= minfo
->pflags
;
237 switch (minfo
->flags
) {
238 case IPT_MPORT_SOURCE
:
242 case IPT_MPORT_DESTINATION
:
246 case IPT_MPORT_EITHER
:
251 for (i
=0; i
< IPT_MULTI_PORTS
; i
++) {
253 && minfo
->ports
[i
] == 65535)
255 if (i
== IPT_MULTI_PORTS
-1
256 && minfo
->ports
[i
-1] == minfo
->ports
[i
])
258 printf("%s", i
? "," : "");
259 print_port(minfo
->ports
[i
], ip
->proto
, 1);
260 if (pflags
& (1<<i
)) {
262 print_port(minfo
->ports
[++i
], ip
->proto
, 1);
268 static struct iptables_match mport
= {
271 .version
= IPTABLES_VERSION
,
272 .size
= IPT_ALIGN(sizeof(struct ipt_mport
)),
273 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_mport
)),
277 .final_check
= &final_check
,
286 register_match(&mport
);