libxt_dccp.c revision 830132ac9c0d270bf9dcfe85c2464e3fe8c73fb9
1/* Shared library add-on to iptables for DCCP matching
2 *
3 * (C) 2005 by Harald Welte <laforge@netfilter.org>
4 *
5 * This program is distributed under the terms of GNU GPL v2, 1991
6 *
7 */
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <getopt.h>
12#include <netdb.h>
13#include <ctype.h>
14
15#include <xtables.h>
16#include <linux/dccp.h>
17#include <linux/netfilter/x_tables.h>
18#include <linux/netfilter/xt_dccp.h>
19
20#if 0
21#define DEBUGP(format, first...) printf(format, ##first)
22#define static
23#else
24#define DEBUGP(format, fist...)
25#endif
26
27/* Initialize the match. */
28static void
29init(struct xt_entry_match *m)
30{
31	struct xt_dccp_info *einfo = (struct xt_dccp_info *)m->data;
32
33	memset(einfo, 0, sizeof(struct xt_dccp_info));
34}
35
36static void help(void)
37{
38	printf(
39"DCCP match v%s options\n"
40" --source-port [!] port[:port]                          match source port(s)\n"
41" --sport ...\n"
42" --destination-port [!] port[:port]                     match destination port(s)\n"
43" --dport ...\n"
44,
45	IPTABLES_VERSION);
46}
47
48static const struct option opts[] = {
49	{ .name = "source-port", .has_arg = 1, .val = '1' },
50	{ .name = "sport", .has_arg = 1, .val = '1' },
51	{ .name = "destination-port", .has_arg = 1, .val = '2' },
52	{ .name = "dport", .has_arg = 1, .val = '2' },
53	{ .name = "dccp-types", .has_arg = 1, .val = '3' },
54	{ .name = "dccp-option", .has_arg = 1, .val = '4' },
55	{ }
56};
57
58static void
59parse_dccp_ports(const char *portstring,
60		 u_int16_t *ports)
61{
62	char *buffer;
63	char *cp;
64
65	buffer = strdup(portstring);
66	DEBUGP("%s\n", portstring);
67	if ((cp = strchr(buffer, ':')) == NULL) {
68		ports[0] = ports[1] = parse_port(buffer, "dccp");
69	}
70	else {
71		*cp = '\0';
72		cp++;
73
74		ports[0] = buffer[0] ? parse_port(buffer, "dccp") : 0;
75		ports[1] = cp[0] ? parse_port(cp, "dccp") : 0xFFFF;
76
77		if (ports[0] > ports[1])
78			exit_error(PARAMETER_PROBLEM,
79				   "invalid portrange (min > max)");
80	}
81	free(buffer);
82}
83
84static char *dccp_pkt_types[] = {
85	[DCCP_PKT_REQUEST] 	= "REQUEST",
86	[DCCP_PKT_RESPONSE]	= "RESPONSE",
87	[DCCP_PKT_DATA]		= "DATA",
88	[DCCP_PKT_ACK]		= "ACK",
89	[DCCP_PKT_DATAACK]	= "DATAACK",
90	[DCCP_PKT_CLOSEREQ]	= "CLOSEREQ",
91	[DCCP_PKT_CLOSE]	= "CLOSE",
92	[DCCP_PKT_RESET]	= "RESET",
93	[DCCP_PKT_SYNC]		= "SYNC",
94	[DCCP_PKT_SYNCACK]	= "SYNCACK",
95	[DCCP_PKT_INVALID]	= "INVALID",
96};
97
98static u_int16_t
99parse_dccp_types(const char *typestring)
100{
101	u_int16_t typemask = 0;
102	char *ptr, *buffer;
103
104	buffer = strdup(typestring);
105
106	for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
107		unsigned int i;
108		for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) {
109			if (!strcasecmp(dccp_pkt_types[i], ptr)) {
110				typemask |= (1 << i);
111				break;
112			}
113		}
114		if (i == sizeof(dccp_pkt_types)/sizeof(char *))
115			exit_error(PARAMETER_PROBLEM,
116				   "Unknown DCCP type `%s'", ptr);
117	}
118
119	free(buffer);
120	return typemask;
121}
122
123static u_int8_t parse_dccp_option(char *optstring)
124{
125	unsigned int ret;
126
127	if (string_to_number(optstring, 1, 255, &ret) == -1)
128		exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'",
129			   optstring);
130
131	return (u_int8_t)ret;
132}
133
134static int
135parse(int c, char **argv, int invert, unsigned int *flags,
136      const void *entry,
137      struct xt_entry_match **match)
138{
139	struct xt_dccp_info *einfo
140		= (struct xt_dccp_info *)(*match)->data;
141
142	switch (c) {
143	case '1':
144		if (*flags & XT_DCCP_SRC_PORTS)
145			exit_error(PARAMETER_PROBLEM,
146			           "Only one `--source-port' allowed");
147		einfo->flags |= XT_DCCP_SRC_PORTS;
148		check_inverse(optarg, &invert, &optind, 0);
149		parse_dccp_ports(argv[optind-1], einfo->spts);
150		if (invert)
151			einfo->invflags |= XT_DCCP_SRC_PORTS;
152		*flags |= XT_DCCP_SRC_PORTS;
153		break;
154
155	case '2':
156		if (*flags & XT_DCCP_DEST_PORTS)
157			exit_error(PARAMETER_PROBLEM,
158				   "Only one `--destination-port' allowed");
159		einfo->flags |= XT_DCCP_DEST_PORTS;
160		check_inverse(optarg, &invert, &optind, 0);
161		parse_dccp_ports(argv[optind-1], einfo->dpts);
162		if (invert)
163			einfo->invflags |= XT_DCCP_DEST_PORTS;
164		*flags |= XT_DCCP_DEST_PORTS;
165		break;
166
167	case '3':
168		if (*flags & XT_DCCP_TYPE)
169			exit_error(PARAMETER_PROBLEM,
170				   "Only one `--dccp-types' allowed");
171		einfo->flags |= XT_DCCP_TYPE;
172		check_inverse(optarg, &invert, &optind, 0);
173		einfo->typemask = parse_dccp_types(argv[optind-1]);
174		if (invert)
175			einfo->invflags |= XT_DCCP_TYPE;
176		*flags |= XT_DCCP_TYPE;
177		break;
178
179	case '4':
180		if (*flags & XT_DCCP_OPTION)
181			exit_error(PARAMETER_PROBLEM,
182				   "Only one `--dccp-option' allowed");
183		einfo->flags |= XT_DCCP_OPTION;
184		check_inverse(optarg, &invert, &optind, 0);
185		einfo->option = parse_dccp_option(argv[optind-1]);
186		if (invert)
187			einfo->invflags |= XT_DCCP_OPTION;
188		*flags |= XT_DCCP_OPTION;
189		break;
190	default:
191		return 0;
192	}
193	return 1;
194}
195
196static char *
197port_to_service(int port)
198{
199	struct servent *service;
200
201	if ((service = getservbyport(htons(port), "dccp")))
202		return service->s_name;
203
204	return NULL;
205}
206
207static void
208print_port(u_int16_t port, int numeric)
209{
210	char *service;
211
212	if (numeric || (service = port_to_service(port)) == NULL)
213		printf("%u", port);
214	else
215		printf("%s", service);
216}
217
218static void
219print_ports(const char *name, u_int16_t min, u_int16_t max,
220	    int invert, int numeric)
221{
222	const char *inv = invert ? "!" : "";
223
224	if (min != 0 || max != 0xFFFF || invert) {
225		printf("%s", name);
226		if (min == max) {
227			printf(":%s", inv);
228			print_port(min, numeric);
229		} else {
230			printf("s:%s", inv);
231			print_port(min, numeric);
232			printf(":");
233			print_port(max, numeric);
234		}
235		printf(" ");
236	}
237}
238
239static void
240print_types(u_int16_t types, int inverted, int numeric)
241{
242	int have_type = 0;
243
244	if (inverted)
245		printf("! ");
246
247	while (types) {
248		unsigned int i;
249
250		for (i = 0; !(types & (1 << i)); i++);
251
252		if (have_type)
253			printf(",");
254		else
255			have_type = 1;
256
257		if (numeric)
258			printf("%u", i);
259		else
260			printf("%s", dccp_pkt_types[i]);
261
262		types &= ~(1 << i);
263	}
264}
265
266static void
267print_option(u_int8_t option, int invert, int numeric)
268{
269	if (option || invert)
270		printf("option=%s%u ", invert ? "!" : "", option);
271}
272
273/* Prints out the matchinfo. */
274static void
275print(const void *ip,
276      const struct xt_entry_match *match,
277      int numeric)
278{
279	const struct xt_dccp_info *einfo =
280		(const struct xt_dccp_info *)match->data;
281
282	printf("dccp ");
283
284	if (einfo->flags & XT_DCCP_SRC_PORTS) {
285		print_ports("spt", einfo->spts[0], einfo->spts[1],
286			einfo->invflags & XT_DCCP_SRC_PORTS,
287			numeric);
288	}
289
290	if (einfo->flags & XT_DCCP_DEST_PORTS) {
291		print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
292			einfo->invflags & XT_DCCP_DEST_PORTS,
293			numeric);
294	}
295
296	if (einfo->flags & XT_DCCP_TYPE) {
297		print_types(einfo->typemask,
298			   einfo->invflags & XT_DCCP_TYPE,
299			   numeric);
300	}
301
302	if (einfo->flags & XT_DCCP_OPTION) {
303		print_option(einfo->option,
304			     einfo->invflags & XT_DCCP_OPTION, numeric);
305	}
306}
307
308/* Saves the union ipt_matchinfo in parsable form to stdout. */
309static void
310save(const void *ip,
311     const struct xt_entry_match *match)
312{
313	const struct xt_dccp_info *einfo =
314		(const struct xt_dccp_info *)match->data;
315
316	if (einfo->flags & XT_DCCP_SRC_PORTS) {
317		if (einfo->invflags & XT_DCCP_SRC_PORTS)
318			printf("! ");
319		if (einfo->spts[0] != einfo->spts[1])
320			printf("--sport %u:%u ",
321			       einfo->spts[0], einfo->spts[1]);
322		else
323			printf("--sport %u ", einfo->spts[0]);
324	}
325
326	if (einfo->flags & XT_DCCP_DEST_PORTS) {
327		if (einfo->invflags & XT_DCCP_DEST_PORTS)
328			printf("! ");
329		if (einfo->dpts[0] != einfo->dpts[1])
330			printf("--dport %u:%u ",
331			       einfo->dpts[0], einfo->dpts[1]);
332		else
333			printf("--dport %u ", einfo->dpts[0]);
334	}
335
336	if (einfo->flags & XT_DCCP_TYPE) {
337		printf("--dccp-type ");
338		print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0);
339	}
340
341	if (einfo->flags & XT_DCCP_OPTION) {
342		printf("--dccp-option %s%u ",
343			einfo->typemask & XT_DCCP_OPTION ? "! " : "",
344			einfo->option);
345	}
346}
347
348static struct xtables_match dccp =
349{
350	.name		= "dccp",
351	.family		= AF_INET,
352	.version	= IPTABLES_VERSION,
353	.size		= XT_ALIGN(sizeof(struct xt_dccp_info)),
354	.userspacesize	= XT_ALIGN(sizeof(struct xt_dccp_info)),
355	.help		= &help,
356	.init		= &init,
357	.parse		= &parse,
358	.print		= &print,
359	.save		= &save,
360	.extra_opts	= opts
361};
362
363static struct xtables_match dccp6 =
364{
365	.name		= "dccp",
366	.family		= AF_INET6,
367	.version	= IPTABLES_VERSION,
368	.size		= XT_ALIGN(sizeof(struct xt_dccp_info)),
369	.userspacesize	= XT_ALIGN(sizeof(struct xt_dccp_info)),
370	.help		= &help,
371	.init		= &init,
372	.parse		= &parse,
373	.print		= &print,
374	.save		= &save,
375	.extra_opts	= opts
376};
377
378void _init(void)
379{
380	xtables_register_match(&dccp);
381	xtables_register_match(&dccp6);
382}
383
384