libip6t_dst.c revision ea146a982e26c42f9954f140276f8deeb2edbe98
1/* Shared library add-on to ip6tables to add Hop-by-Hop and Dst headers support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <errno.h>
8#include <ip6tables.h>
9#include <linux/netfilter_ipv6/ip6t_opts.h>
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <arpa/inet.h>
13
14#ifdef HOPBYHOP
15#define UNAME "HBH"
16#define LNAME "hbh"
17#else
18#define UNAME "DST"
19#define LNAME "dst"
20#endif
21
22/* Function which prints out usage message. */
23static void
24help(void)
25{
26	printf(
27UNAME " v%s options:\n"
28" --" LNAME "-len [!] length           total length of this header\n"
29" --" LNAME "-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
30"                               Options and its length (list, max: %d)\n",
31IPTABLES_VERSION, IP6T_OPTS_OPTSNR);
32}
33
34static const struct option opts[] = {
35	{ .name = LNAME "-len",        .has_arg = 1, .flag = 0, .val = '1' },
36	{ .name = LNAME "-opts",       .has_arg = 1, .flag = 0, .val = '2' },
37	{ .name = LNAME "-not-strict", .has_arg = 1, .flag = 0, .val = '3' },
38	{ .name = 0 }
39};
40
41static u_int32_t
42parse_opts_num(const char *idstr, const char *typestr)
43{
44	unsigned long int id;
45	char* ep;
46
47	id = strtoul(idstr, &ep, 0);
48
49	if ( idstr == ep ) {
50		exit_error(PARAMETER_PROBLEM,
51			   UNAME " no valid digits in %s `%s'", typestr, idstr);
52	}
53	if ( id == ULONG_MAX  && errno == ERANGE ) {
54		exit_error(PARAMETER_PROBLEM,
55			   "%s `%s' specified too big: would overflow",
56			   typestr, idstr);
57	}
58	if ( *idstr != '\0'  && *ep != '\0' ) {
59		exit_error(PARAMETER_PROBLEM,
60			   UNAME " error parsing %s `%s'", typestr, idstr);
61	}
62	return (u_int32_t) id;
63}
64
65static int
66parse_options(const char *optsstr, u_int16_t *opts)
67{
68        char *buffer, *cp, *next, *range;
69        unsigned int i;
70
71	buffer = strdup(optsstr);
72        if (!buffer)
73		exit_error(OTHER_PROBLEM, "strdup failed");
74
75        for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
76        {
77                next = strchr(cp, ',');
78
79                if (next)
80			*next++='\0';
81
82                range = strchr(cp, ':');
83
84                if (range) {
85                        if (i == IP6T_OPTS_OPTSNR-1)
86                                exit_error(PARAMETER_PROBLEM,
87                                           "too many ports specified");
88                        *range++ = '\0';
89                }
90
91                opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8);
92                if (range) {
93			if (opts[i] == 0)
94        			exit_error(PARAMETER_PROBLEM,
95					"PAD0 hasn't got length");
96                        opts[i] |= (u_int16_t)(parse_opts_num(range,"length") &
97					0x000000FF);
98                } else
99                        opts[i] |= (0x00FF);
100
101#ifdef DEBUG
102		printf("opts str: %s %s\n", cp, range);
103		printf("opts opt: %04X\n", opts[i]);
104#endif
105	}
106
107        if (cp)
108		exit_error(PARAMETER_PROBLEM, "too many addresses specified");
109
110	free(buffer);
111
112#ifdef DEBUG
113	printf("addr nr: %d\n", i);
114#endif
115
116	return i;
117}
118
119/* Initialize the match. */
120static void
121init(struct xt_entry_match *m)
122{
123	struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data;
124
125	optinfo->hdrlen = 0;
126	optinfo->flags = 0;
127	optinfo->invflags = 0;
128	optinfo->optsnr = 0;
129}
130
131/* Function which parses command options; returns true if it
132   ate an option */
133static int
134parse(int c, char **argv, int invert, unsigned int *flags,
135      const void *entry,
136      struct xt_entry_match **match)
137{
138	struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
139
140	switch (c) {
141	case '1':
142		if (*flags & IP6T_OPTS_LEN)
143			exit_error(PARAMETER_PROBLEM,
144				   "Only one `--" LNAME "-len' allowed");
145		check_inverse(optarg, &invert, &optind, 0);
146		optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
147		if (invert)
148			optinfo->invflags |= IP6T_OPTS_INV_LEN;
149		optinfo->flags |= IP6T_OPTS_LEN;
150		*flags |= IP6T_OPTS_LEN;
151		break;
152	case '2':
153		if (*flags & IP6T_OPTS_OPTS)
154			exit_error(PARAMETER_PROBLEM,
155				   "Only one `--" LNAME "-opts' allowed");
156                check_inverse(optarg, &invert, &optind, 0);
157                if (invert)
158                        exit_error(PARAMETER_PROBLEM,
159				" '!' not allowed with `--" LNAME "-opts'");
160		optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
161		optinfo->flags |= IP6T_OPTS_OPTS;
162		*flags |= IP6T_OPTS_OPTS;
163		break;
164	case '3':
165		if (*flags & IP6T_OPTS_NSTRICT)
166			exit_error(PARAMETER_PROBLEM,
167				   "Only one `--" LNAME "-not-strict' allowed");
168		if ( !(*flags & IP6T_OPTS_OPTS) )
169			exit_error(PARAMETER_PROBLEM,
170				   "`--" LNAME "-opts ...' required before `--"
171				   LNAME "-not-strict'");
172		optinfo->flags |= IP6T_OPTS_NSTRICT;
173		*flags |= IP6T_OPTS_NSTRICT;
174		break;
175	default:
176		return 0;
177	}
178
179	return 1;
180}
181
182/* Final check; we don't care. */
183static void
184final_check(unsigned int flags)
185{
186}
187
188static void
189print_options(int optsnr, u_int16_t *optsp)
190{
191	unsigned int i;
192
193	for(i = 0; i < optsnr; i++) {
194		printf("%d", (optsp[i] & 0xFF00) >> 8);
195
196		if ((optsp[i] & 0x00FF) != 0x00FF)
197			printf(":%d", (optsp[i] & 0x00FF));
198
199		printf("%c", (i != optsnr - 1) ? ',' : ' ');
200	}
201}
202
203/* Prints out the union ip6t_matchinfo. */
204static void
205print(const void *ip,
206      const struct xt_entry_match *match, int numeric)
207{
208	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
209
210	printf(LNAME " ");
211	if (optinfo->flags & IP6T_OPTS_LEN)
212		printf("length:%s%u ",
213			optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "",
214			optinfo->hdrlen);
215
216	if (optinfo->flags & IP6T_OPTS_OPTS)
217		printf("opts ");
218
219	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
220
221	if (optinfo->flags & IP6T_OPTS_NSTRICT)
222		printf("not-strict ");
223
224	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
225		printf("Unknown invflags: 0x%X ",
226		       optinfo->invflags & ~IP6T_OPTS_INV_MASK);
227}
228
229/* Saves the union ip6t_matchinfo in parsable form to stdout. */
230static void save(const void *ip, const struct xt_entry_match *match)
231{
232	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
233
234	if (optinfo->flags & IP6T_OPTS_LEN) {
235		printf("--" LNAME "-len %s%u ",
236			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "",
237			optinfo->hdrlen);
238	}
239
240	if (optinfo->flags & IP6T_OPTS_OPTS)
241		printf("--" LNAME "-opts ");
242
243	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
244
245	if (optinfo->flags & IP6T_OPTS_NSTRICT)
246		printf("--" LNAME "-not-strict ");
247}
248
249static
250struct ip6tables_match optstruct = {
251	.name          = LNAME,
252	.version       = IPTABLES_VERSION,
253	.size          = IP6T_ALIGN(sizeof(struct ip6t_opts)),
254	.userspacesize = IP6T_ALIGN(sizeof(struct ip6t_opts)),
255	.help          = &help,
256	.init          = &init,
257	.parse         = &parse,
258	.final_check   = &final_check,
259	.print         = &print,
260	.save          = &save,
261	.extra_opts    = opts
262};
263
264void
265_init(void)
266{
267	register_match6(&optstruct);
268}
269