3 * Configuration file parser for mrouted.
5 * Written by Bill Fenner, NRL, 1994
8 * cfparse.y,v 3.8.4.30 1998/03/01 01:48:58 fenner Exp
21 * Local function declarations
23 static void fatal __P((char *fmt, ...)) __printflike(1, 2);
24 static void warn __P((char *fmt, ...)) __printflike(1, 2);
25 static void yyerror __P((char *s));
26 static char * next_word __P((void));
27 static int yylex __P((void));
28 static u_int32 valid_if __P((char *s));
29 static const char * ifconfaddr(u_int32_t a);
30 int yyparse __P((void));
34 char *configfilename = _PATH_MROUTED_CONF;
36 extern int cache_lifetime;
37 extern int prune_lifetime;
39 /* imported from config.c, with slight memory leak */
40 extern struct ifconf ifc;
42 int allow_black_holes = 0;
46 static struct uvif *v;
48 static int order, state;
49 static int noflood = 0;
50 static int rexmit = VIFF_REXMIT_PRUNES;
59 struct addrmask bound;
64 struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
65 int numbounds = 0; /* Number of named boundaries */
73 struct addrmask addrmask;
75 struct vf_element *filterelem;
78 %token CACHE_LIFETIME PRUNE_LIFETIME PRUNING BLACK_HOLE NOFLOOD
79 %token PHYINT TUNNEL NAME
80 %token DISABLE IGMPV1 SRCRT BESIDE
81 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC
82 %token FILTER ACCEPT DENY EXACT BIDIR REXMIT_PRUNES REXMIT_PRUNES2
83 %token PASSIVE ALLOW_NONPRUNERS
84 %token NOTRANSIT BLASTER FORCE_LEAF
85 %token PRUNE_LIFETIME2 NOFLOOD2
86 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
90 %token <addrmask> ADDRMASK
93 %type <addr> interface addrname
94 %type <addrmask> bound boundary addrmask
95 %type <filterelem> filter filtlist filtelement filtelem
116 fatal("phyints must appear before tunnels");
118 for (vifi = 0, v = uvifs;
121 if (!(v->uv_flags & VIFF_TUNNEL) &&
122 $2 == v->uv_lcl_addr)
126 fatal("%s is not a configured interface",
131 | TUNNEL interface addrname {
138 ifname = ifconfaddr($2);
140 fatal("Tunnel local address %s is not mine",
143 if (((ntohl($2) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) ==
145 fatal("Tunnel local address %s is a loopback address",
148 if (ifconfaddr($3) != 0)
149 fatal("Tunnel remote address %s is one of mine",
152 for (vifi = 0, v = uvifs;
155 if (v->uv_flags & VIFF_TUNNEL) {
156 if ($3 == v->uv_rmt_addr)
157 fatal("Duplicate tunnel to %s",
159 } else if (!(v->uv_flags & VIFF_DISABLED)) {
160 if (($3 & v->uv_subnetmask) == v->uv_subnet)
161 fatal("Unnecessary tunnel to %s, same subnet as vif %d (%s)",
162 inet_fmt($3,s1), vifi, v->uv_name);
165 if (numvifs == MAXVIFS)
166 fatal("too many vifs");
168 strlcpy(ffr.ifr_name, ifname, sizeof(ffr.ifr_name));
169 if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
170 fatal("ioctl SIOCGIFFLAGS on %s", ffr.ifr_name);
174 v->uv_flags = VIFF_TUNNEL | rexmit | noflood;
175 v->uv_flags |= VIFF_OTUNNEL; /*XXX*/
179 strlcpy(v->uv_name, ffr.ifr_name, sizeof(v->uv_name));
181 if (!(ffr.ifr_flags & IFF_UP)) {
182 v->uv_flags |= VIFF_DOWN;
189 if (!(v->uv_flags & VIFF_OTUNNEL)) {
194 "installing tunnel from %s to %s as vif #%u - rate=%d",
195 inet_fmt($2, s1), inet_fmt($3, s2),
196 numvifs, v->uv_rate_limit);
201 | CACHE_LIFETIME NUMBER {
203 if ($2 < MIN_CACHE_LIFETIME) {
204 warn("cache_lifetime %d must be at least %d",
205 $2, MIN_CACHE_LIFETIME);
211 | PRUNE_LIFETIME NUMBER {
213 if ($2 < MIN_PRUNE_LIFETIME) {
214 warn("prune_lifetime %d must be at least %d",
215 $2, MIN_PRUNE_LIFETIME);
224 warn("Disabling pruning is no longer supported");
229 #ifdef ALLOW_BLACK_HOLES
230 allow_black_holes = 1;
234 * Turn off initial flooding (until subordinateness is learned
235 * via route exchange) on all phyints and set the default for
236 * all further tunnels.
242 noflood = VIFF_NOFLOOD;
243 for (vifi = 0, v = uvifs;
246 v->uv_flags |= VIFF_NOFLOOD;
250 * Turn on prune retransmission on all interfaces.
251 * Tunnels default to retransmitting, so this just
252 * needs to turn on phyints.
258 for (vifi = 0, v = uvifs;
261 v->uv_flags |= VIFF_REXMIT_PRUNES;
265 * If true, do as above. If false, no need to turn
266 * it off for phyints since they default to not
267 * rexmit; need to set flag to not rexmit on tunnels.
269 | REXMIT_PRUNES BOOLEAN {
274 for (vifi = 0, v = uvifs;
277 v->uv_flags |= VIFF_REXMIT_PRUNES;
283 | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
284 fatal("Too many named boundaries (max %d)", MAXBOUNDS);
287 boundlist[numbounds].name = malloc(strlen($2) + 1);
288 strcpy(boundlist[numbounds].name, $2);
289 boundlist[numbounds++].bound = $3;
296 | SYSCONTACT STRING {
301 | SYSVERSION STRING {
306 | SYSLOCATION STRING {
313 tunnelmods : /* empty */
314 | tunnelmods tunnelmod
318 | BESIDE { v->uv_flags |= VIFF_OTUNNEL; }
322 v->uv_flags |= VIFF_OTUNNEL;
324 v->uv_flags &= ~VIFF_OTUNNEL;
328 | SRCRT { fatal("Source-route tunnels not supported"); }
336 | DISABLE { v->uv_flags |= VIFF_DISABLED; }
337 | IGMPV1 { v->uv_flags |= VIFF_IGMPV1; }
339 u_int32 subnet, mask;
342 subnet = v->uv_lcl_addr & mask;
343 if (!inet_valid_subnet(subnet, mask))
344 fatal("Invalid netmask");
345 v->uv_subnet = subnet;
346 v->uv_subnetmask = mask;
347 v->uv_subnetbcast = subnet | ~mask;
351 warn("Expected address after netmask keyword, ignored");
358 ph = (struct phaddr *)malloc(sizeof(struct phaddr));
360 fatal("out of memory");
362 VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
364 ph->pa_subnetmask = v->uv_subnetmask;
365 ph->pa_subnet = $2.addr & ph->pa_subnetmask;
366 ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
367 if ($2.addr & ~ph->pa_subnetmask)
368 warn("Extra subnet %s/%d has host bits set",
369 inet_fmt($2.addr,s1), $2.mask);
370 ph->pa_next = v->uv_addrs;
376 warn("Expected address after altnet keyword, ignored");
381 v->uv_flags |= VIFF_FORCE_LEAF;
384 | FORCE_LEAF BOOLEAN {
387 v->uv_flags |= VIFF_FORCE_LEAF;
389 v->uv_flags &= ~VIFF_FORCE_LEAF;
395 mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
396 fatal("Invalid threshold %d",$2);
397 v->uv_threshold = $2;
401 warn("Expected number after threshold keyword, ignored");
404 | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
405 fatal("Invalid metric %d",$2);
410 warn("Expected number after metric keyword, ignored");
413 | ADVERT_METRIC NUMBER { if ($2 < 0 || $2 > UNREACHABLE - 1)
414 fatal("Invalid advert_metric %d", $2);
419 warn("Expected number after advert_metric keyword, ignored");
422 | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
423 fatal("Invalid rate_limit %d",$2);
424 v->uv_rate_limit = $2;
428 warn("Expected number after rate_limit keyword, ignored");
433 struct vif_acl *v_acl;
435 v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
437 fatal("out of memory");
438 VAL_TO_MASK(v_acl->acl_mask, $2.mask);
439 v_acl->acl_addr = $2.addr & v_acl->acl_mask;
440 if ($2.addr & ~v_acl->acl_mask)
441 warn("Boundary spec %s/%d has host bits set",
442 inet_fmt($2.addr,s1),$2.mask);
443 v_acl->acl_next = v->uv_acl;
449 warn("Expected boundary spec after boundary keyword, ignored");
454 v->uv_flags |= VIFF_REXMIT_PRUNES;
457 | REXMIT_PRUNES2 BOOLEAN {
460 v->uv_flags |= VIFF_REXMIT_PRUNES;
462 v->uv_flags &= ~VIFF_REXMIT_PRUNES;
468 v->uv_flags |= VIFF_PASSIVE;
473 v->uv_flags |= VIFF_NOFLOOD;
478 v->uv_flags |= VIFF_NOTRANSIT;
483 v->uv_flags |= VIFF_BLASTER;
484 blaster_alloc(v - uvifs);
489 v->uv_flags |= VIFF_ALLOW_NONPRUNERS;
492 | PRUNE_LIFETIME2 NUMBER {
494 if ($2 < MIN_PRUNE_LIFETIME) {
495 warn("prune_lifetime %d must be at least %d",
496 $2, MIN_PRUNE_LIFETIME);
498 v->uv_prune_lifetime = $2;
504 if (v->uv_filter == NULL) {
505 struct vif_filter *v_filter;
507 v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter));
508 if (v_filter == NULL)
509 fatal("out of memory");
510 v_filter->vf_flags = 0;
511 v_filter->vf_type = VFT_ACCEPT;
512 v_filter->vf_filter = $2;
513 v->uv_filter = v_filter;
514 } else if (v->uv_filter->vf_type != VFT_ACCEPT) {
515 fatal("can't accept and deny");
517 struct vf_element *p;
519 p = v->uv_filter->vf_filter;
528 warn("Expected filter spec after accept keyword, ignored");
533 if (v->uv_filter == NULL) {
534 struct vif_filter *v_filter;
536 v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter));
537 if (v_filter == NULL)
538 fatal("out of memory");
539 v_filter->vf_flags = 0;
540 v_filter->vf_type = VFT_DENY;
541 v_filter->vf_filter = $2;
542 v->uv_filter = v_filter;
543 } else if (v->uv_filter->vf_type != VFT_DENY) {
544 fatal("can't accept and deny");
546 struct vf_element *p;
548 p = v->uv_filter->vf_filter;
557 warn("Expected filter spec after deny keyword, ignored");
562 if (v->uv_filter == NULL) {
563 fatal("bidir goes after filters");
565 v->uv_filter->vf_flags |= VFF_BIDIR;
570 interface : ADDR { $$ = $1; }
574 fatal("Invalid interface name %s",$1);
578 addrname : ADDR { $$ = $1; }
579 | STRING { struct hostent *hp;
581 if ((hp = gethostbyname($1)) == NULL ||
582 hp->h_length != sizeof($$))
583 fatal("No such host %s", $1);
585 if (hp->h_addr_list[1])
586 fatal("Hostname %s does not %s",
587 $1, "map to a unique address");
589 bcopy(hp->h_addr_list[0], &$$,
593 bound : boundary { $$ = $1; }
596 for (i=0; i < numbounds; i++) {
597 if (!strcmp(boundlist[i].name, $1)) {
598 $$ = boundlist[i].bound;
602 if (i == numbounds) {
603 fatal("Invalid boundary name %s",$1);
608 boundary : ADDRMASK {
610 #ifdef ALLOW_BLACK_HOLES
611 if (!allow_black_holes)
613 if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
614 fatal("Boundaries must be 239.x.x.x, not %s/%d",
615 inet_fmt($1.addr, s1), $1.mask);
622 addrmask : ADDRMASK { $$ = $1; }
623 | ADDR { $$.addr = $1; $$.mask = 0; }
626 filter : filtlist { $$ = $1; }
627 | STRING { fatal("named filters no implemented yet"); }
630 filtlist : filtelement { $$ = $1; }
631 | filtelement filtlist { $1->vfe_next = $2; $$ = $1; }
634 filtelement : filtelem { $$ = $1; }
635 | filtelem EXACT { $1->vfe_flags |= VFEF_EXACT; $$ = $1; }
638 filtelem : ADDRMASK {
640 struct vf_element *vfe;
642 vfe = (struct vf_element *)malloc(sizeof(struct vf_element));
644 fatal("out of memory");
646 vfe->vfe_addr = $1.addr;
647 VAL_TO_MASK(vfe->vfe_mask, $1.mask);
649 vfe->vfe_next = NULL;
657 fatal(char *fmt, ...)
660 char buf[MAXHOSTNAMELEN + 100];
671 char buf[MAXHOSTNAMELEN + 100];
675 vsnprintf(buf, sizeof(buf), fmt, ap);
678 log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
701 vsnprintf(buf, sizeof(buf), fmt, ap);
704 log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
711 log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
717 static char buf[1024];
724 if (fgets(buf, sizeof(buf), f) == NULL)
728 while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
731 p = NULL; /* skip comments */
738 while (*p && *p != '"' && *p != '\n')
739 p++; /* find next whitespace */
744 while (*p && *p != ' ' && *p != '\t' && *p != '\n')
745 p++; /* find next whitespace */
746 *p++ = '\0'; /* null-terminate string */
750 continue; /* if 0-length string, read another line */
758 * List of keywords. Must have an empty record at the end to terminate
759 * list. If a second value is specified, the first is used at the beginning
760 * of the file and the second is used while parsing interfaces (e.g. after
761 * the first "phyint" or "tunnel" keyword).
763 static struct keyword {
768 { "cache_lifetime", CACHE_LIFETIME },
769 { "prune_lifetime", PRUNE_LIFETIME, PRUNE_LIFETIME2 },
770 { "pruning", PRUNING },
771 { "phyint", PHYINT },
772 { "tunnel", TUNNEL },
773 { "disable", DISABLE },
774 { "metric", METRIC },
775 { "advert_metric", ADVERT_METRIC },
776 { "threshold", THRESHOLD },
777 { "rate_limit", RATE_LIMIT },
778 { "force_leaf", FORCE_LEAF },
780 { "sourceroute", SRCRT },
781 { "boundary", BOUNDARY },
782 { "netmask", NETMASK },
783 { "igmpv1", IGMPV1 },
784 { "altnet", ALTNET },
786 { "accept", ACCEPT },
790 { "allow_nonpruners", ALLOW_NONPRUNERS },
791 #ifdef ALLOW_BLACK_HOLES
792 { "allow_black_holes", BLACK_HOLE },
794 { "noflood", NOFLOOD, NOFLOOD2},
795 { "notransit", NOTRANSIT },
796 { "blaster", BLASTER },
797 { "rexmit_prunes", REXMIT_PRUNES, REXMIT_PRUNES2 },
798 { "passive", PASSIVE },
799 { "beside", BESIDE },
801 { "sysName", SYSNAM },
802 { "sysContact", SYSCONTACT },
803 { "sysVersion", SYSVERSION },
804 { "sysLocation", SYSLOCATION },
818 if ((q = next_word()) == NULL) {
822 for (w = words; w->word; w++)
823 if (!strcmp(q, w->word))
824 return (state && w->val2) ? w->val2 : w->val1;
826 if (!strcmp(q,"on") || !strcmp(q,"yes")) {
830 if (!strcmp(q,"off") || !strcmp(q,"no")) {
834 if (!strcmp(q,"default")) {
835 yylval.addrmask.mask = 0;
836 yylval.addrmask.addr = 0;
839 if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
840 if ((addr = inet_parse(s1,1)) != 0xffffffff) {
841 yylval.addrmask.mask = n;
842 yylval.addrmask.addr = addr;
845 /* fall through to returning STRING */
847 if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
848 if ((addr = inet_parse(s1,4)) != 0xffffffff &&
849 inet_valid_host(addr)) {
854 if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
858 if (sscanf(q,"%d%c",&n,s1) == 1) {
864 if (q[ strlen(q)-1 ]=='"')
865 q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
875 config_vifs_from_file()
882 if ((f = fopen(configfilename, "r")) == NULL) {
884 log(LOG_ERR, errno, "can't open %s", configfilename);
897 register vifi_t vifi;
898 register struct uvif *v;
900 for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
901 if (!strcmp(v->uv_name, s))
902 return v->uv_lcl_addr;
908 ifconfaddr(u_int32_t a)
910 static char ifname[IFNAMSIZ];
911 struct ifaddrs *ifap, *ifa;
913 if (getifaddrs(&ifap) != 0)
916 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
917 if (ifa->ifa_addr->sa_family == AF_INET &&
918 ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == a) {
919 strlcpy(ifname, ifa->ifa_name, sizeof(ifname));