libip6t_frag.c revision f1f447b836a714b4646450aaed3dd1aa6ab2808a
1/* Shared library add-on to ip6tables to add Fragmentation header 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_frag.h>
10
11/* Function which prints out usage message. */
12static void
13help(void)
14{
15	printf(
16"FRAG v%s options:\n"
17" --fragid [!] id[:id]          match the id (range)\n"
18" --fraglen [!] length          total length of this header\n"
19" --fragres                     check the reserved filed, too\n"
20" --fragfirst                   matches on the frst fragment\n"
21" [--fragmore|--fraglast]       there are more fragments or this\n"
22"                               is the last one\n",
23NETFILTER_VERSION);
24}
25
26static struct option opts[] = {
27	{ "fragid", 1, 0, '1' },
28	{ "fraglen", 1, 0, '2' },
29	{ "fragres", 0, 0, '3' },
30	{ "fragfirst", 0, 0, '4' },
31	{ "fragmore", 0, 0, '5' },
32	{ "fraglast", 0, 0, '6' },
33	{0}
34};
35
36static u_int32_t
37parse_frag_id(const char *idstr, const char *typestr)
38{
39	unsigned long int id;
40	char* ep;
41
42	id =  strtoul(idstr,&ep,0) ;
43
44	if ( idstr == ep ) {
45		exit_error(PARAMETER_PROBLEM,
46			   "FRAG no valid digits in %s `%s'", typestr, idstr);
47	}
48	if ( id == ULONG_MAX  && errno == ERANGE ) {
49		exit_error(PARAMETER_PROBLEM,
50			   "%s `%s' specified too big: would overflow",
51			   typestr, idstr);
52	}
53	if ( *idstr != '\0'  && *ep != '\0' ) {
54		exit_error(PARAMETER_PROBLEM,
55			   "FRAG error parsing %s `%s'", typestr, idstr);
56	}
57	return (u_int32_t) id;
58}
59
60static void
61parse_frag_ids(const char *idstring, u_int32_t *ids)
62{
63	char *buffer;
64	char *cp;
65
66	buffer = strdup(idstring);
67	if ((cp = strchr(buffer, ':')) == NULL)
68		ids[0] = ids[1] = parse_frag_id(buffer,"id");
69	else {
70		*cp = '\0';
71		cp++;
72
73		ids[0] = buffer[0] ? parse_frag_id(buffer,"id") : 0;
74		ids[1] = cp[0] ? parse_frag_id(cp,"id") : 0xFFFFFFFF;
75	}
76	free(buffer);
77}
78
79/* Initialize the match. */
80static void
81init(struct ip6t_entry_match *m, unsigned int *nfcache)
82{
83	struct ip6t_frag *fraginfo = (struct ip6t_frag *)m->data;
84
85	fraginfo->ids[0] = 0x0L;
86	fraginfo->ids[1] = 0xFFFFFFFF;
87	fraginfo->hdrlen = 0;
88	fraginfo->flags = 0;
89	fraginfo->invflags = 0;
90}
91
92/* Function which parses command options; returns true if it
93   ate an option */
94static int
95parse(int c, char **argv, int invert, unsigned int *flags,
96      const struct ip6t_entry *entry,
97      unsigned int *nfcache,
98      struct ip6t_entry_match **match)
99{
100	struct ip6t_frag *fraginfo = (struct ip6t_frag *)(*match)->data;
101
102	switch (c) {
103	case '1':
104		if (*flags & IP6T_FRAG_IDS)
105			exit_error(PARAMETER_PROBLEM,
106				   "Only one `--fragid' allowed");
107		check_inverse(optarg, &invert, &optind, 0);
108		parse_frag_ids(argv[optind-1], fraginfo->ids);
109		if (invert)
110			fraginfo->invflags |= IP6T_FRAG_INV_IDS;
111		fraginfo->flags |= IP6T_FRAG_IDS;
112		*flags |= IP6T_FRAG_IDS;
113		break;
114	case '2':
115		if (*flags & IP6T_FRAG_LEN)
116			exit_error(PARAMETER_PROBLEM,
117				   "Only one `--fraglen' allowed");
118		check_inverse(optarg, &invert, &optind, 0);
119		fraginfo->hdrlen = parse_frag_id(argv[optind-1], "length");
120		if (invert)
121			fraginfo->invflags |= IP6T_FRAG_INV_LEN;
122		fraginfo->flags |= IP6T_FRAG_LEN;
123		*flags |= IP6T_FRAG_LEN;
124		break;
125	case '3':
126		if (*flags & IP6T_FRAG_RES)
127			exit_error(PARAMETER_PROBLEM,
128				   "Only one `--fragres' allowed");
129		fraginfo->flags |= IP6T_FRAG_RES;
130		*flags |= IP6T_FRAG_RES;
131		break;
132	case '4':
133		if (*flags & IP6T_FRAG_FST)
134			exit_error(PARAMETER_PROBLEM,
135				   "Only one `--fragfirst' allowed");
136		fraginfo->flags |= IP6T_FRAG_FST;
137		*flags |= IP6T_FRAG_FST;
138		break;
139	case '5':
140		if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF))
141			exit_error(PARAMETER_PROBLEM,
142			   "Only one `--fragmore' or `--fraglast' allowed");
143		fraginfo->flags |= IP6T_FRAG_MF;
144		*flags |= IP6T_FRAG_MF;
145		break;
146	case '6':
147		if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF))
148			exit_error(PARAMETER_PROBLEM,
149			   "Only one `--fragmore' or `--fraglast' allowed");
150		fraginfo->flags |= IP6T_FRAG_NMF;
151		*flags |= IP6T_FRAG_NMF;
152		break;
153	default:
154		return 0;
155	}
156
157	return 1;
158}
159
160/* Final check; we don't care. */
161static void
162final_check(unsigned int flags)
163{
164}
165
166static void
167print_ids(const char *name, u_int32_t min, u_int32_t max,
168	    int invert)
169{
170	const char *inv = invert ? "!" : "";
171
172	if (min != 0 || max != 0xFFFFFFFF || invert) {
173		printf("%s", name);
174		if (min == max) {
175			printf(":%s", inv);
176			printf("%u", min);
177		} else {
178			printf("s:%s", inv);
179			printf("%u",min);
180			printf(":");
181			printf("%u",max);
182		}
183		printf(" ");
184	}
185}
186
187static void
188print_len(const char *name, u_int32_t len, int invert)
189{
190	const char *inv = invert ? "!" : "";
191
192	if (len != 0 || invert) {
193		printf("%s", name);
194		printf(":%s", inv);
195		printf("%u", len);
196		printf(" ");
197	}
198}
199
200/* Prints out the union ip6t_matchinfo. */
201static void
202print(const struct ip6t_ip6 *ip,
203      const struct ip6t_entry_match *match, int numeric)
204{
205	const struct ip6t_frag *frag = (struct ip6t_frag *)match->data;
206
207	printf("frag ");
208	print_ids("id", frag->ids[0], frag->ids[1],
209		    frag->invflags & IP6T_FRAG_INV_IDS);
210	print_len("length", frag->hdrlen,
211		    frag->invflags & IP6T_FRAG_INV_LEN);
212	if (frag->flags & IP6T_FRAG_RES) printf("reserved ");
213	if (frag->flags & IP6T_FRAG_FST) printf("first ");
214	if (frag->flags & IP6T_FRAG_MF) printf("more ");
215	if (frag->flags & IP6T_FRAG_NMF) printf("last ");
216	if (frag->invflags & ~IP6T_FRAG_INV_MASK)
217		printf("Unknown invflags: 0x%X ",
218		       frag->invflags & ~IP6T_FRAG_INV_MASK);
219}
220
221/* Saves the union ip6t_matchinfo in parsable form to stdout. */
222static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
223{
224	const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data;
225
226	if (!(fraginfo->ids[0] == 0
227	    && fraginfo->ids[1] == 0xFFFFFFFF)) {
228		printf("--fragid %s",
229			(fraginfo->invflags & IP6T_FRAG_INV_IDS) ? "! " : "");
230		if (fraginfo->ids[0]
231		    != fraginfo->ids[1])
232			printf("%u:%u ",
233			       fraginfo->ids[0],
234			       fraginfo->ids[1]);
235		else
236			printf("%u ",
237			       fraginfo->ids[0]);
238	}
239
240	if (fraginfo->hdrlen != 0 ) {
241		printf("--fraglen %s%u ",
242			(fraginfo->invflags & IP6T_FRAG_INV_LEN) ? "! " : "",
243			fraginfo->hdrlen);
244	}
245
246	if (fraginfo->flags & IP6T_FRAG_RES) printf("--fragres ");
247	if (fraginfo->flags & IP6T_FRAG_FST) printf("--fragfirst ");
248	if (fraginfo->flags & IP6T_FRAG_MF) printf("--fragmore ");
249	if (fraginfo->flags & IP6T_FRAG_NMF) printf("--fraglast ");
250
251}
252
253static
254struct ip6tables_match frag
255= { NULL,
256    "frag",
257    NETFILTER_VERSION,
258    IP6T_ALIGN(sizeof(struct ip6t_frag)),
259    IP6T_ALIGN(sizeof(struct ip6t_frag)),
260    &help,
261    &init,
262    &parse,
263    &final_check,
264    &print,
265    &save,
266    opts
267};
268
269void
270_init(void)
271{
272	register_match6(&frag);
273}
274