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