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