1/*
2 *   $Id: gram.y,v 1.21 2009/06/19 07:34:07 psavola Exp $
3 *
4 *   Authors:
5 *    Pedro Roque		<roque@di.fc.ul.pt>
6 *    Lars Fenneberg		<lf@elemental.net>
7 *
8 *   This software is Copyright 1996-2000 by the above mentioned author(s),
9 *   All Rights Reserved.
10 *
11 *   The license which is distributed with this software in the file COPYRIGHT
12 *   applies to this software. If your distribution is missing this file, you
13 *   may request it from <pekkas@netcore.fi>.
14 *
15 */
16%{
17#include <config.h>
18#include <includes.h>
19#include <radvd.h>
20#include <defaults.h>
21
22extern struct Interface *IfaceList;
23struct Interface *iface = NULL;
24struct AdvPrefix *prefix = NULL;
25struct AdvRoute *route = NULL;
26struct AdvRDNSS *rdnss = NULL;
27
28extern char *conf_file;
29extern int num_lines;
30extern char *yytext;
31extern int sock;
32
33static void cleanup(void);
34static void yyerror(char *msg);
35
36#if 0 /* no longer necessary? */
37#ifndef HAVE_IN6_ADDR_S6_ADDR
38# ifdef __FreeBSD__
39#  define s6_addr32 __u6_addr.__u6_addr32
40#  define s6_addr16 __u6_addr.__u6_addr16
41# endif
42#endif
43#endif
44
45#define ABORT	do { cleanup(); YYABORT; } while (0);
46
47%}
48
49%token		T_INTERFACE
50%token		T_PREFIX
51%token		T_ROUTE
52%token		T_RDNSS
53%token		T_CLIENTS
54
55%token	<str>	STRING
56%token	<num>	NUMBER
57%token	<snum>	SIGNEDNUMBER
58%token	<dec>	DECIMAL
59%token	<num>	SWITCH
60%token	<addr>	IPV6ADDR
61%token 		INFINITY
62
63%token		T_IgnoreIfMissing
64%token		T_AdvSendAdvert
65%token		T_MaxRtrAdvInterval
66%token		T_MinRtrAdvInterval
67%token		T_MinDelayBetweenRAs
68%token		T_AdvManagedFlag
69%token		T_AdvOtherConfigFlag
70%token		T_AdvLinkMTU
71%token		T_AdvReachableTime
72%token		T_AdvRetransTimer
73%token		T_AdvCurHopLimit
74%token		T_AdvDefaultLifetime
75%token		T_AdvDefaultPreference
76%token		T_AdvSourceLLAddress
77
78%token		T_AdvOnLink
79%token		T_AdvAutonomous
80%token		T_AdvValidLifetime
81%token		T_AdvPreferredLifetime
82
83%token		T_AdvRouterAddr
84%token		T_AdvHomeAgentFlag
85%token		T_AdvIntervalOpt
86%token		T_AdvHomeAgentInfo
87
88%token		T_Base6to4Interface
89%token		T_UnicastOnly
90
91%token		T_HomeAgentPreference
92%token		T_HomeAgentLifetime
93
94%token		T_AdvRoutePreference
95%token		T_AdvRouteLifetime
96
97%token		T_AdvRDNSSPreference
98%token		T_AdvRDNSSOpenFlag
99%token		T_AdvRDNSSLifetime
100
101%token		T_AdvMobRtrSupportFlag
102
103%token		T_BAD_TOKEN
104
105%type	<str>	name
106%type	<pinfo> optional_prefixlist prefixdef prefixlist
107%type	<ainfo> optional_clientslist clientslist v6addrlist
108%type	<rinfo>	optional_routelist routedef routelist
109%type	<rdnssinfo> optional_rdnsslist rdnssdef rdnsslist
110%type   <num>	number_or_infinity
111
112%union {
113	unsigned int		num;
114	int			snum;
115	double			dec;
116	struct in6_addr		*addr;
117	char			*str;
118	struct AdvPrefix	*pinfo;
119	struct AdvRoute		*rinfo;
120	struct AdvRDNSS		*rdnssinfo;
121	struct Clients		*ainfo;
122};
123
124%%
125
126grammar		: grammar ifacedef
127		| ifacedef
128		;
129
130ifacedef	: ifacehead '{' ifaceparams  '}' ';'
131		{
132			struct Interface *iface2;
133
134			iface2 = IfaceList;
135			while (iface2)
136			{
137				if (!strcmp(iface2->Name, iface->Name))
138				{
139					flog(LOG_ERR, "duplicate interface "
140						"definition for %s", iface->Name);
141					ABORT;
142				}
143				iface2 = iface2->next;
144			}
145
146			if (check_device(sock, iface) < 0) {
147				if (iface->IgnoreIfMissing) {
148					dlog(LOG_DEBUG, 4, "interface %s did not exist, ignoring the interface", iface->Name);
149					goto skip_interface;
150				}
151				else {
152					flog(LOG_ERR, "interface %s does not exist", iface->Name);
153					ABORT;
154				}
155			}
156			if (setup_deviceinfo(sock, iface) < 0)
157				ABORT;
158			if (check_iface(iface) < 0)
159				ABORT;
160			if (setup_linklocal_addr(sock, iface) < 0)
161				ABORT;
162			if (setup_allrouters_membership(sock, iface) < 0)
163				ABORT;
164
165			iface->next = IfaceList;
166			IfaceList = iface;
167
168			dlog(LOG_DEBUG, 4, "interface definition for %s is ok", iface->Name);
169
170skip_interface:
171			iface = NULL;
172		};
173
174ifacehead	: T_INTERFACE name
175		{
176			iface = malloc(sizeof(struct Interface));
177
178			if (iface == NULL) {
179				flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
180				ABORT;
181			}
182
183			iface_init_defaults(iface);
184			strncpy(iface->Name, $2, IFNAMSIZ-1);
185			iface->Name[IFNAMSIZ-1] = '\0';
186		}
187		;
188
189name		: STRING
190		{
191			/* check vality */
192			$$ = $1;
193		}
194		;
195
196ifaceparams	: optional_ifacevlist optional_prefixlist optional_clientslist optional_routelist optional_rdnsslist
197		{
198			iface->AdvPrefixList = $2;
199			iface->ClientList = $3;
200			iface->AdvRouteList = $4;
201			iface->AdvRDNSSList = $5;
202		}
203		;
204
205optional_ifacevlist: /* empty */
206		   | ifacevlist
207		   ;
208
209optional_prefixlist: /* empty */
210		{
211			$$ = NULL;
212		}
213		| prefixlist
214		;
215
216optional_clientslist: /* empty */
217		{
218			$$ = NULL;
219		}
220		| clientslist
221		;
222
223optional_routelist: /* empty */
224		{
225			$$ = NULL;
226		}
227		| routelist
228		;
229
230optional_rdnsslist: /* empty */
231		{
232			$$ = NULL;
233		}
234		| rdnsslist
235		;
236
237ifacevlist	: ifacevlist ifaceval
238		| ifaceval
239		;
240
241ifaceval	: T_MinRtrAdvInterval NUMBER ';'
242		{
243			iface->MinRtrAdvInterval = $2;
244		}
245		| T_MaxRtrAdvInterval NUMBER ';'
246		{
247			iface->MaxRtrAdvInterval = $2;
248		}
249		| T_MinDelayBetweenRAs NUMBER ';'
250		{
251			iface->MinDelayBetweenRAs = $2;
252		}
253		| T_MinRtrAdvInterval DECIMAL ';'
254		{
255			iface->MinRtrAdvInterval = $2;
256		}
257		| T_MaxRtrAdvInterval DECIMAL ';'
258		{
259			iface->MaxRtrAdvInterval = $2;
260		}
261		| T_MinDelayBetweenRAs DECIMAL ';'
262		{
263			iface->MinDelayBetweenRAs = $2;
264		}
265		| T_IgnoreIfMissing SWITCH ';'
266		{
267			iface->IgnoreIfMissing = $2;
268		}
269		| T_AdvSendAdvert SWITCH ';'
270		{
271			iface->AdvSendAdvert = $2;
272		}
273		| T_AdvManagedFlag SWITCH ';'
274		{
275			iface->AdvManagedFlag = $2;
276		}
277		| T_AdvOtherConfigFlag SWITCH ';'
278		{
279			iface->AdvOtherConfigFlag = $2;
280		}
281		| T_AdvLinkMTU NUMBER ';'
282		{
283			iface->AdvLinkMTU = $2;
284		}
285		| T_AdvReachableTime NUMBER ';'
286		{
287			iface->AdvReachableTime = $2;
288		}
289		| T_AdvRetransTimer NUMBER ';'
290		{
291			iface->AdvRetransTimer = $2;
292		}
293		| T_AdvDefaultLifetime NUMBER ';'
294		{
295			iface->AdvDefaultLifetime = $2;
296		}
297		| T_AdvDefaultPreference SIGNEDNUMBER ';'
298		{
299			iface->AdvDefaultPreference = $2;
300		}
301		| T_AdvCurHopLimit NUMBER ';'
302		{
303			iface->AdvCurHopLimit = $2;
304		}
305		| T_AdvSourceLLAddress SWITCH ';'
306		{
307			iface->AdvSourceLLAddress = $2;
308		}
309		| T_AdvIntervalOpt SWITCH ';'
310		{
311			iface->AdvIntervalOpt = $2;
312		}
313		| T_AdvHomeAgentInfo SWITCH ';'
314		{
315			iface->AdvHomeAgentInfo = $2;
316		}
317		| T_AdvHomeAgentFlag SWITCH ';'
318		{
319			iface->AdvHomeAgentFlag = $2;
320		}
321		| T_HomeAgentPreference NUMBER ';'
322		{
323			iface->HomeAgentPreference = $2;
324		}
325		| T_HomeAgentLifetime NUMBER ';'
326		{
327			iface->HomeAgentLifetime = $2;
328		}
329		| T_UnicastOnly SWITCH ';'
330		{
331			iface->UnicastOnly = $2;
332		}
333		| T_AdvMobRtrSupportFlag SWITCH ';'
334		{
335			iface->AdvMobRtrSupportFlag = $2;
336		}
337		;
338
339clientslist	: T_CLIENTS '{' v6addrlist '}' ';'
340		{
341			$$ = $3;
342		}
343		;
344
345v6addrlist	: IPV6ADDR ';'
346		{
347			struct Clients *new = calloc(1, sizeof(struct Clients));
348			if (new == NULL) {
349				flog(LOG_CRIT, "calloc failed: %s", strerror(errno));
350				ABORT;
351			}
352
353			memcpy(&(new->Address), $1, sizeof(struct in6_addr));
354			$$ = new;
355		}
356		| v6addrlist IPV6ADDR ';'
357		{
358			struct Clients *new = calloc(1, sizeof(struct Clients));
359			if (new == NULL) {
360				flog(LOG_CRIT, "calloc failed: %s", strerror(errno));
361				ABORT;
362			}
363
364			memcpy(&(new->Address), $2, sizeof(struct in6_addr));
365			new->next = $1;
366			$$ = new;
367		}
368		;
369
370
371prefixlist	: prefixdef optional_prefixlist
372		{
373			$1->next = $2;
374			$$ = $1;
375		}
376		;
377
378prefixdef	: prefixhead '{' optional_prefixplist '}' ';'
379		{
380			unsigned int dst;
381
382			if (prefix->AdvPreferredLifetime >
383			    prefix->AdvValidLifetime)
384			{
385				flog(LOG_ERR, "AdvValidLifeTime must be "
386					"greater than AdvPreferredLifetime in %s, line %d",
387					conf_file, num_lines);
388				ABORT;
389			}
390
391			if( prefix->if6to4[0] )
392			{
393				if (get_v4addr(prefix->if6to4, &dst) < 0)
394				{
395					flog(LOG_ERR, "interface %s has no IPv4 addresses, disabling 6to4 prefix", prefix->if6to4 );
396					prefix->enabled = 0;
397				} else
398				{
399					*((uint16_t *)(prefix->Prefix.s6_addr)) = htons(0x2002);
400					memcpy( prefix->Prefix.s6_addr + 2, &dst, sizeof( dst ) );
401				}
402			}
403
404			$$ = prefix;
405			prefix = NULL;
406		}
407		;
408
409prefixhead	: T_PREFIX IPV6ADDR '/' NUMBER
410		{
411			struct in6_addr zeroaddr;
412			prefix = malloc(sizeof(struct AdvPrefix));
413
414			if (prefix == NULL) {
415				flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
416				ABORT;
417			}
418
419			prefix_init_defaults(prefix);
420
421			if ($4 > MAX_PrefixLen)
422			{
423				flog(LOG_ERR, "invalid prefix length in %s, line %d", conf_file, num_lines);
424				ABORT;
425			}
426
427			prefix->PrefixLen = $4;
428
429			memcpy(&prefix->Prefix, $2, sizeof(struct in6_addr));
430
431			memset(&zeroaddr, 0, sizeof(zeroaddr));
432			if (!memcmp($2, &zeroaddr, sizeof(struct in6_addr))) {
433#ifndef HAVE_IFADDRS_H
434				flog(LOG_ERR, "invalid all-zeros prefix in %s, line %d", conf_file, num_lines);
435				ABORT;
436#else
437				dlog(LOG_DEBUG, 5, "all-zeros prefix in %s, line %d, parsing..", conf_file, num_lines);
438				struct ifaddrs *ifap, *ifa;
439				if (getifaddrs(&ifap) != 0)
440					flog(LOG_ERR, "getifaddrs failed: %s", strerror(errno));
441			        for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
442				        struct sockaddr_in6 *s6;
443					char buf[INET6_ADDRSTRLEN];
444					if (strncmp(ifa->ifa_name, iface->Name, IFNAMSIZ))
445						continue;
446                			if (ifa->ifa_addr->sa_family != AF_INET6)
447			                        continue;
448					s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
449	                		if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr))
450						continue;
451					if (inet_ntop(ifa->ifa_addr->sa_family, (void *)&(s6->sin6_addr), buf, sizeof(buf)) == NULL) {
452						flog(LOG_ERR, "%s: inet_ntop failed in %s, line %d!", ifa->ifa_name, conf_file, num_lines);
453					}
454					else {
455						dlog(LOG_DEBUG, 5, "auto-selected prefix %s on interface %s", buf, ifa->ifa_name);
456						memcpy(&prefix->Prefix, &s6->sin6_addr, sizeof(struct in6_addr));
457						prefix->AdvRouterAddr=1;
458						prefix->AutoSelected=1;
459					}
460				}
461				if (!memcmp(&prefix->Prefix, &zeroaddr, sizeof(struct in6_addr))) {
462					prefix->enabled = 0;
463					flog(LOG_WARNING, "no auto-selected prefix on interface %s, disabling advertisements",  iface->Name);
464				}
465				freeifaddrs(ifap);
466				freeifaddrs(ifa);
467#endif /* ifndef HAVE_IFADDRS_H */
468			}
469		}
470		;
471
472optional_prefixplist: /* empty */
473		| prefixplist
474		;
475
476prefixplist	: prefixplist prefixparms
477		| prefixparms
478		;
479
480prefixparms	: T_AdvOnLink SWITCH ';'
481		{
482			prefix->AdvOnLinkFlag = $2;
483		}
484		| T_AdvAutonomous SWITCH ';'
485		{
486			prefix->AdvAutonomousFlag = $2;
487		}
488		| T_AdvRouterAddr SWITCH ';'
489		{
490			if (prefix->AutoSelected && $2 == 0)
491				flog(LOG_WARNING, "prefix automatically selected, AdvRouterAddr always enabled, ignoring config line %d", num_lines);
492			else
493				prefix->AdvRouterAddr = $2;
494		}
495		| T_AdvValidLifetime number_or_infinity ';'
496		{
497			prefix->AdvValidLifetime = $2;
498		}
499		| T_AdvPreferredLifetime number_or_infinity ';'
500		{
501			prefix->AdvPreferredLifetime = $2;
502		}
503		| T_Base6to4Interface name ';'
504		{
505			if (prefix->AutoSelected) {
506				flog(LOG_ERR, "automatically selecting the prefix and Base6to4Interface are mutually exclusive");
507				ABORT;
508			} /* fallthrough */
509			dlog(LOG_DEBUG, 4, "using interface %s for 6to4", $2);
510			strncpy(prefix->if6to4, $2, IFNAMSIZ-1);
511			prefix->if6to4[IFNAMSIZ-1] = '\0';
512		}
513		;
514
515routelist	: routedef optional_routelist
516		{
517			$1->next = $2;
518			$$ = $1;
519		}
520		;
521
522routedef	: routehead '{' optional_routeplist '}' ';'
523		{
524			$$ = route;
525			route = NULL;
526		}
527		;
528
529
530routehead	: T_ROUTE IPV6ADDR '/' NUMBER
531		{
532			route = malloc(sizeof(struct AdvRoute));
533
534			if (route == NULL) {
535				flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
536				ABORT;
537			}
538
539			route_init_defaults(route, iface);
540
541			if ($4 > MAX_PrefixLen)
542			{
543				flog(LOG_ERR, "invalid route prefix length in %s, line %d", conf_file, num_lines);
544				ABORT;
545			}
546
547			route->PrefixLen = $4;
548
549			memcpy(&route->Prefix, $2, sizeof(struct in6_addr));
550		}
551		;
552
553
554optional_routeplist: /* empty */
555		| routeplist
556		;
557
558routeplist	: routeplist routeparms
559		| routeparms
560		;
561
562
563routeparms	: T_AdvRoutePreference SIGNEDNUMBER ';'
564		{
565			route->AdvRoutePreference = $2;
566		}
567		| T_AdvRouteLifetime number_or_infinity ';'
568		{
569			route->AdvRouteLifetime = $2;
570		}
571		;
572
573rdnsslist	: rdnssdef optional_rdnsslist
574		{
575			$1->next = $2;
576			$$ = $1;
577		}
578		;
579
580rdnssdef	: rdnsshead '{' optional_rdnssplist '}' ';'
581		{
582			$$ = rdnss;
583			rdnss = NULL;
584		}
585		;
586
587rdnssaddrs	: rdnssaddrs rdnssaddr
588		| rdnssaddr
589		;
590
591rdnssaddr	: IPV6ADDR
592		{
593			if (!rdnss) {
594				/* first IP found */
595				rdnss = malloc(sizeof(struct AdvRDNSS));
596
597				if (rdnss == NULL) {
598					flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
599					ABORT;
600				}
601
602				rdnss_init_defaults(rdnss, iface);
603			}
604
605			switch (rdnss->AdvRDNSSNumber) {
606				case 0:
607					memcpy(&rdnss->AdvRDNSSAddr1, $1, sizeof(struct in6_addr));
608					rdnss->AdvRDNSSNumber++;
609					break;
610				case 1:
611					memcpy(&rdnss->AdvRDNSSAddr2, $1, sizeof(struct in6_addr));
612					rdnss->AdvRDNSSNumber++;
613					break;
614				case 2:
615					memcpy(&rdnss->AdvRDNSSAddr3, $1, sizeof(struct in6_addr));
616					rdnss->AdvRDNSSNumber++;
617					break;
618				default:
619					flog(LOG_CRIT, "Too many addresses in RDNSS section");
620					ABORT;
621			}
622
623		}
624		;
625
626rdnsshead	: T_RDNSS rdnssaddrs
627		{
628			if (!rdnss) {
629				flog(LOG_CRIT, "No address specified in RDNSS section");
630				ABORT;
631			}
632		}
633		;
634
635optional_rdnssplist: /* empty */
636		| rdnssplist
637		;
638
639rdnssplist	: rdnssplist rdnssparms
640		| rdnssparms
641		;
642
643
644rdnssparms	: T_AdvRDNSSPreference NUMBER ';'
645		{
646			rdnss->AdvRDNSSPreference = $2;
647		}
648		| T_AdvRDNSSOpenFlag SWITCH ';'
649		{
650			rdnss->AdvRDNSSOpenFlag = $2;
651		}
652		| T_AdvRDNSSLifetime number_or_infinity ';'
653		{
654			if ($2 < iface->MaxRtrAdvInterval && $2 != 0) {
655				flog(LOG_ERR, "AdvRDNSSLifetime must be at least MaxRtrAdvInterval");
656				ABORT;
657			}
658			if ($2 > 2*(iface->MaxRtrAdvInterval))
659				flog(LOG_WARNING, "Warning: AdvRDNSSLifetime <= 2*MaxRtrAdvInterval would allow stale DNS servers to be deleted faster");
660
661			rdnss->AdvRDNSSLifetime = $2;
662		}
663		;
664
665number_or_infinity      : NUMBER
666                        {
667                                $$ = $1;
668                        }
669                        | INFINITY
670                        {
671                                $$ = (uint32_t)~0;
672                        }
673                        ;
674
675%%
676
677static
678void cleanup(void)
679{
680	if (iface)
681		free(iface);
682
683	if (prefix)
684		free(prefix);
685
686	if (route)
687		free(route);
688
689	if (rdnss)
690		free(rdnss);
691}
692
693static void
694yyerror(char *msg)
695{
696	cleanup();
697	flog(LOG_ERR, "%s in %s, line %d: %s", msg, conf_file, num_lines, yytext);
698}
699