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 service_to_port(const char *name, const char *proto)
39 struct servent *service;
41 if ((service = getservbyname(name, proto)) != NULL)
42 return ntohs((unsigned short) service->s_port);
48 parse_port(const char *port, const char *proto)
52 if (string_to_number(port, 0, 65535, &portnum) != -1 ||
53 (portnum = service_to_port(port, proto)) != -1)
54 return (u_int16_t)portnum;
56 exit_error(PARAMETER_PROBLEM,
57 "invalid port/service `%s' specified", port);
61 parse_multi_ports(const char *portstring, struct ipt_mport *minfo,
64 char *buffer, *cp, *next, *range;
68 buffer = strdup(portstring);
69 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
73 for (cp=buffer, i=0, m=1; cp && i<IPT_MULTI_PORTS; cp=next,i++,m<<=1)
76 if (next) *next++='\0';
77 range = strchr(cp, ':');
79 if (i == IPT_MULTI_PORTS-1)
80 exit_error(PARAMETER_PROBLEM,
81 "too many ports specified");
84 minfo->ports[i] = parse_port(cp, proto);
87 minfo->ports[++i] = parse_port(range, proto);
88 if (minfo->ports[i-1] >= minfo->ports[i])
89 exit_error(PARAMETER_PROBLEM,
90 "invalid portrange specified");
94 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
95 if (i == IPT_MULTI_PORTS-1)
96 minfo->ports[i] = minfo->ports[i-1];
97 else if (i < IPT_MULTI_PORTS-1) {
99 minfo->pflags |= 1<<i;
104 /* Initialize the match. */
106 init(struct ipt_entry_match *m, unsigned int *nfcache)
111 check_proto(const struct ipt_entry *entry)
113 if (entry->ip.proto == IPPROTO_TCP)
115 else if (entry->ip.proto == IPPROTO_UDP)
117 else if (!entry->ip.proto)
118 exit_error(PARAMETER_PROBLEM,
119 "multiport needs `-p tcp' or `-p udp'");
121 exit_error(PARAMETER_PROBLEM,
122 "multiport only works with TCP or UDP");
125 /* Function which parses command options; returns true if it
128 parse(int c, char **argv, int invert, unsigned int *flags,
129 const struct ipt_entry *entry,
130 unsigned int *nfcache,
131 struct ipt_entry_match **match)
134 struct ipt_mport *minfo
135 = (struct ipt_mport *)(*match)->data;
139 check_inverse(argv[optind-1], &invert, &optind, 0);
140 proto = check_proto(entry);
141 parse_multi_ports(argv[optind-1], minfo, proto);
142 minfo->flags = IPT_MPORT_SOURCE;
146 check_inverse(argv[optind-1], &invert, &optind, 0);
147 proto = check_proto(entry);
148 parse_multi_ports(argv[optind-1], minfo, proto);
149 minfo->flags = IPT_MPORT_DESTINATION;
153 check_inverse(argv[optind-1], &invert, &optind, 0);
154 proto = check_proto(entry);
155 parse_multi_ports(argv[optind-1], minfo, proto);
156 minfo->flags = IPT_MPORT_EITHER;
164 exit_error(PARAMETER_PROBLEM,
165 "multiport does not support invert");
168 exit_error(PARAMETER_PROBLEM,
169 "multiport can only have one option");
174 /* Final check; must specify something. */
176 final_check(unsigned int flags)
179 exit_error(PARAMETER_PROBLEM, "mport expects an option");
183 port_to_service(int port, u_int8_t proto)
185 struct servent *service;
187 if ((service = getservbyport(htons(port),
188 proto == IPPROTO_TCP ? "tcp" : "udp")))
189 return service->s_name;
195 print_port(u_int16_t port, u_int8_t protocol, int numeric)
199 if (numeric || (service = port_to_service(port, protocol)) == NULL)
202 printf("%s", service);
205 /* Prints out the matchinfo. */
207 print(const struct ipt_ip *ip,
208 const struct ipt_entry_match *match,
211 const struct ipt_mport *minfo
212 = (const struct ipt_mport *)match->data;
214 u_int16_t pflags = minfo->pflags;
218 switch (minfo->flags) {
219 case IPT_MPORT_SOURCE:
223 case IPT_MPORT_DESTINATION:
227 case IPT_MPORT_EITHER:
236 for (i=0; i < IPT_MULTI_PORTS; i++) {
238 && minfo->ports[i] == 65535)
240 if (i == IPT_MULTI_PORTS-1
241 && minfo->ports[i-1] == minfo->ports[i])
243 printf("%s", i ? "," : "");
244 print_port(minfo->ports[i], ip->proto, numeric);
245 if (pflags & (1<<i)) {
247 print_port(minfo->ports[++i], ip->proto, numeric);
253 /* Saves the union ipt_matchinfo in parsable form to stdout. */
254 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
256 const struct ipt_mport *minfo
257 = (const struct ipt_mport *)match->data;
259 u_int16_t pflags = minfo->pflags;
261 switch (minfo->flags) {
262 case IPT_MPORT_SOURCE:
266 case IPT_MPORT_DESTINATION:
270 case IPT_MPORT_EITHER:
275 for (i=0; i < IPT_MULTI_PORTS; i++) {
277 && minfo->ports[i] == 65535)
279 if (i == IPT_MULTI_PORTS-1
280 && minfo->ports[i-1] == minfo->ports[i])
282 printf("%s", i ? "," : "");
283 print_port(minfo->ports[i], ip->proto, 1);
284 if (pflags & (1<<i)) {
286 print_port(minfo->ports[++i], ip->proto, 1);
292 static struct iptables_match mport = {
295 .version = IPTABLES_VERSION,
296 .size = IPT_ALIGN(sizeof(struct ipt_mport)),
297 .userspacesize = IPT_ALIGN(sizeof(struct ipt_mport)),
301 .final_check = &final_check,
310 register_match(&mport);