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
20 * Local function declarations
22 static void fatal __P((char *fmt, ...)) __printflike(1, 2);
23 static void warn __P((char *fmt, ...)) __printflike(1, 2);;
24 static void yyerror __P((char *s));
25 static char * next_word __P((void));
26 static int yylex __P((void));
27 static u_int32 valid_if __P((char *s));
28 static struct ifreq * ifconfaddr __P((struct ifconf *ifcp, u_int32 a));
29 int yyparse __P((void));
33 char *configfilename = _PATH_MROUTED_CONF;
35 extern int cache_lifetime;
36 extern int prune_lifetime;
38 /* imported from config.c, with slight memory leak */
39 extern struct ifconf ifc;
41 int allow_black_holes = 0;
45 static struct uvif *v;
47 static int order, state;
48 static int noflood = 0;
49 static int rexmit = VIFF_REXMIT_PRUNES;
58 struct addrmask bound;
63 struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
64 int numbounds = 0; /* Number of named boundaries */
72 struct addrmask addrmask;
74 struct vf_element *filterelem;
77 %token CACHE_LIFETIME PRUNE_LIFETIME PRUNING BLACK_HOLE NOFLOOD
78 %token PHYINT TUNNEL NAME
79 %token DISABLE IGMPV1 SRCRT BESIDE
80 %token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC
81 %token FILTER ACCEPT DENY EXACT BIDIR REXMIT_PRUNES REXMIT_PRUNES2
82 %token PASSIVE ALLOW_NONPRUNERS
83 %token NOTRANSIT BLASTER FORCE_LEAF
84 %token PRUNE_LIFETIME2 NOFLOOD2
85 %token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
89 %token <addrmask> ADDRMASK
92 %type <addr> interface addrname
93 %type <addrmask> bound boundary addrmask
94 %type <filterelem> filter filtlist filtelement filtelem
115 fatal("phyints must appear before tunnels");
117 for (vifi = 0, v = uvifs;
120 if (!(v->uv_flags & VIFF_TUNNEL) &&
121 $2 == v->uv_lcl_addr)
125 fatal("%s is not a configured interface",
130 | TUNNEL interface addrname {
138 ifr = ifconfaddr(&ifc, $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(&ifc, $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 strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
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 strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
180 v->uv_name[IFNAMSIZ-1]='\0';
182 if (!(ffr.ifr_flags & IFF_UP)) {
183 v->uv_flags |= VIFF_DOWN;
190 if (!(v->uv_flags & VIFF_OTUNNEL)) {
195 "installing tunnel from %s to %s as vif #%u - rate=%d",
196 inet_fmt($2, s1), inet_fmt($3, s2),
197 numvifs, v->uv_rate_limit);
202 | CACHE_LIFETIME NUMBER {
204 if ($2 < MIN_CACHE_LIFETIME) {
205 warn("cache_lifetime %d must be at least %d",
206 $2, MIN_CACHE_LIFETIME);
212 | PRUNE_LIFETIME NUMBER {
214 if ($2 < MIN_PRUNE_LIFETIME) {
215 warn("prune_lifetime %d must be at least %d",
216 $2, MIN_PRUNE_LIFETIME);
225 warn("Disabling pruning is no longer supported");
230 #ifdef ALLOW_BLACK_HOLES
231 allow_black_holes = 1;
235 * Turn off initial flooding (until subordinateness is learned
236 * via route exchange) on all phyints and set the default for
237 * all further tunnels.
243 noflood = VIFF_NOFLOOD;
244 for (vifi = 0, v = uvifs;
247 v->uv_flags |= VIFF_NOFLOOD;
251 * Turn on prune retransmission on all interfaces.
252 * Tunnels default to retransmitting, so this just
253 * needs to turn on phyints.
259 for (vifi = 0, v = uvifs;
262 v->uv_flags |= VIFF_REXMIT_PRUNES;
266 * If true, do as above. If false, no need to turn
267 * it off for phyints since they default to not
268 * rexmit; need to set flag to not rexmit on tunnels.
270 | REXMIT_PRUNES BOOLEAN {
275 for (vifi = 0, v = uvifs;
278 v->uv_flags |= VIFF_REXMIT_PRUNES;
284 | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
285 fatal("Too many named boundaries (max %d)", MAXBOUNDS);
288 boundlist[numbounds].name = malloc(strlen($2) + 1);
289 strcpy(boundlist[numbounds].name, $2);
290 boundlist[numbounds++].bound = $3;
297 | SYSCONTACT STRING {
302 | SYSVERSION STRING {
307 | SYSLOCATION STRING {
314 tunnelmods : /* empty */
315 | tunnelmods tunnelmod
319 | BESIDE { v->uv_flags |= VIFF_OTUNNEL; }
323 v->uv_flags |= VIFF_OTUNNEL;
325 v->uv_flags &= ~VIFF_OTUNNEL;
329 | SRCRT { fatal("Source-route tunnels not supported"); }
337 | DISABLE { v->uv_flags |= VIFF_DISABLED; }
338 | IGMPV1 { v->uv_flags |= VIFF_IGMPV1; }
340 u_int32 subnet, mask;
343 subnet = v->uv_lcl_addr & mask;
344 if (!inet_valid_subnet(subnet, mask))
345 fatal("Invalid netmask");
346 v->uv_subnet = subnet;
347 v->uv_subnetmask = mask;
348 v->uv_subnetbcast = subnet | ~mask;
352 warn("Expected address after netmask keyword, ignored");
359 ph = (struct phaddr *)malloc(sizeof(struct phaddr));
361 fatal("out of memory");
363 VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
365 ph->pa_subnetmask = v->uv_subnetmask;
366 ph->pa_subnet = $2.addr & ph->pa_subnetmask;
367 ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
368 if ($2.addr & ~ph->pa_subnetmask)
369 warn("Extra subnet %s/%d has host bits set",
370 inet_fmt($2.addr,s1), $2.mask);
371 ph->pa_next = v->uv_addrs;
377 warn("Expected address after altnet keyword, ignored");
382 v->uv_flags |= VIFF_FORCE_LEAF;
385 | FORCE_LEAF BOOLEAN {
388 v->uv_flags |= VIFF_FORCE_LEAF;
390 v->uv_flags &= ~VIFF_FORCE_LEAF;
396 mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
397 fatal("Invalid threshold %d",$2);
398 v->uv_threshold = $2;
402 warn("Expected number after threshold keyword, ignored");
405 | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
406 fatal("Invalid metric %d",$2);
411 warn("Expected number after metric keyword, ignored");
414 | ADVERT_METRIC NUMBER { if ($2 < 0 || $2 > UNREACHABLE - 1)
415 fatal("Invalid advert_metric %d", $2);
420 warn("Expected number after advert_metric keyword, ignored");
423 | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
424 fatal("Invalid rate_limit %d",$2);
425 v->uv_rate_limit = $2;
429 warn("Expected number after rate_limit keyword, ignored");
434 struct vif_acl *v_acl;
436 v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
438 fatal("out of memory");
439 VAL_TO_MASK(v_acl->acl_mask, $2.mask);
440 v_acl->acl_addr = $2.addr & v_acl->acl_mask;
441 if ($2.addr & ~v_acl->acl_mask)
442 warn("Boundary spec %s/%d has host bits set",
443 inet_fmt($2.addr,s1),$2.mask);
444 v_acl->acl_next = v->uv_acl;
450 warn("Expected boundary spec after boundary keyword, ignored");
455 v->uv_flags |= VIFF_REXMIT_PRUNES;
458 | REXMIT_PRUNES2 BOOLEAN {
461 v->uv_flags |= VIFF_REXMIT_PRUNES;
463 v->uv_flags &= ~VIFF_REXMIT_PRUNES;
469 v->uv_flags |= VIFF_PASSIVE;
474 v->uv_flags |= VIFF_NOFLOOD;
479 v->uv_flags |= VIFF_NOTRANSIT;
484 v->uv_flags |= VIFF_BLASTER;
485 blaster_alloc(v - uvifs);
490 v->uv_flags |= VIFF_ALLOW_NONPRUNERS;
493 | PRUNE_LIFETIME2 NUMBER {
495 if ($2 < MIN_PRUNE_LIFETIME) {
496 warn("prune_lifetime %d must be at least %d",
497 $2, MIN_PRUNE_LIFETIME);
499 v->uv_prune_lifetime = $2;
505 if (v->uv_filter == NULL) {
506 struct vif_filter *v_filter;
508 v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter));
509 if (v_filter == NULL)
510 fatal("out of memory");
511 v_filter->vf_flags = 0;
512 v_filter->vf_type = VFT_ACCEPT;
513 v_filter->vf_filter = $2;
514 v->uv_filter = v_filter;
515 } else if (v->uv_filter->vf_type != VFT_ACCEPT) {
516 fatal("can't accept and deny");
518 struct vf_element *p;
520 p = v->uv_filter->vf_filter;
529 warn("Expected filter spec after accept keyword, ignored");
534 if (v->uv_filter == NULL) {
535 struct vif_filter *v_filter;
537 v_filter = (struct vif_filter *)malloc(sizeof(struct vif_filter));
538 if (v_filter == NULL)
539 fatal("out of memory");
540 v_filter->vf_flags = 0;
541 v_filter->vf_type = VFT_DENY;
542 v_filter->vf_filter = $2;
543 v->uv_filter = v_filter;
544 } else if (v->uv_filter->vf_type != VFT_DENY) {
545 fatal("can't accept and deny");
547 struct vf_element *p;
549 p = v->uv_filter->vf_filter;
558 warn("Expected filter spec after deny keyword, ignored");
563 if (v->uv_filter == NULL) {
564 fatal("bidir goes after filters");
566 v->uv_filter->vf_flags |= VFF_BIDIR;
571 interface : ADDR { $$ = $1; }
575 fatal("Invalid interface name %s",$1);
579 addrname : ADDR { $$ = $1; }
580 | STRING { struct hostent *hp;
582 if ((hp = gethostbyname($1)) == NULL ||
583 hp->h_length != sizeof($$))
584 fatal("No such host %s", $1);
586 if (hp->h_addr_list[1])
587 fatal("Hostname %s does not %s",
588 $1, "map to a unique address");
590 bcopy(hp->h_addr_list[0], &$$,
594 bound : boundary { $$ = $1; }
597 for (i=0; i < numbounds; i++) {
598 if (!strcmp(boundlist[i].name, $1)) {
599 $$ = boundlist[i].bound;
603 if (i == numbounds) {
604 fatal("Invalid boundary name %s",$1);
609 boundary : ADDRMASK {
611 #ifdef ALLOW_BLACK_HOLES
612 if (!allow_black_holes)
614 if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
615 fatal("Boundaries must be 239.x.x.x, not %s/%d",
616 inet_fmt($1.addr, s1), $1.mask);
623 addrmask : ADDRMASK { $$ = $1; }
624 | ADDR { $$.addr = $1; $$.mask = 0; }
627 filter : filtlist { $$ = $1; }
628 | STRING { fatal("named filters no implemented yet"); }
631 filtlist : filtelement { $$ = $1; }
632 | filtelement filtlist { $1->vfe_next = $2; $$ = $1; }
635 filtelement : filtelem { $$ = $1; }
636 | filtelem EXACT { $1->vfe_flags |= VFEF_EXACT; $$ = $1; }
639 filtelem : ADDRMASK {
641 struct vf_element *vfe;
643 vfe = (struct vf_element *)malloc(sizeof(struct vf_element));
645 fatal("out of memory");
647 vfe->vfe_addr = $1.addr;
648 VAL_TO_MASK(vfe->vfe_mask, $1.mask);
650 vfe->vfe_next = NULL;
658 fatal(char *fmt, ...)
661 char buf[MAXHOSTNAMELEN + 100];
672 char buf[MAXHOSTNAMELEN + 100];
676 vsnprintf(buf, sizeof(buf), fmt, ap);
679 log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
702 vsnprintf(buf, sizeof(buf), fmt, ap);
705 log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
712 log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
718 static char buf[1024];
725 if (fgets(buf, sizeof(buf), f) == NULL)
729 while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
732 p = NULL; /* skip comments */
739 while (*p && *p != '"' && *p != '\n')
740 p++; /* find next whitespace */
745 while (*p && *p != ' ' && *p != '\t' && *p != '\n')
746 p++; /* find next whitespace */
747 *p++ = '\0'; /* null-terminate string */
751 continue; /* if 0-length string, read another line */
759 * List of keywords. Must have an empty record at the end to terminate
760 * list. If a second value is specified, the first is used at the beginning
761 * of the file and the second is used while parsing interfaces (e.g. after
762 * the first "phyint" or "tunnel" keyword).
764 static struct keyword {
769 { "cache_lifetime", CACHE_LIFETIME },
770 { "prune_lifetime", PRUNE_LIFETIME, PRUNE_LIFETIME2 },
771 { "pruning", PRUNING },
772 { "phyint", PHYINT },
773 { "tunnel", TUNNEL },
774 { "disable", DISABLE },
775 { "metric", METRIC },
776 { "advert_metric", ADVERT_METRIC },
777 { "threshold", THRESHOLD },
778 { "rate_limit", RATE_LIMIT },
779 { "force_leaf", FORCE_LEAF },
781 { "sourceroute", SRCRT },
782 { "boundary", BOUNDARY },
783 { "netmask", NETMASK },
784 { "igmpv1", IGMPV1 },
785 { "altnet", ALTNET },
787 { "accept", ACCEPT },
791 { "allow_nonpruners", ALLOW_NONPRUNERS },
792 #ifdef ALLOW_BLACK_HOLES
793 { "allow_black_holes", BLACK_HOLE },
795 { "noflood", NOFLOOD, NOFLOOD2},
796 { "notransit", NOTRANSIT },
797 { "blaster", BLASTER },
798 { "rexmit_prunes", REXMIT_PRUNES, REXMIT_PRUNES2 },
799 { "passive", PASSIVE },
800 { "beside", BESIDE },
802 { "sysName", SYSNAM },
803 { "sysContact", SYSCONTACT },
804 { "sysVersion", SYSVERSION },
805 { "sysLocation", SYSLOCATION },
819 if ((q = next_word()) == NULL) {
823 for (w = words; w->word; w++)
824 if (!strcmp(q, w->word))
825 return (state && w->val2) ? w->val2 : w->val1;
827 if (!strcmp(q,"on") || !strcmp(q,"yes")) {
831 if (!strcmp(q,"off") || !strcmp(q,"no")) {
835 if (!strcmp(q,"default")) {
836 yylval.addrmask.mask = 0;
837 yylval.addrmask.addr = 0;
840 if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
841 if ((addr = inet_parse(s1,1)) != 0xffffffff) {
842 yylval.addrmask.mask = n;
843 yylval.addrmask.addr = addr;
846 /* fall through to returning STRING */
848 if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
849 if ((addr = inet_parse(s1,4)) != 0xffffffff &&
850 inet_valid_host(addr)) {
855 if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
859 if (sscanf(q,"%d%c",&n,s1) == 1) {
865 if (q[ strlen(q)-1 ]=='"')
866 q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
876 config_vifs_from_file()
883 if ((f = fopen(configfilename, "r")) == NULL) {
885 log(LOG_ERR, errno, "can't open %s", configfilename);
898 register vifi_t vifi;
899 register struct uvif *v;
901 for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
902 if (!strcmp(v->uv_name, s))
903 return v->uv_lcl_addr;
908 static struct ifreq *
914 struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
915 struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
917 while (ifrp < ifend) {
918 if (ifrp->ifr_addr.sa_family == AF_INET &&
919 ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
922 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
923 if (n < sizeof(*ifrp))
926 ifrp = (struct ifreq *)((char *)ifrp + n);