blob: bac4621fdbe674bbd7dcb636dcfd472caa1e8b72 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* 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_multiport.h>
9
10/* Function which prints out usage message. */
11static void
12help(void)
13{
14 printf(
15"multiport v%s options:\n"
16" --source-ports port[,port,port...]\n"
17" --sports ...\n"
18" match source port(s)\n"
19" --destination-ports port[,port,port...]\n"
20" --dports ...\n"
21" match destination port(s)\n"
22" --ports port[,port,port]\n"
23" match both source and destination port(s)\n",
24NETFILTER_VERSION);
25}
26
27static 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}
34};
35
36static int
37service_to_port(const char *name, const char *proto)
38{
39 struct servent *service;
40
41 if ((service = getservbyname(name, proto)) != NULL)
42 return ntohs((unsigned short) service->s_port);
43
44 return -1;
45}
46
47static u_int16_t
48parse_port(const char *port, const char *proto)
49{
50 int portnum;
51 if ((portnum = string_to_number(port, 0, 65535)) != -1 ||
52 (portnum = service_to_port(port, proto)) != -1)
53 return (u_int16_t)portnum;
54
55 exit_error(PARAMETER_PROBLEM,
56 "invalid port/service `%s' specified", port);
57}
58
59static unsigned int
60parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
61{
62 char *buffer, *cp, *next;
63 unsigned int i;
64
65 buffer = strdup(portstring);
66 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
67
68 for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next,i++)
69 {
70 next=strchr(cp, ',');
71 if (next) *next++='\0';
72 ports[i] = parse_port(cp, proto);
73 }
74 if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
75 free(buffer);
76 return i;
77}
78
79/* Initialize the match. */
80static void
81init(struct ipt_entry_match *m, unsigned int *nfcache)
82{
83}
84
85static const char *
86check_proto(const struct ipt_entry *entry)
87{
88 if (entry->ip.proto == IPPROTO_TCP)
89 return "tcp";
90 else if (entry->ip.proto == IPPROTO_UDP)
91 return "udp";
92 else if (!entry->ip.proto)
93 exit_error(PARAMETER_PROBLEM,
94 "multiport needs `-p tcp' or `-p udp'");
95 else
96 exit_error(PARAMETER_PROBLEM,
97 "multiport only works with TCP or UDP");
98}
99
100/* Function which parses command options; returns true if it
101 ate an option */
102static int
103parse(int c, char **argv, int invert, unsigned int *flags,
104 const struct ipt_entry *entry,
105 unsigned int *nfcache,
106 struct ipt_entry_match **match)
107{
108 const char *proto;
109 struct ipt_multiport *multiinfo
110 = (struct ipt_multiport *)(*match)->data;
111
112 switch (c) {
113 case '1':
114 proto = check_proto(entry);
115 multiinfo->count = parse_multi_ports(argv[optind-1],
116 multiinfo->ports, proto);
117 multiinfo->flags = IPT_MULTIPORT_SOURCE;
118 *nfcache |= NFC_IP_SRC_PT;
119 break;
120
121 case '2':
122 proto = check_proto(entry);
123 multiinfo->count = parse_multi_ports(argv[optind-1],
124 multiinfo->ports, proto);
125 multiinfo->flags = IPT_MULTIPORT_DESTINATION;
126 *nfcache |= NFC_IP_DST_PT;
127 break;
128
129 case '3':
130 proto = check_proto(entry);
131 multiinfo->count = parse_multi_ports(argv[optind-1],
132 multiinfo->ports, proto);
133 multiinfo->flags = IPT_MULTIPORT_EITHER;
134 *nfcache |= NFC_IP_SRC_PT | NFC_IP_DST_PT;
135 break;
136
137 default:
138 return 0;
139 }
140
141 if (*flags)
142 exit_error(PARAMETER_PROBLEM,
143 "multiport can only have one option");
144 *flags = 1;
145 return 1;
146}
147
148/* Final check; must specify something. */
149static void
150final_check(unsigned int flags)
151{
152 if (!flags)
153 exit_error(PARAMETER_PROBLEM, "multiport expection an option");
154}
155
156static char *
157port_to_service(int port, u_int8_t proto)
158{
159 struct servent *service;
160
161 if ((service = getservbyport(htons(port),
162 proto == IPPROTO_TCP ? "tcp" : "udp")))
163 return service->s_name;
164
165 return NULL;
166}
167
168static void
169print_port(u_int16_t port, u_int8_t protocol, int numeric)
170{
171 char *service;
172
173 if (numeric || (service = port_to_service(port, protocol)) == NULL)
174 printf("%u", port);
175 else
176 printf("%s", service);
177}
178
179/* Prints out the matchinfo. */
180static void
181print(const struct ipt_ip *ip,
182 const struct ipt_entry_match *match,
183 int numeric)
184{
185 const struct ipt_multiport *multiinfo
186 = (const struct ipt_multiport *)match->data;
187 unsigned int i;
188
189 printf("multiport ");
190
191 switch (multiinfo->flags) {
192 case IPT_MULTIPORT_SOURCE:
193 printf("sports ");
194 break;
195
196 case IPT_MULTIPORT_DESTINATION:
197 printf("dports ");
198 break;
199
200 case IPT_MULTIPORT_EITHER:
201 printf("ports ");
202 break;
203
204 default:
205 printf("ERROR ");
206 break;
207 }
208
209 for (i=0; i < multiinfo->count; i++) {
210 printf("%s", i ? "," : "");
211 print_port(multiinfo->ports[i], ip->proto, numeric);
212 }
213 printf(" ");
214}
215
216/* Saves the union ipt_matchinfo in parsable form to stdout. */
217static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
218{
219 const struct ipt_multiport *multiinfo
220 = (const struct ipt_multiport *)match->data;
221 unsigned int i;
222
223 switch (multiinfo->flags) {
224 case IPT_MULTIPORT_SOURCE:
225 printf("--sports ");
226 break;
227
228 case IPT_MULTIPORT_DESTINATION:
229 printf("--dports ");
230 break;
231
232 case IPT_MULTIPORT_EITHER:
233 printf("--ports ");
234 break;
235 }
236
237 for (i=0; i < multiinfo->count; i++) {
238 printf("%s", i ? "," : "");
239 print_port(multiinfo->ports[i], ip->proto, 0);
240 }
241 printf(" ");
242}
243
244struct iptables_match multiport
245= { NULL,
246 "multiport",
247 NETFILTER_VERSION,
Rusty Russell73f72f52000-07-03 10:17:57 +0000248 IPT_ALIGN(sizeof(struct ipt_multiport)),
249 IPT_ALIGN(sizeof(struct ipt_multiport)),
Marc Bouchere6869a82000-03-20 06:03:29 +0000250 &help,
251 &init,
252 &parse,
253 &final_check,
254 &print,
255 &save,
256 opts
257};
258
259void
260_init(void)
261{
262 register_match(&multiport);
263}