Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iptables / extensions / libipt_mport.c
blob624de13421c98fd6c1d944707601aeed0e1a044d
1 /* Shared library add-on to iptables to add multiple TCP port support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <iptables.h>
8 #include <linux/netfilter_ipv4/ipt_mport.h>
10 /* Function which prints out usage message. */
11 static void
12 help(void)
14 printf(
15 "mport v%s options:\n"
16 " --source-ports port[,port:port,port...]\n"
17 " --sports ...\n"
18 " match source port(s)\n"
19 " --destination-ports port[,port:port,port...]\n"
20 " --dports ...\n"
21 " match destination port(s)\n"
22 " --ports port[,port:port,port]\n"
23 " match both source and destination port(s)\n",
24 IPTABLES_VERSION);
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' },
33 {0}
36 static void
37 parse_multi_ports(const char *portstring, struct ipt_mport *minfo,
38 const char *proto)
40 char *buffer, *cp, *next, *range;
41 unsigned int i;
42 u_int16_t m;
44 buffer = strdup(portstring);
45 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
47 minfo->pflags = 0;
49 for (cp=buffer, i=0, m=1; cp && i<IPT_MULTI_PORTS; cp=next,i++,m<<=1)
51 next=strchr(cp, ',');
52 if (next) *next++='\0';
53 range = strchr(cp, ':');
54 if (range) {
55 if (i == IPT_MULTI_PORTS-1)
56 exit_error(PARAMETER_PROBLEM,
57 "too many ports specified");
58 *range++ = '\0';
60 minfo->ports[i] = parse_port(cp, proto);
61 if (range) {
62 minfo->pflags |= m;
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");
67 m <<= 1;
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) {
74 minfo->ports[i] = ~0;
75 minfo->pflags |= 1<<i;
77 free(buffer);
80 /* Initialize the match. */
81 static void
82 init(struct ipt_entry_match *m, unsigned int *nfcache)
86 static const char *
87 check_proto(const struct ipt_entry *entry)
89 if (entry->ip.proto == IPPROTO_TCP)
90 return "tcp";
91 else if (entry->ip.proto == IPPROTO_UDP)
92 return "udp";
93 else if (!entry->ip.proto)
94 exit_error(PARAMETER_PROBLEM,
95 "multiport needs `-p tcp' or `-p udp'");
96 else
97 exit_error(PARAMETER_PROBLEM,
98 "multiport only works with TCP or UDP");
101 /* Function which parses command options; returns true if it
102 ate an option */
103 static int
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)
109 const char *proto;
110 struct ipt_mport *minfo
111 = (struct ipt_mport *)(*match)->data;
113 switch (c) {
114 case '1':
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;
119 break;
121 case '2':
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;
126 break;
128 case '3':
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;
133 break;
135 default:
136 return 0;
139 if (invert)
140 exit_error(PARAMETER_PROBLEM,
141 "multiport does not support invert");
143 if (*flags)
144 exit_error(PARAMETER_PROBLEM,
145 "multiport can only have one option");
146 *flags = 1;
147 return 1;
150 /* Final check; must specify something. */
151 static void
152 final_check(unsigned int flags)
154 if (!flags)
155 exit_error(PARAMETER_PROBLEM, "mport expects an option");
158 static char *
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;
167 return NULL;
170 static void
171 print_port(u_int16_t port, u_int8_t protocol, int numeric)
173 char *service;
175 if (numeric || (service = port_to_service(port, protocol)) == NULL)
176 printf("%u", port);
177 else
178 printf("%s", service);
181 /* Prints out the matchinfo. */
182 static void
183 print(const struct ipt_ip *ip,
184 const struct ipt_entry_match *match,
185 int numeric)
187 const struct ipt_mport *minfo
188 = (const struct ipt_mport *)match->data;
189 unsigned int i;
190 u_int16_t pflags = minfo->pflags;
192 printf("mport ");
194 switch (minfo->flags) {
195 case IPT_MPORT_SOURCE:
196 printf("sports ");
197 break;
199 case IPT_MPORT_DESTINATION:
200 printf("dports ");
201 break;
203 case IPT_MPORT_EITHER:
204 printf("ports ");
205 break;
207 default:
208 printf("ERROR ");
209 break;
212 for (i=0; i < IPT_MULTI_PORTS; i++) {
213 if (pflags & (1<<i)
214 && minfo->ports[i] == 65535)
215 break;
216 if (i == IPT_MULTI_PORTS-1
217 && minfo->ports[i-1] == minfo->ports[i])
218 break;
219 printf("%s", i ? "," : "");
220 print_port(minfo->ports[i], ip->proto, numeric);
221 if (pflags & (1<<i)) {
222 printf(":");
223 print_port(minfo->ports[++i], ip->proto, numeric);
226 printf(" ");
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;
234 unsigned int i;
235 u_int16_t pflags = minfo->pflags;
237 switch (minfo->flags) {
238 case IPT_MPORT_SOURCE:
239 printf("--sports ");
240 break;
242 case IPT_MPORT_DESTINATION:
243 printf("--dports ");
244 break;
246 case IPT_MPORT_EITHER:
247 printf("--ports ");
248 break;
251 for (i=0; i < IPT_MULTI_PORTS; i++) {
252 if (pflags & (1<<i)
253 && minfo->ports[i] == 65535)
254 break;
255 if (i == IPT_MULTI_PORTS-1
256 && minfo->ports[i-1] == minfo->ports[i])
257 break;
258 printf("%s", i ? "," : "");
259 print_port(minfo->ports[i], ip->proto, 1);
260 if (pflags & (1<<i)) {
261 printf(":");
262 print_port(minfo->ports[++i], ip->proto, 1);
265 printf(" ");
268 static struct iptables_match mport = {
269 .next = NULL,
270 .name = "mport",
271 .version = IPTABLES_VERSION,
272 .size = IPT_ALIGN(sizeof(struct ipt_mport)),
273 .userspacesize = IPT_ALIGN(sizeof(struct ipt_mport)),
274 .help = &help,
275 .init = &init,
276 .parse = &parse,
277 .final_check = &final_check,
278 .print = &print,
279 .save = &save,
280 .extra_opts = opts
283 void
284 _init(void)
286 register_match(&mport);