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