/* * $Id$ * * Authors: * Pedro Roque * Lars Fenneberg * * This software is Copyright 1996-2000 by the above mentioned author(s), * All Rights Reserved. * * The license which is distributed with this software in the file COPYRIGHT * applies to this software. If your distribution is missing this file, you * may request it from . * */ %{ #include #include #include #include extern struct Interface *IfaceList; struct Interface *iface = NULL; struct AdvPrefix *prefix = NULL; struct AdvRoute *route = NULL; struct AdvRDNSS *rdnss = NULL; extern char *conf_file; extern int num_lines; extern char *yytext; extern int sock; static void cleanup(void); static void yyerror(char *msg); #if 0 /* no longer necessary? */ #ifndef HAVE_IN6_ADDR_S6_ADDR # ifdef __FreeBSD__ # define s6_addr32 __u6_addr.__u6_addr32 # define s6_addr16 __u6_addr.__u6_addr16 # endif #endif #endif #define ABORT do { cleanup(); YYABORT; } while (0); %} %token T_INTERFACE %token T_PREFIX %token T_ROUTE %token T_RDNSS %token STRING %token NUMBER %token SIGNEDNUMBER %token DECIMAL %token SWITCH %token IPV6ADDR %token INFINITY %token T_IgnoreIfMissing %token T_AdvSendAdvert %token T_MaxRtrAdvInterval %token T_MinRtrAdvInterval %token T_MinDelayBetweenRAs %token T_AdvManagedFlag %token T_AdvOtherConfigFlag %token T_AdvLinkMTU %token T_AdvReachableTime %token T_AdvRetransTimer %token T_AdvCurHopLimit %token T_AdvDefaultLifetime %token T_AdvDefaultPreference %token T_AdvSourceLLAddress %token T_AdvOnLink %token T_AdvAutonomous %token T_AdvValidLifetime %token T_AdvPreferredLifetime %token T_AdvRouterAddr %token T_AdvHomeAgentFlag %token T_AdvIntervalOpt %token T_AdvHomeAgentInfo %token T_Base6to4Interface %token T_UnicastOnly %token T_HomeAgentPreference %token T_HomeAgentLifetime %token T_AdvRoutePreference %token T_AdvRouteLifetime %token T_AdvRDNSSPreference %token T_AdvRDNSSOpenFlag %token T_AdvRDNSSLifetime %token T_AdvMobRtrSupportFlag %token T_BAD_TOKEN %type name %type optional_prefixlist prefixdef prefixlist %type optional_routelist routedef routelist %type optional_rdnsslist rdnssdef rdnsslist %type number_or_infinity %union { unsigned int num; int snum; double dec; int bool; struct in6_addr *addr; char *str; struct AdvPrefix *pinfo; struct AdvRoute *rinfo; struct AdvRDNSS *rdnssinfo; }; %% grammar : grammar ifacedef | ifacedef ; ifacedef : ifacehead '{' ifaceparams '}' ';' { struct Interface *iface2; iface2 = IfaceList; while (iface2) { if (!strcmp(iface2->Name, iface->Name)) { flog(LOG_ERR, "duplicate interface " "definition for %s", iface->Name); ABORT; } iface2 = iface2->next; } if (check_device(sock, iface) < 0) { if (iface->IgnoreIfMissing) { dlog(LOG_DEBUG, 4, "interface %s did not exist, ignoring the interface", iface->Name); goto skip_interface; } else { flog(LOG_ERR, "interface %s does not exist", iface->Name); ABORT; } } if (setup_deviceinfo(sock, iface) < 0) ABORT; if (check_iface(iface) < 0) ABORT; if (setup_linklocal_addr(sock, iface) < 0) ABORT; if (setup_allrouters_membership(sock, iface) < 0) ABORT; iface->next = IfaceList; IfaceList = iface; dlog(LOG_DEBUG, 4, "interface definition for %s is ok", iface->Name); skip_interface: iface = NULL; }; ifacehead : T_INTERFACE name { iface = malloc(sizeof(struct Interface)); if (iface == NULL) { flog(LOG_CRIT, "malloc failed: %s", strerror(errno)); ABORT; } iface_init_defaults(iface); strncpy(iface->Name, $2, IFNAMSIZ-1); iface->Name[IFNAMSIZ-1] = '\0'; } ; name : STRING { /* check vality */ $$ = $1; } ; ifaceparams : optional_ifacevlist optional_prefixlist optional_routelist optional_rdnsslist { iface->AdvPrefixList = $2; iface->AdvRouteList = $3; iface->AdvRDNSSList = $4; } ; optional_ifacevlist: /* empty */ | ifacevlist ; optional_prefixlist: /* empty */ { $$ = NULL; } | prefixlist ; optional_routelist: /* empty */ { $$ = NULL; } | routelist ; optional_rdnsslist: /* empty */ { $$ = NULL; } | rdnsslist ; ifacevlist : ifacevlist ifaceval | ifaceval ; ifaceval : T_MinRtrAdvInterval NUMBER ';' { iface->MinRtrAdvInterval = $2; } | T_MaxRtrAdvInterval NUMBER ';' { iface->MaxRtrAdvInterval = $2; } | T_MinDelayBetweenRAs NUMBER ';' { iface->MinDelayBetweenRAs = $2; } | T_MinRtrAdvInterval DECIMAL ';' { iface->MinRtrAdvInterval = $2; } | T_MaxRtrAdvInterval DECIMAL ';' { iface->MaxRtrAdvInterval = $2; } | T_MinDelayBetweenRAs DECIMAL ';' { iface->MinDelayBetweenRAs = $2; } | T_IgnoreIfMissing SWITCH ';' { iface->IgnoreIfMissing = $2; } | T_AdvSendAdvert SWITCH ';' { iface->AdvSendAdvert = $2; } | T_AdvManagedFlag SWITCH ';' { iface->AdvManagedFlag = $2; } | T_AdvOtherConfigFlag SWITCH ';' { iface->AdvOtherConfigFlag = $2; } | T_AdvLinkMTU NUMBER ';' { iface->AdvLinkMTU = $2; } | T_AdvReachableTime NUMBER ';' { iface->AdvReachableTime = $2; } | T_AdvRetransTimer NUMBER ';' { iface->AdvRetransTimer = $2; } | T_AdvDefaultLifetime NUMBER ';' { iface->AdvDefaultLifetime = $2; } | T_AdvDefaultPreference SIGNEDNUMBER ';' { iface->AdvDefaultPreference = $2; } | T_AdvCurHopLimit NUMBER ';' { iface->AdvCurHopLimit = $2; } | T_AdvSourceLLAddress SWITCH ';' { iface->AdvSourceLLAddress = $2; } | T_AdvIntervalOpt SWITCH ';' { iface->AdvIntervalOpt = $2; } | T_AdvHomeAgentInfo SWITCH ';' { iface->AdvHomeAgentInfo = $2; } | T_AdvHomeAgentFlag SWITCH ';' { iface->AdvHomeAgentFlag = $2; } | T_HomeAgentPreference NUMBER ';' { iface->HomeAgentPreference = $2; } | T_HomeAgentLifetime NUMBER ';' { iface->HomeAgentLifetime = $2; } | T_UnicastOnly SWITCH ';' { iface->UnicastOnly = $2; } | T_AdvMobRtrSupportFlag SWITCH ';' { iface->AdvMobRtrSupportFlag = $2; } ; prefixlist : prefixdef { $$ = $1; } | prefixlist prefixdef { $2->next = $1; $$ = $2; } ; prefixdef : prefixhead '{' optional_prefixplist '}' ';' { unsigned int dst; if (prefix->AdvPreferredLifetime > prefix->AdvValidLifetime) { flog(LOG_ERR, "AdvValidLifeTime must be " "greater than AdvPreferredLifetime in %s, line %d", conf_file, num_lines); ABORT; } if( prefix->if6to4[0] ) { if (get_v4addr(prefix->if6to4, &dst) < 0) { flog(LOG_ERR, "interface %s has no IPv4 addresses, disabling 6to4 prefix", prefix->if6to4 ); prefix->enabled = 0; } else { *((uint16_t *)(prefix->Prefix.s6_addr)) = htons(0x2002); memcpy( prefix->Prefix.s6_addr + 2, &dst, sizeof( dst ) ); } } $$ = prefix; prefix = NULL; } ; prefixhead : T_PREFIX IPV6ADDR '/' NUMBER { prefix = malloc(sizeof(struct AdvPrefix)); if (prefix == NULL) { flog(LOG_CRIT, "malloc failed: %s", strerror(errno)); ABORT; } prefix_init_defaults(prefix); if ($4 > MAX_PrefixLen) { flog(LOG_ERR, "invalid prefix length in %s, line %d", conf_file, num_lines); ABORT; } prefix->PrefixLen = $4; memcpy(&prefix->Prefix, $2, sizeof(struct in6_addr)); } ; optional_prefixplist: /* empty */ | prefixplist ; prefixplist : prefixplist prefixparms | prefixparms ; prefixparms : T_AdvOnLink SWITCH ';' { prefix->AdvOnLinkFlag = $2; } | T_AdvAutonomous SWITCH ';' { prefix->AdvAutonomousFlag = $2; } | T_AdvRouterAddr SWITCH ';' { prefix->AdvRouterAddr = $2; } | T_AdvValidLifetime number_or_infinity ';' { prefix->AdvValidLifetime = $2; } | T_AdvPreferredLifetime number_or_infinity ';' { prefix->AdvPreferredLifetime = $2; } | T_Base6to4Interface name ';' { dlog(LOG_DEBUG, 4, "using interface %s for 6to4", $2); strncpy(prefix->if6to4, $2, IFNAMSIZ-1); prefix->if6to4[IFNAMSIZ-1] = '\0'; } ; routelist : routedef { $$ = $1; } | routelist routedef { $2->next = $1; $$ = $2; } ; routedef : routehead '{' optional_routeplist '}' ';' { $$ = route; route = NULL; } ; routehead : T_ROUTE IPV6ADDR '/' NUMBER { route = malloc(sizeof(struct AdvRoute)); if (route == NULL) { flog(LOG_CRIT, "malloc failed: %s", strerror(errno)); ABORT; } route_init_defaults(route, iface); if ($4 > MAX_PrefixLen) { flog(LOG_ERR, "invalid route prefix length in %s, line %d", conf_file, num_lines); ABORT; } route->PrefixLen = $4; memcpy(&route->Prefix, $2, sizeof(struct in6_addr)); } ; optional_routeplist: /* empty */ | routeplist ; routeplist : routeplist routeparms | routeparms ; routeparms : T_AdvRoutePreference SIGNEDNUMBER ';' { route->AdvRoutePreference = $2; } | T_AdvRouteLifetime number_or_infinity ';' { route->AdvRouteLifetime = $2; } ; rdnsslist : rdnssdef { $$ = $1; } | rdnsslist rdnssdef { $2->next = $1; $$ = $2; } ; rdnssdef : rdnsshead '{' optional_rdnssplist '}' ';' { $$ = rdnss; rdnss = NULL; } ; rdnssaddrs : rdnssaddrs rdnssaddr | rdnssaddr ; rdnssaddr : IPV6ADDR { if (!rdnss) { /* first IP found */ rdnss = malloc(sizeof(struct AdvRDNSS)); if (rdnss == NULL) { flog(LOG_CRIT, "malloc failed: %s", strerror(errno)); ABORT; } rdnss_init_defaults(rdnss, iface); } switch (rdnss->AdvRDNSSNumber) { case 0: memcpy(&rdnss->AdvRDNSSAddr1, $1, sizeof(struct in6_addr)); rdnss->AdvRDNSSNumber++; break; case 1: memcpy(&rdnss->AdvRDNSSAddr2, $1, sizeof(struct in6_addr)); rdnss->AdvRDNSSNumber++; break; case 2: memcpy(&rdnss->AdvRDNSSAddr3, $1, sizeof(struct in6_addr)); rdnss->AdvRDNSSNumber++; break; default: flog(LOG_CRIT, "Too many addresses in RDNSS section"); ABORT; } } ; rdnsshead : T_RDNSS rdnssaddrs { if (!rdnss) { flog(LOG_CRIT, "No address specified in RDNSS section"); ABORT; } } ; optional_rdnssplist: /* empty */ | rdnssplist ; rdnssplist : rdnssplist rdnssparms | rdnssparms ; rdnssparms : T_AdvRDNSSPreference NUMBER ';' { rdnss->AdvRDNSSPreference = $2; } | T_AdvRDNSSOpenFlag SWITCH ';' { rdnss->AdvRDNSSOpenFlag = $2; } | T_AdvRDNSSLifetime number_or_infinity ';' { if ($2 < iface->MaxRtrAdvInterval && $2 != 0) { flog(LOG_ERR, "AdvRDNSSLifetime must be at least MaxRtrAdvInterval"); ABORT; } if ($2 > 2*(iface->MaxRtrAdvInterval)) flog(LOG_WARNING, "Warning: AdvRDNSSLifetime <= 2*MaxRtrAdvInterval would allow stale DNS servers to be deleted faster"); rdnss->AdvRDNSSLifetime = $2; } ; number_or_infinity : NUMBER { $$ = $1; } | INFINITY { $$ = (uint32_t)~0; } ; %% static void cleanup(void) { if (iface) free(iface); if (prefix) free(prefix); if (route) free(route); if (rdnss) free(rdnss); } static void yyerror(char *msg) { cleanup(); flog(LOG_ERR, "%s in %s, line %d: %s", msg, conf_file, num_lines, yytext); }