parse.y revision 1.1 1 /* $NetBSD: parse.y,v 1.1 2010/05/07 17:41:58 degroote Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 %{
30 #include <sys/cdefs.h>
31
32 #ifndef lint
33 __RCSID("$NetBSD: parse.y,v 1.1 2010/05/07 17:41:58 degroote Exp $");
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdint.h>
40 #include <stdbool.h>
41 #include <inttypes.h>
42 #include <errno.h>
43
44 #include <net/if.h>
45 #include <netinet/in.h>
46 #include <net/pfvar.h>
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 #include <netinet/tcp_fsm.h>
50
51 #include "parser.h"
52
53 // XXX it is really correct ?
54 extern const char * const tcpstates[];
55
56
57 struct pfsync_state global_state;
58 struct pfsync_state_peer *src_peer, *dst_peer;
59 struct pfsync_state_peer current_peer;
60
61 static void parse_init(void);
62 static void add_state(void);
63 static bool get_pfsync_host(const char*, struct pfsync_state_host*, sa_family_t*);
64 static uint8_t retrieve_peer_state(const char*, int);
65 static bool retrieve_seq(const char*, struct pfsync_state_peer*);
66 static bool strtou32(const char*, uint32_t*);
67
68 %}
69
70 %union {
71 uintmax_t num;
72 char* str;
73 }
74
75 %token STATE
76 %token IN OUT
77 %token ON PROTO
78 %token FROM TO USING
79 %token ID CID EXPIRE TIMEOUT
80 %token SRC DST
81 %token SEQ MAX_WIN WSCALE MSS
82 %token NOSCRUB SCRUB FLAGS TTL MODE
83 %token NUMBER STRING
84
85 %type <str> STRING
86 %type <num> NUMBER
87 %%
88
89 states
90 : /* NOTHING */
91 | state states { parse_init(); }
92 ;
93
94 state
95 : STATE direction iface proto addrs id cid expire timeout src_peer dst_peer {
96 add_state();
97 }
98 ;
99
100 direction
101 : IN {
102 global_state.direction = PF_IN;
103 src_peer = &global_state.dst;
104 dst_peer = &global_state.src;
105 }
106 | OUT {
107 global_state.direction = PF_OUT;
108 src_peer = &global_state.src;
109 dst_peer = &global_state.dst;
110 }
111 ;
112
113 iface
114 : ON STRING {
115 strlcpy(global_state.ifname, $2, sizeof(global_state.ifname));
116 free($2);
117 }
118 ;
119
120 proto
121 : PROTO STRING {
122 struct protoent *p;
123 p = getprotobyname($2);
124 if (p == NULL)
125 yyfatal("Invalid protocol name");
126 global_state.proto = p->p_proto;
127 free($2);
128 }
129 | PROTO NUMBER {
130 // check that the number may be valid proto ?
131 global_state.proto = $2;
132 }
133 ;
134
135 addrs
136 : FROM STRING TO STRING {
137 get_pfsync_host($2, &global_state.lan, &global_state.af);
138 get_pfsync_host($4, &global_state.ext, &global_state.af);
139 memcpy(&global_state.gwy, &global_state.lan, sizeof(struct pfsync_state_host));
140 free($2);
141 free($4);
142 }
143 | FROM STRING TO STRING USING STRING {
144 get_pfsync_host($2, &global_state.lan, &global_state.af);
145 get_pfsync_host($4, &global_state.ext, &global_state.af);
146 get_pfsync_host($6, &global_state.gwy, &global_state.af);
147 free($2);
148 free($4);
149 free($6);
150 }
151 ;
152
153 id
154 : ID NUMBER {
155 if ( $2 > UINT64_MAX)
156 yyfatal("id is too big");
157 uint64_t value = (uint64_t)$2;
158 memcpy(global_state.id, &value, sizeof(global_state.id));
159 }
160 ;
161
162 cid
163 : CID NUMBER {
164 if ( $2 > UINT32_MAX)
165 yyfatal("creator id is too big");
166 global_state.creatorid = (uint32_t)$2;
167 }
168 ;
169
170 expire
171 : EXPIRE NUMBER {
172 if ( $2 > UINT32_MAX)
173 yyfatal("expire time is too big");
174 global_state.expire = (uint32_t) $2;
175 }
176 ;
177
178 timeout
179 : TIMEOUT NUMBER {
180 if ($2 > UINT8_MAX)
181 yyfatal("timeout time is too big");
182 global_state.timeout = (uint8_t) $2;
183 }
184 ;
185
186 src_peer
187 : SRC peer {
188 memcpy(src_peer, ¤t_peer, sizeof(current_peer));
189 }
190 ;
191
192 dst_peer
193 : DST peer {
194 memcpy(dst_peer, ¤t_peer, sizeof(current_peer));
195 }
196 ;
197
198 peer
199 : peer_state scrub
200 | peer_state tcp_options scrub
201 ;
202
203 peer_state
204 : STATE STRING {
205 current_peer.state = retrieve_peer_state($2, global_state.proto);
206 free($2);
207 }
208 | STATE NUMBER {
209 if ( $2 > UINT8_MAX)
210 yyfatal("peer state is too big");
211 current_peer.state = $2;
212 }
213 ;
214
215 tcp_options
216 : SEQ seqs MAX_WIN NUMBER WSCALE NUMBER {
217 if ($4 > UINT16_MAX)
218 yyfatal("max_win is too big");
219 current_peer.max_win = $4;
220
221 if ($6 > UINT8_MAX)
222 yyfatal("wscale is too big");
223 current_peer.wscale = $6;
224 }
225 | SEQ seqs MAX_WIN NUMBER WSCALE NUMBER MSS NUMBER {
226 if ($4 > UINT16_MAX)
227 yyfatal("max_win is too big");
228 current_peer.max_win = $4;
229
230 if ($6 > UINT8_MAX)
231 yyfatal("wscale is too big");
232 current_peer.wscale = $6;
233
234 if ($8 > UINT16_MAX)
235 yyfatal("mss is too big");
236 current_peer.mss = $8;
237 }
238 ;
239
240 seqs
241 : STRING {
242 if (!retrieve_seq($1, ¤t_peer))
243 yyfatal("invalid seq number");
244
245 free($1);
246 }
247 ;
248
249 scrub
250 : NOSCRUB { current_peer.scrub.scrub_flag= 0;}
251 | SCRUB FLAGS NUMBER MODE NUMBER TTL NUMBER {
252 current_peer.scrub.scrub_flag= PFSYNC_SCRUB_FLAG_VALID;
253 if ($3 > UINT16_MAX)
254 yyfatal("scrub flags is too big");
255 current_peer.scrub.pfss_flags = $3;
256
257 if ($5 > UINT32_MAX)
258 yyfatal("scrub mode is too big");
259 current_peer.scrub.pfss_ts_mod = $5;
260
261 if ($7 > UINT8_MAX)
262 yyfatal("scrub ttl is too big");
263 current_peer.scrub.pfss_ttl = $7;
264 }
265 ;
266
267
268 %%
269
270 static void
271 parse_init(void)
272 {
273 memset(&global_state, 0, sizeof(global_state));
274 memset(¤t_peer, 0, sizeof(current_peer));
275 src_peer = NULL;
276 dst_peer = NULL;
277 }
278
279 static bool
280 get_pfsync_host(const char* str, struct pfsync_state_host* host, sa_family_t* af)
281 {
282 size_t count_colon, addr_len, port_len;
283 const char* p, *last_colon, *first_bracket, *last_bracket;
284 char buf[48];
285 char buf_port[6];
286
287 if (str == NULL || *str == '\0')
288 return false;
289
290 p = str;
291 last_colon = NULL;
292 count_colon = 0;
293
294 while (*p != '\0') {
295 if (*p == ':') {
296 count_colon++;
297 last_colon = p;
298 }
299 p++;
300 }
301
302 /*
303 * If no colon, it is not an expected addr
304 * If there are more than one colon, we guess that af = AF_INET6
305 */
306
307 if (count_colon == 0)
308 return false;
309
310 if (count_colon == 1)
311 *af = AF_INET;
312 else
313 *af = AF_INET6;
314
315 /*
316 * First bracket must be next character after last colon
317 * Last bracket must be the last character
318 * distance between both must be <= 7
319 */
320
321 if (*(last_colon+1) == '[')
322 first_bracket = last_colon + 1;
323 else
324 return false;
325
326 last_bracket = str + (strlen(str) - 1);
327 if (*last_bracket != ']')
328 return false;
329
330 port_len = last_bracket - first_bracket;
331 if (last_bracket - first_bracket > 7)
332 return false;
333
334 memcpy(buf_port, first_bracket +1, port_len - 1);
335 buf_port[port_len-1]= '\0';
336
337 addr_len = last_colon - str;
338 if (addr_len >= sizeof(buf))
339 return false;
340 memcpy(buf, str, addr_len);
341 buf[addr_len] = '\0';
342
343 if (inet_pton(*af, buf, &host->addr) != 1)
344 return false;
345
346 host->port = htons(atoi(buf_port));
347
348 return true;
349 }
350
351 static uint8_t
352 retrieve_peer_state(const char* str, int proto)
353 {
354 uint8_t i;
355
356 if (proto == IPPROTO_TCP) {
357 i = 0;
358 while (i < TCP_NSTATES) {
359 if (strcmp(str, tcpstates[i]) == 0)
360 return i;
361 i++;
362 }
363 yyfatal("Invalid peer state");
364
365 } else {
366 if (proto == IPPROTO_UDP) {
367 const char* mystates[] = PFUDPS_NAMES;
368 i = 0;
369
370 while (i < PFUDPS_NSTATES) {
371 if (strcmp(str, mystates[i]) == 0)
372 return i;
373 i++;
374 }
375
376 yyfatal("Invalid peer state");
377 } else {
378 const char *mystates[] = PFOTHERS_NAMES;
379 i = 0;
380
381 while (i < PFOTHERS_NSTATES) {
382 if (strcmp(str, mystates[i]) == 0)
383 return i;
384 i++;
385 }
386
387 yyfatal("Invalid peer state");
388 }
389 }
390 /*NOTREACHED*/
391 return 0;
392 }
393
394 static bool
395 strtou32(const char* str, uint32_t* res)
396 {
397 uintmax_t u;
398 errno = 0;
399 u = strtoumax(str, NULL, 10);
400 if (errno == ERANGE && u == UINTMAX_MAX)
401 return false;
402 if (u > UINT32_MAX)
403 return false;
404 *res = (uint32_t) u;
405 return true;
406 }
407
408 static bool
409 retrieve_seq(const char* str, struct pfsync_state_peer* peer)
410 {
411 const char* p, *p_colon, *p_comma;
412 char buf[100];
413 size_t size;
414
415 if (str == NULL || *str == '\0')
416 return false;
417
418 if (*str != '[' || *(str+(strlen(str) -1)) != ']')
419 return false;
420
421 p = str;
422 p_colon = NULL;
423 p_comma = NULL;
424 while (*p != '\0') {
425 if (*p == ':') {
426 if (p_colon !=NULL)
427 return false;
428 else
429 p_colon = p;
430 }
431
432 if (*p == ',') {
433 if (p_comma != NULL)
434 return false;
435 else
436 p_comma = p;
437 }
438 p++;
439 }
440
441 size = p_colon - str;
442 if (size > sizeof(buf))
443 return false;
444 memcpy(buf, str+1, size-1);
445 buf[size-1] = '\0';
446
447 if (!strtou32(buf, &peer->seqlo))
448 return false;
449
450
451 if (p_comma == NULL)
452 size = str + strlen(str) - 1 - p_colon;
453 else
454 size = p_comma - p_colon;
455
456 if (size > sizeof(buf))
457 return false;
458 memcpy(buf, p_colon+1, size -1);
459 buf[size-1] = '\0';
460
461 if (!strtou32(buf, &peer->seqhi))
462 return false;
463
464 if (p_comma == NULL) {
465 peer->seqdiff = 0;
466 } else {
467 size = str + strlen(str) - 1 - p_comma;
468 if (size > sizeof(buf))
469 return false;
470 memcpy(buf, p_comma +1, size -1);
471 buf[size-1] = '\0';
472
473 if (!strtou32(buf, &peer->seqdiff))
474 return false;
475 }
476
477 return true;
478 }
479
480 static void
481 add_state(void)
482 {
483 int idx;
484
485 if (allocated == 0) {
486 allocated = 5;
487 states->ps_buf = malloc(allocated * sizeof(struct pfsync_state));
488 if (states->ps_buf == NULL)
489 yyfatal("Not enougth memory");
490 }
491
492 if (allocated == (states->ps_len / sizeof(struct pfsync_state))) {
493 void *buf;
494 allocated = allocated * 2 + 1;
495 buf = realloc(states->ps_buf, allocated * sizeof(struct pfsync_state));
496 if (buf == NULL) {
497 free(states->ps_buf);
498 yyfatal("Not enougth memory");
499 }
500 states->ps_buf = buf;
501 }
502
503 idx = states->ps_len / sizeof(struct pfsync_state);
504 }
505