libxt_dccp.c revision ea146a982e26c42f9954f140276f8deeb2edbe98
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, .flag = 0, .val = '1' },
50	{ .name = "sport", .has_arg = 1, .flag = 0, .val = '1' },
51	{ .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' },
52	{ .name = "dport", .has_arg = 1, .flag = 0, .val = '2' },
53	{ .name = "dccp-types", .has_arg = 1, .flag = 0, .val = '3' },
54	{ .name = "dccp-option", .has_arg = 1, .flag = 0, .val = '4' },
55	{ .name = 0 }
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 void
197final_check(unsigned int flags)
198{
199}
200
201static char *
202port_to_service(int port)
203{
204	struct servent *service;
205
206	if ((service = getservbyport(htons(port), "dccp")))
207		return service->s_name;
208
209	return NULL;
210}
211
212static void
213print_port(u_int16_t port, int numeric)
214{
215	char *service;
216
217	if (numeric || (service = port_to_service(port)) == NULL)
218		printf("%u", port);
219	else
220		printf("%s", service);
221}
222
223static void
224print_ports(const char *name, u_int16_t min, u_int16_t max,
225	    int invert, int numeric)
226{
227	const char *inv = invert ? "!" : "";
228
229	if (min != 0 || max != 0xFFFF || invert) {
230		printf("%s", name);
231		if (min == max) {
232			printf(":%s", inv);
233			print_port(min, numeric);
234		} else {
235			printf("s:%s", inv);
236			print_port(min, numeric);
237			printf(":");
238			print_port(max, numeric);
239		}
240		printf(" ");
241	}
242}
243
244static void
245print_types(u_int16_t types, int inverted, int numeric)
246{
247	int have_type = 0;
248
249	if (inverted)
250		printf("! ");
251
252	while (types) {
253		unsigned int i;
254
255		for (i = 0; !(types & (1 << i)); i++);
256
257		if (have_type)
258			printf(",");
259		else
260			have_type = 1;
261
262		if (numeric)
263			printf("%u", i);
264		else
265			printf("%s", dccp_pkt_types[i]);
266
267		types &= ~(1 << i);
268	}
269}
270
271static void
272print_option(u_int8_t option, int invert, int numeric)
273{
274	if (option || invert)
275		printf("option=%s%u ", invert ? "!" : "", option);
276}
277
278/* Prints out the matchinfo. */
279static void
280print(const void *ip,
281      const struct xt_entry_match *match,
282      int numeric)
283{
284	const struct xt_dccp_info *einfo =
285		(const struct xt_dccp_info *)match->data;
286
287	printf("dccp ");
288
289	if (einfo->flags & XT_DCCP_SRC_PORTS) {
290		print_ports("spt", einfo->spts[0], einfo->spts[1],
291			einfo->invflags & XT_DCCP_SRC_PORTS,
292			numeric);
293	}
294
295	if (einfo->flags & XT_DCCP_DEST_PORTS) {
296		print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
297			einfo->invflags & XT_DCCP_DEST_PORTS,
298			numeric);
299	}
300
301	if (einfo->flags & XT_DCCP_TYPE) {
302		print_types(einfo->typemask,
303			   einfo->invflags & XT_DCCP_TYPE,
304			   numeric);
305	}
306
307	if (einfo->flags & XT_DCCP_OPTION) {
308		print_option(einfo->option,
309			     einfo->invflags & XT_DCCP_OPTION, numeric);
310	}
311}
312
313/* Saves the union ipt_matchinfo in parsable form to stdout. */
314static void
315save(const void *ip,
316     const struct xt_entry_match *match)
317{
318	const struct xt_dccp_info *einfo =
319		(const struct xt_dccp_info *)match->data;
320
321	if (einfo->flags & XT_DCCP_SRC_PORTS) {
322		if (einfo->invflags & XT_DCCP_SRC_PORTS)
323			printf("! ");
324		if (einfo->spts[0] != einfo->spts[1])
325			printf("--sport %u:%u ",
326			       einfo->spts[0], einfo->spts[1]);
327		else
328			printf("--sport %u ", einfo->spts[0]);
329	}
330
331	if (einfo->flags & XT_DCCP_DEST_PORTS) {
332		if (einfo->invflags & XT_DCCP_DEST_PORTS)
333			printf("! ");
334		if (einfo->dpts[0] != einfo->dpts[1])
335			printf("--dport %u:%u ",
336			       einfo->dpts[0], einfo->dpts[1]);
337		else
338			printf("--dport %u ", einfo->dpts[0]);
339	}
340
341	if (einfo->flags & XT_DCCP_TYPE) {
342		printf("--dccp-type ");
343		print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0);
344	}
345
346	if (einfo->flags & XT_DCCP_OPTION) {
347		printf("--dccp-option %s%u ",
348			einfo->typemask & XT_DCCP_OPTION ? "! " : "",
349			einfo->option);
350	}
351}
352
353static struct xtables_match dccp =
354{
355	.name		= "dccp",
356	.family		= AF_INET,
357	.version	= IPTABLES_VERSION,
358	.size		= XT_ALIGN(sizeof(struct xt_dccp_info)),
359	.userspacesize	= XT_ALIGN(sizeof(struct xt_dccp_info)),
360	.help		= &help,
361	.init		= &init,
362	.parse		= &parse,
363	.final_check	= &final_check,
364	.print		= &print,
365	.save		= &save,
366	.extra_opts	= opts
367};
368
369static struct xtables_match dccp6 =
370{
371	.name		= "dccp",
372	.family		= AF_INET6,
373	.version	= IPTABLES_VERSION,
374	.size		= XT_ALIGN(sizeof(struct xt_dccp_info)),
375	.userspacesize	= XT_ALIGN(sizeof(struct xt_dccp_info)),
376	.help		= &help,
377	.init		= &init,
378	.parse		= &parse,
379	.final_check	= &final_check,
380	.print		= &print,
381	.save		= &save,
382	.extra_opts	= opts
383};
384
385void _init(void)
386{
387	xtables_register_match(&dccp);
388	xtables_register_match(&dccp6);
389}
390
391