• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
23 static void
help(void)24 help(void)
25 {
26 	printf(
27 UNAME " 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",
31 IPTABLES_VERSION, IP6T_OPTS_OPTSNR);
32 }
33 
34 static 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 
41 static u_int32_t
parse_opts_num(const char * idstr,const char * typestr)42 parse_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 
65 static int
parse_options(const char * optsstr,u_int16_t * opts)66 parse_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. */
120 static void
init(struct ip6t_entry_match * m,unsigned int * nfcache)121 init(struct ip6t_entry_match *m, unsigned int *nfcache)
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 */
133 static int
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ip6t_entry * entry,unsigned int * nfcache,struct ip6t_entry_match ** match)134 parse(int c, char **argv, int invert, unsigned int *flags,
135       const struct ip6t_entry *entry,
136       unsigned int *nfcache,
137       struct ip6t_entry_match **match)
138 {
139 	struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
140 
141 	switch (c) {
142 	case '1':
143 		if (*flags & IP6T_OPTS_LEN)
144 			exit_error(PARAMETER_PROBLEM,
145 				   "Only one `--" LNAME "-len' allowed");
146 		check_inverse(optarg, &invert, &optind, 0);
147 		optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
148 		if (invert)
149 			optinfo->invflags |= IP6T_OPTS_INV_LEN;
150 		optinfo->flags |= IP6T_OPTS_LEN;
151 		*flags |= IP6T_OPTS_LEN;
152 		break;
153 	case '2':
154 		if (*flags & IP6T_OPTS_OPTS)
155 			exit_error(PARAMETER_PROBLEM,
156 				   "Only one `--" LNAME "-opts' allowed");
157                 check_inverse(optarg, &invert, &optind, 0);
158                 if (invert)
159                         exit_error(PARAMETER_PROBLEM,
160 				" '!' not allowed with `--" LNAME "-opts'");
161 		optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
162 		optinfo->flags |= IP6T_OPTS_OPTS;
163 		*flags |= IP6T_OPTS_OPTS;
164 		break;
165 	case '3':
166 		if (*flags & IP6T_OPTS_NSTRICT)
167 			exit_error(PARAMETER_PROBLEM,
168 				   "Only one `--" LNAME "-not-strict' allowed");
169 		if ( !(*flags & IP6T_OPTS_OPTS) )
170 			exit_error(PARAMETER_PROBLEM,
171 				   "`--" LNAME "-opts ...' required before `--"
172 				   LNAME "-not-strict'");
173 		optinfo->flags |= IP6T_OPTS_NSTRICT;
174 		*flags |= IP6T_OPTS_NSTRICT;
175 		break;
176 	default:
177 		return 0;
178 	}
179 
180 	return 1;
181 }
182 
183 /* Final check; we don't care. */
184 static void
final_check(unsigned int flags)185 final_check(unsigned int flags)
186 {
187 }
188 
189 static void
print_options(int optsnr,u_int16_t * optsp)190 print_options(int optsnr, u_int16_t *optsp)
191 {
192 	unsigned int i;
193 
194 	for(i = 0; i < optsnr; i++) {
195 		printf("%d", (optsp[i] & 0xFF00) >> 8);
196 
197 		if ((optsp[i] & 0x00FF) != 0x00FF)
198 			printf(":%d", (optsp[i] & 0x00FF));
199 
200 		printf("%c", (i != optsnr - 1) ? ',' : ' ');
201 	}
202 }
203 
204 /* Prints out the union ip6t_matchinfo. */
205 static void
print(const struct ip6t_ip6 * ip,const struct ip6t_entry_match * match,int numeric)206 print(const struct ip6t_ip6 *ip,
207       const struct ip6t_entry_match *match, int numeric)
208 {
209 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
210 
211 	printf(LNAME " ");
212 	if (optinfo->flags & IP6T_OPTS_LEN)
213 		printf("length:%s%u ",
214 			optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "",
215 			optinfo->hdrlen);
216 
217 	if (optinfo->flags & IP6T_OPTS_OPTS)
218 		printf("opts ");
219 
220 	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
221 
222 	if (optinfo->flags & IP6T_OPTS_NSTRICT)
223 		printf("not-strict ");
224 
225 	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
226 		printf("Unknown invflags: 0x%X ",
227 		       optinfo->invflags & ~IP6T_OPTS_INV_MASK);
228 }
229 
230 /* Saves the union ip6t_matchinfo in parsable form to stdout. */
save(const struct ip6t_ip6 * ip,const struct ip6t_entry_match * match)231 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
232 {
233 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
234 
235 	if (optinfo->flags & IP6T_OPTS_LEN) {
236 		printf("--" LNAME "-len %s%u ",
237 			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "",
238 			optinfo->hdrlen);
239 	}
240 
241 	if (optinfo->flags & IP6T_OPTS_OPTS)
242 		printf("--" LNAME "-opts ");
243 
244 	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
245 
246 	if (optinfo->flags & IP6T_OPTS_NSTRICT)
247 		printf("--" LNAME "-not-strict ");
248 }
249 
250 static
251 struct ip6tables_match optstruct = {
252 	.name          = LNAME,
253 	.version       = IPTABLES_VERSION,
254 	.size          = IP6T_ALIGN(sizeof(struct ip6t_opts)),
255 	.userspacesize = IP6T_ALIGN(sizeof(struct ip6t_opts)),
256 	.help          = &help,
257 	.init          = &init,
258 	.parse         = &parse,
259 	.final_check   = &final_check,
260 	.print         = &print,
261 	.save          = &save,
262 	.extra_opts    = opts
263 };
264 
265 void
_init(void)266 _init(void)
267 {
268 	register_match6(&optstruct);
269 }
270