1/*	$KAME: parser.y,v 1.8 2000/11/08 03:03:34 jinmei Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD$
32 */
33
34%{
35#include <sys/param.h>
36#include <sys/ioctl.h>
37#include <sys/socket.h>
38#include <sys/uio.h>
39#include <sys/queue.h>
40
41#include <net/if.h>
42#if defined(__FreeBSD__) && __FreeBSD__ >= 3
43#include <net/if_var.h>
44#endif /* __FreeBSD__ >= 3 */
45
46#include <netinet/in.h>
47#include <netinet/in_var.h>
48#include <netinet/icmp6.h>
49
50#include <limits.h>
51#include <netdb.h>
52#include <string.h>
53#include <stdio.h>
54
55#include "rrenumd.h"
56
57struct config_is_set {
58	u_short cis_dest : 1;
59} cis;
60
61struct dst_list *dl_head;
62struct payload_list *pl_head, ple_cur;
63u_int retry;
64char errbuf[LINE_MAX];
65
66extern int lineno;
67extern void yyerror(const char *s);
68extern int yylex(void);
69static struct payload_list * pllist_lookup(int seqnum);
70static void pllist_enqueue(struct payload_list *pl_entry);
71
72#define MAX_RETRYNUM 10 /* upper limit of retry in this rrenumd program */
73#define MAX_SEQNUM 256 /* upper limit of seqnum in this rrenumd program */
74#define NOSPEC	-1
75
76%}
77
78%union {
79	u_long num;
80	struct {
81		char *cp;
82		int len;
83	} cs;
84	struct in_addr addr4;
85	struct in6_addr addr6;
86	struct {
87		struct in6_addr addr;
88		u_char plen;
89	} prefix;
90	struct dst_list *dl;
91	struct payload_list *pl;
92	struct sockaddr *sa;
93}
94
95%token <num> ADD CHANGE SETGLOBAL
96%token DEBUG_CMD DEST_CMD RETRY_CMD SEQNUM_CMD
97%token MATCH_PREFIX_CMD MAXLEN_CMD MINLEN_CMD
98%token USE_PREFIX_CMD KEEPLEN_CMD
99%token VLTIME_CMD PLTIME_CMD
100%token RAF_ONLINK_CMD RAF_AUTO_CMD RAF_DECRVALID_CMD RAF_DECRPREFD_CMD
101%token <num> DAYS HOURS MINUTES SECONDS INFINITY
102%token <num> ON OFF
103%token BCL ECL EOS ERROR
104%token <cs> NAME HOSTNAME QSTRING DECSTRING
105%token <addr4> IPV4ADDR
106%token <addr6> IPV6ADDR
107%token <num> PREFIXLEN
108
109%type <num> retrynum seqnum rrenum_cmd
110%type <num> prefixlen maxlen minlen keeplen vltime pltime
111%type <num> lifetime days hours minutes seconds
112%type <num> decstring
113%type <num> raf_onlink raf_auto raf_decrvalid raf_decrprefd flag
114%type <dl> dest_addrs dest_addr sin sin6
115%type <pl> rrenum_statement
116%type <cs> ifname
117%type <prefix> prefixval
118
119%%
120config:
121		/* empty */
122	| 	statements
123	;
124
125statements:
126		statement
127	| 	statements statement
128	;
129
130statement:
131		debug_statement
132	|	destination_statement
133	|	rrenum_statement_without_seqnum
134	|	rrenum_statement_with_seqnum
135	|	error EOS
136		{
137			yyerrok;
138		}
139	|	EOS
140	;
141
142debug_statement:
143		DEBUG_CMD flag EOS
144		{
145#ifdef YYDEBUG
146			yydebug = $2;
147#endif /* YYDEBUG */
148		}
149	;
150
151destination_statement:
152		DEST_CMD dest_addrs retrynum EOS
153		{
154			dl_head = $2;
155			retry = $3;
156		}
157	;
158
159dest_addrs:
160		dest_addr
161	|	dest_addrs dest_addr
162		{
163			$2->dl_next = $1;
164			$$ = $2;
165		}
166	;
167
168dest_addr :
169		sin
170		{
171			with_v4dest = 1;
172		}
173	|	sin6
174		{
175			with_v6dest = 1;
176		}
177	|	sin6 ifname
178		{
179			struct sockaddr_in6 *sin6;
180
181			sin6 = (struct sockaddr_in6 *)$1->dl_dst;
182			sin6->sin6_scope_id = if_nametoindex($2.cp);
183			with_v6dest = 1;
184			$$ = $1;
185		}
186	|	HOSTNAME
187		{
188			struct sockaddr_storage *ss;
189			struct addrinfo hints, *res;
190			int error;
191
192			memset(&hints, 0, sizeof(hints));
193			hints.ai_flags = AI_CANONNAME;
194			hints.ai_family = AF_UNSPEC;
195			hints.ai_socktype = SOCK_RAW;
196			hints.ai_protocol = 0;
197			error = getaddrinfo($1.cp, 0, &hints, &res);
198			if (error) {
199				snprintf(errbuf, sizeof(errbuf),
200				    "name resolution failed for %s:%s",
201				    $1.cp, gai_strerror(error));
202				yyerror(errbuf);
203			}
204			ss = (struct sockaddr_storage *)malloc(sizeof(*ss));
205			memset(ss, 0, sizeof(*ss));
206			memcpy(ss, res->ai_addr, res->ai_addr->sa_len);
207			freeaddrinfo(res);
208
209			$$ = (struct dst_list *)
210			     malloc(sizeof(struct dst_list));
211			memset($$, 0, sizeof(struct dst_list));
212			$$->dl_dst = (struct sockaddr *)ss;
213		}
214	;
215
216sin:
217		IPV4ADDR
218		{
219			struct sockaddr_in *sin;
220
221			sin = (struct sockaddr_in *)malloc(sizeof(*sin));
222			memset(sin, 0, sizeof(*sin));
223			sin->sin_len = sizeof(*sin);
224			sin->sin_family = AF_INET;
225			sin->sin_addr = $1;
226
227			$$ = (struct dst_list *)
228			     malloc(sizeof(struct dst_list));
229			memset($$, 0, sizeof(struct dst_list));
230			$$->dl_dst = (struct sockaddr *)sin;
231		}
232	;
233
234sin6:
235		IPV6ADDR
236		{
237			struct sockaddr_in6 *sin6;
238
239			sin6 = (struct sockaddr_in6 *)malloc(sizeof(*sin6));
240			memset(sin6, 0, sizeof(*sin6));
241			sin6->sin6_len = sizeof(*sin6);
242			sin6->sin6_family = AF_INET6;
243			sin6->sin6_addr = $1;
244
245			$$ = (struct dst_list *)
246			     malloc(sizeof(struct dst_list));
247			memset($$, 0, sizeof(struct dst_list));
248			$$->dl_dst = (struct sockaddr *)sin6;
249		}
250
251ifname:
252		NAME
253		{
254			$$.cp = strdup($1.cp);
255			$$.len = $1.len;
256		}
257	|	QSTRING
258		{
259			$1.cp[$1.len - 1] = 0;
260			$$.cp = strdup(&$1.cp[1]);
261			$$.len = $1.len - 2;
262		}
263	;
264
265retrynum:
266		/* empty */
267		{
268			$$ = 2;
269		}
270	|	RETRY_CMD decstring
271		{
272			if ($2 > MAX_RETRYNUM)
273				$2 = MAX_RETRYNUM;
274			$$ = $2;
275		}
276	;
277
278rrenum_statement_with_seqnum:
279		SEQNUM_CMD seqnum
280		{
281			if (pllist_lookup($2)) {
282				snprintf(errbuf, sizeof(errbuf),
283				    "duplicate seqnum %ld specified at %d",
284				    $2, lineno);
285				yyerror(errbuf);
286			}
287		}
288		BCL rrenum_statement EOS ECL EOS
289		{
290			$5->pl_irr.rr_seqnum = $2;
291			pllist_enqueue($5);
292		}
293	;
294
295seqnum:
296		/* empty */
297		{
298			$$ = 0;
299		}
300	|	decstring
301		{
302			if ($1 > MAX_SEQNUM) {
303				snprintf(errbuf, sizeof(errbuf),
304				    "seqnum %ld is illegal for this  program. "
305				    "should be between 0 and %d",
306				    $1, MAX_SEQNUM);
307				yyerror(errbuf);
308			}
309			$$ = $1;
310		}
311	;
312
313rrenum_statement_without_seqnum:
314		rrenum_statement EOS
315		{
316			if (pllist_lookup(0)) {
317				snprintf(errbuf, sizeof(errbuf),
318				    "duplicate seqnum %d specified  at %d",
319				    0, lineno);
320				yyerror(errbuf);
321			}
322			$1->pl_irr.rr_seqnum = 0;
323			pllist_enqueue($1);
324		}
325	;
326
327rrenum_statement:
328		match_prefix_definition use_prefix_definition
329		{
330			$$ = (struct payload_list *)
331			     malloc(sizeof(struct payload_list));
332			memcpy($$, &ple_cur, sizeof(ple_cur));
333		}
334	;
335
336match_prefix_definition:
337		rrenum_cmd MATCH_PREFIX_CMD prefixval maxlen minlen
338		{
339			struct icmp6_router_renum *irr;
340			struct rr_pco_match *rpm;
341
342			irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
343			rpm = (struct rr_pco_match *)(irr + 1);
344			memset(rpm, 0, sizeof(*rpm));
345
346			rpm->rpm_code = $1;
347			rpm->rpm_prefix = $3.addr;
348			rpm->rpm_matchlen = $3.plen;
349			rpm->rpm_maxlen = $4;
350			rpm->rpm_minlen = $5;
351		}
352	;
353
354rrenum_cmd:
355		/* empty */
356		{
357			$$ = RPM_PCO_ADD;
358		}
359	|	ADD
360	|	CHANGE
361	|	SETGLOBAL
362	;
363
364prefixval:
365		IPV6ADDR prefixlen
366		{
367			$$.addr = $1;
368			$$.plen = $2;
369		}
370	;
371
372prefixlen:
373		/* empty */
374		{
375			$$ = 64;
376		}
377	|	PREFIXLEN
378	;
379
380maxlen:
381		/* empty */
382		{
383			$$ = 128;
384		}
385	|	MAXLEN_CMD decstring
386		{
387			if ($2 > 128)
388				$2 = 128;
389			$$ = $2;
390		}
391	;
392
393minlen:
394		/* empty */
395		{
396			$$ = 0;
397		}
398	|	MINLEN_CMD decstring
399		{
400			if ($2 > 128)
401				$2 = 128;
402			$$ = $2;
403		}
404	;
405
406use_prefix_definition:
407		/* empty */
408		{
409			struct icmp6_router_renum *irr;
410			struct rr_pco_match *rpm;
411			struct rr_pco_use *rpu;
412
413			irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
414			rpm = (struct rr_pco_match *)(irr + 1);
415			rpu = (struct rr_pco_use *)(rpm + 1);
416			memset(rpu, 0, sizeof(*rpu));
417		}
418	|	USE_PREFIX_CMD prefixval keeplen use_prefix_values
419		{
420			struct icmp6_router_renum *irr;
421			struct rr_pco_match *rpm;
422			struct rr_pco_use *rpu;
423
424			irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
425			rpm = (struct rr_pco_match *)(irr + 1);
426			rpu = (struct rr_pco_use *)(rpm + 1);
427
428			rpu->rpu_prefix = $2.addr;
429			rpu->rpu_uselen = $2.plen;
430			rpu->rpu_keeplen = $3;
431		}
432	;
433
434use_prefix_values:
435		/* empty */
436		{
437			struct icmp6_router_renum *irr;
438			struct rr_pco_match *rpm;
439			struct rr_pco_use *rpu;
440
441			irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
442			rpm = (struct rr_pco_match *)(irr + 1);
443			rpu = (struct rr_pco_use *)(rpm + 1);
444			memset(rpu, 0, sizeof(*rpu));
445
446			rpu->rpu_vltime = htonl(DEF_VLTIME);
447			rpu->rpu_pltime = htonl(DEF_PLTIME);
448			rpu->rpu_ramask = 0;
449			rpu->rpu_flags = 0;
450		}
451	|	BCL vltime pltime raf_onlink raf_auto raf_decrvalid raf_decrprefd ECL
452		{
453			struct icmp6_router_renum *irr;
454			struct rr_pco_match *rpm;
455			struct rr_pco_use *rpu;
456
457			irr = (struct icmp6_router_renum *)&ple_cur.pl_irr;
458			rpm = (struct rr_pco_match *)(irr + 1);
459			rpu = (struct rr_pco_use *)(rpm + 1);
460			memset(rpu, 0, sizeof(*rpu));
461
462			rpu->rpu_vltime = $2;
463			rpu->rpu_pltime = $3;
464			if ($4 == NOSPEC) {
465				rpu->rpu_ramask &=
466				    ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
467			} else {
468				rpu->rpu_ramask |=
469				    ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
470				if ($4 == ON) {
471					rpu->rpu_raflags |=
472					    ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
473				} else {
474					rpu->rpu_raflags &=
475					    ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK;
476				}
477			}
478			if ($5 == NOSPEC) {
479				rpu->rpu_ramask &=
480				    ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
481			} else {
482				rpu->rpu_ramask |=
483				    ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
484				if ($5 == ON) {
485					rpu->rpu_raflags |=
486					    ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
487				} else {
488					rpu->rpu_raflags &=
489					    ~ICMP6_RR_PCOUSE_RAFLAGS_AUTO;
490				}
491			}
492			rpu->rpu_flags = 0;
493			if ($6 == ON) {
494				rpu->rpu_flags |=
495				    ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME;
496			}
497			if ($7 == ON) {
498				rpu->rpu_flags |=
499				    ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME;
500			}
501		}
502	;
503
504keeplen:
505		/* empty */
506		{
507			$$ = 0;
508		}
509	|	KEEPLEN_CMD decstring
510		{
511			if ($2 > 128)
512				$2 = 128;
513			$$ = $2;
514		}
515	;
516
517
518vltime:
519		/* empty */
520		{
521			$$ = htonl(DEF_VLTIME);
522		}
523	|	VLTIME_CMD lifetime
524		{
525			$$ = htonl($2);
526		}
527	;
528
529pltime:
530		/* empty */
531		{
532			$$ = htonl(DEF_PLTIME);
533		}
534	|	PLTIME_CMD lifetime
535		{
536			$$ = htonl($2);
537		}
538
539raf_onlink:
540		/* empty */
541		{
542			$$ = NOSPEC;
543		}
544	|	RAF_ONLINK_CMD flag
545		{
546			$$ = $2;
547		}
548	;
549
550raf_auto:
551		/* empty */
552		{
553			$$ = NOSPEC;
554		}
555	|	RAF_AUTO_CMD flag
556		{
557			$$ = $2;
558		}
559	;
560
561raf_decrvalid:
562		/* empty */
563		{
564			$$ = NOSPEC;
565		}
566	|	RAF_DECRVALID_CMD flag
567		{
568			$$ = $2;
569		}
570	;
571
572raf_decrprefd:
573		/* empty */
574		{
575			$$ = NOSPEC;
576		}
577	|	RAF_DECRPREFD_CMD flag
578		{
579			$$ = $2;
580		}
581	;
582
583flag:
584		ON { $$ = ON; }
585	|	OFF { $$ = OFF; }
586	;
587
588lifetime:
589		decstring
590	|	INFINITY
591		{
592			$$ = 0xffffffff;
593		}
594	|	days hours minutes seconds
595		{
596			int d, h, m, s;
597
598			d = $1 * 24 * 60 * 60;
599			h = $2 * 60 * 60;
600			m = $3 * 60;
601			s = $4;
602			$$ = d + h + m + s;
603		}
604	;
605
606days:
607		/* empty */
608		{
609			$$ = 0;
610		}
611	|	DAYS
612	;
613
614hours:
615		/* empty */
616		{
617			$$ = 0;
618		}
619	|	HOURS
620	;
621
622minutes:
623		/* empty */
624		{
625			$$ = 0;
626		}
627	|	MINUTES
628	;
629
630seconds:
631		/* empty */
632		{
633			$$ = 0;
634		}
635	|	SECONDS
636	;
637
638decstring:
639		DECSTRING
640		{
641			int dval;
642
643			dval = atoi($1.cp);
644			$$ = dval;
645		}
646	;
647
648%%
649
650static struct payload_list *
651pllist_lookup(int seqnum)
652{
653	struct payload_list *pl;
654	for (pl = pl_head; pl && pl->pl_irr.rr_seqnum != seqnum;
655	     pl = pl->pl_next)
656		continue;
657	return (pl);
658}
659
660static void
661pllist_enqueue(struct payload_list *pl_entry)
662{
663	struct payload_list *pl, *pl_last;
664
665	pl_last = NULL;
666	for (pl = pl_head;
667	     pl && pl->pl_irr.rr_seqnum < pl_entry->pl_irr.rr_seqnum;
668	     pl_last = pl, pl = pl->pl_next)
669		continue;
670	if (pl_last)
671		pl_last->pl_next = pl_entry;
672	else
673		pl_head = pl_entry;
674
675	return;
676}
677