Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / mrouted / cfparse.y
1 %{
2 /*
3  * Configuration file parser for mrouted.
4  *
5  * Written by Bill Fenner, NRL, 1994
6  *
7  * $FreeBSD: src/usr.sbin/mrouted/cfparse.y,v 1.10.2.2 2001/07/19 01:41:11 kris Exp $
8  * cfparse.y,v 3.8.4.30 1998/03/01 01:48:58 fenner Exp
9  */
10 #include <stdio.h>
11 #ifdef __STDC__
12 #include <stdarg.h>
13 #else
14 #include <varargs.h>
15 #endif
16 #include "defs.h"
17 #include <netdb.h>
18
19 /*
20  * Local function declarations
21  */
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));
30
31 static FILE *f;
32
33 char *configfilename = _PATH_MROUTED_CONF;
34
35 extern int cache_lifetime;
36 extern int prune_lifetime;
37
38 /* imported from config.c, with slight memory leak */
39 extern struct ifconf ifc;
40
41 int allow_black_holes = 0;
42
43 static int lineno;
44
45 static struct uvif *v;
46
47 static int order, state;
48 static int noflood = 0;
49 static int rexmit = VIFF_REXMIT_PRUNES;
50
51 struct addrmask {
52         u_int32 addr;
53         int     mask;
54 };
55
56 struct boundnam {
57         char            *name;
58         struct addrmask  bound;
59 };
60
61 #define MAXBOUNDS 20
62
63 struct boundnam boundlist[MAXBOUNDS];   /* Max. of 20 named boundaries */
64 int numbounds = 0;                      /* Number of named boundaries */
65
66 %}
67
68 %union
69 {
70         int num;
71         char *ptr;
72         struct addrmask addrmask;
73         u_int32 addr;
74         struct vf_element *filterelem;
75 };
76
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
86 %token <num> BOOLEAN
87 %token <num> NUMBER
88 %token <ptr> STRING
89 %token <addrmask> ADDRMASK
90 %token <addr> ADDR
91
92 %type <addr> interface addrname
93 %type <addrmask> bound boundary addrmask
94 %type <filterelem> filter filtlist filtelement filtelem
95
96 %start conf
97
98 %%
99
100 conf    : stmts
101         ;
102
103 stmts   : /* Empty */
104         | stmts stmt
105         ;
106
107 stmt    : error
108         | PHYINT interface              {
109
110                         vifi_t vifi;
111
112                         state++;
113
114                         if (order)
115                             fatal("phyints must appear before tunnels");
116
117                         for (vifi = 0, v = uvifs;
118                              vifi < numvifs;
119                              ++vifi, ++v)
120                             if (!(v->uv_flags & VIFF_TUNNEL) &&
121                                 $2 == v->uv_lcl_addr)
122                                 break;
123                         
124                         if (vifi == numvifs)
125                             fatal("%s is not a configured interface",
126                                 inet_fmt($2,s1));
127
128                                         }
129                 ifmods
130         | TUNNEL interface addrname     {
131
132                         struct ifreq *ifr;
133                         struct ifreq ffr;
134                         vifi_t vifi;
135
136                         order++;
137
138                         ifr = ifconfaddr(&ifc, $2);
139                         if (ifr == 0)
140                             fatal("Tunnel local address %s is not mine",
141                                 inet_fmt($2, s1));
142
143                         if (((ntohl($2) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) ==
144                                 IN_LOOPBACKNET)
145                             fatal("Tunnel local address %s is a loopback address",
146                                 inet_fmt($2, s1));
147
148                         if (ifconfaddr(&ifc, $3) != 0)
149                             fatal("Tunnel remote address %s is one of mine",
150                                 inet_fmt($3, s1));
151
152                         for (vifi = 0, v = uvifs;
153                              vifi < numvifs;
154                              ++vifi, ++v)
155                             if (v->uv_flags & VIFF_TUNNEL) {
156                                 if ($3 == v->uv_rmt_addr)
157                                     fatal("Duplicate tunnel to %s",
158                                         inet_fmt($3, s1));
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);
163                             }
164
165                         if (numvifs == MAXVIFS)
166                             fatal("too many vifs");
167
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);
171
172                         v = &uvifs[numvifs];
173                         zero_vif(v, 1);
174                         v->uv_flags     = VIFF_TUNNEL | rexmit | noflood;
175                         v->uv_flags |= VIFF_OTUNNEL; /*XXX*/
176                         v->uv_lcl_addr  = $2;
177                         v->uv_rmt_addr  = $3;
178                         v->uv_dst_addr  = $3;
179                         strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
180                         v->uv_name[IFNAMSIZ-1]='\0';
181
182                         if (!(ffr.ifr_flags & IFF_UP)) {
183                             v->uv_flags |= VIFF_DOWN;
184                             vifs_down = TRUE;
185                         }
186                                         }
187                 tunnelmods
188                                         {
189
190         if (!(v->uv_flags & VIFF_OTUNNEL)) {
191             init_ipip_on_vif(v);
192         }
193
194         log(LOG_INFO, 0,
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);
198
199         ++numvifs;
200
201                                         }
202         | CACHE_LIFETIME NUMBER     {
203
204                         if ($2 < MIN_CACHE_LIFETIME) {
205                             warn("cache_lifetime %d must be at least %d",
206                                             $2, MIN_CACHE_LIFETIME);
207                         } else {
208                             cache_lifetime = $2;
209                         }
210
211                                     }
212         | PRUNE_LIFETIME NUMBER     {
213
214                         if ($2 < MIN_PRUNE_LIFETIME) {
215                             warn("prune_lifetime %d must be at least %d",
216                                             $2, MIN_PRUNE_LIFETIME);
217                         } else {
218                             prune_lifetime = $2;
219                         }
220
221                                     }
222         | PRUNING BOOLEAN           {
223
224                         if ($2 != 1) {
225                             warn("Disabling pruning is no longer supported");
226                         }
227
228                                     }
229         | BLACK_HOLE                {
230 #ifdef ALLOW_BLACK_HOLES
231                                         allow_black_holes = 1;
232 #endif
233                                     }
234         /*
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.
238          */
239         | NOFLOOD                   {
240
241                         vifi_t vifi;
242
243                         noflood = VIFF_NOFLOOD;
244                         for (vifi = 0, v = uvifs;
245                              vifi < numvifs;
246                              ++vifi, ++v)
247                                 v->uv_flags |= VIFF_NOFLOOD;
248
249                                     }
250         /*
251          * Turn on prune retransmission on all interfaces.
252          * Tunnels default to retransmitting, so this just
253          * needs to turn on phyints.
254          */
255         | REXMIT_PRUNES             {
256
257                         vifi_t vifi;
258
259                         for (vifi = 0, v = uvifs;
260                              vifi < numvifs;
261                              ++vifi, ++v)
262                                 v->uv_flags |= VIFF_REXMIT_PRUNES;
263
264                                     }
265         /*
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.
269          */
270         | REXMIT_PRUNES BOOLEAN {
271
272                     if ($2) {
273                         vifi_t vifi;
274
275                         for (vifi = 0, v = uvifs;
276                              vifi < numvifs;
277                              ++vifi, ++v)
278                                 v->uv_flags |= VIFF_REXMIT_PRUNES;
279                     } else {
280                         rexmit = 0;
281                     }
282
283                                 }
284         | NAME STRING boundary      { if (numbounds >= MAXBOUNDS) {
285                                         fatal("Too many named boundaries (max %d)", MAXBOUNDS);
286                                       }
287
288                                       boundlist[numbounds].name = malloc(strlen($2) + 1);
289                                       strcpy(boundlist[numbounds].name, $2);
290                                       boundlist[numbounds++].bound = $3;
291                                     }
292         | SYSNAM STRING    {
293 #ifdef SNMP
294                             set_sysName($2);
295 #endif /* SNMP */
296                             }
297         | SYSCONTACT STRING {
298 #ifdef SNMP
299                             set_sysContact($2);
300 #endif /* SNMP */
301                             }
302         | SYSVERSION STRING {
303 #ifdef SNMP
304                             set_sysVersion($2);
305 #endif /* SNMP */
306                             }
307         | SYSLOCATION STRING {
308 #ifdef SNMP
309                             set_sysLocation($2);
310 #endif /* SNMP */
311                             }
312         ;
313
314 tunnelmods      : /* empty */
315         | tunnelmods tunnelmod
316         ;
317
318 tunnelmod       : mod
319         | BESIDE                { v->uv_flags |= VIFF_OTUNNEL; }
320         | BESIDE BOOLEAN        {
321
322                     if ($2) {
323                         v->uv_flags |= VIFF_OTUNNEL;
324                     } else {
325                         v->uv_flags &= ~VIFF_OTUNNEL;
326                     }
327
328                                 }
329         | SRCRT                 { fatal("Source-route tunnels not supported"); }
330         ;
331
332 ifmods  : /* empty */
333         | ifmods ifmod
334         ;
335
336 ifmod   : mod
337         | DISABLE               { v->uv_flags |= VIFF_DISABLED; }
338         | IGMPV1                { v->uv_flags |= VIFF_IGMPV1; }
339         | NETMASK addrname      {
340                                   u_int32 subnet, mask;
341
342                                   mask = $2;
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;
349                                 }
350         | NETMASK               {
351
352                     warn("Expected address after netmask keyword, ignored");
353
354                                 }
355         | ALTNET addrmask       {
356
357                     struct phaddr *ph;
358
359                     ph = (struct phaddr *)malloc(sizeof(struct phaddr));
360                     if (ph == NULL)
361                         fatal("out of memory");
362                     if ($2.mask) {
363                         VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
364                     } else
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;
372                     v->uv_addrs = ph;
373
374                                 }
375         | ALTNET                {
376
377                     warn("Expected address after altnet keyword, ignored");
378
379                                 }
380         | FORCE_LEAF            {
381
382                     v->uv_flags |= VIFF_FORCE_LEAF;
383
384                                 }
385         | FORCE_LEAF BOOLEAN    {
386
387                     if ($2) {
388                         v->uv_flags |= VIFF_FORCE_LEAF;
389                     } else {
390                         v->uv_flags &= ~VIFF_FORCE_LEAF;
391                     }
392
393                                 }
394         ;
395
396 mod     : THRESHOLD NUMBER      { if ($2 < 1 || $2 > 255)
397                                     fatal("Invalid threshold %d",$2);
398                                   v->uv_threshold = $2;
399                                 }
400         | THRESHOLD             {
401
402                     warn("Expected number after threshold keyword, ignored");
403
404                                 }
405         | METRIC NUMBER         { if ($2 < 1 || $2 > UNREACHABLE)
406                                     fatal("Invalid metric %d",$2);
407                                   v->uv_metric = $2;
408                                 }
409         | METRIC                {
410
411                     warn("Expected number after metric keyword, ignored");
412
413                                 }
414         | ADVERT_METRIC NUMBER  { if ($2 < 0 || $2 > UNREACHABLE - 1)
415                                     fatal("Invalid advert_metric %d", $2);
416                                   v->uv_admetric = $2;
417                                 }
418         | ADVERT_METRIC         {
419
420                     warn("Expected number after advert_metric keyword, ignored");
421
422                                 }
423         | RATE_LIMIT NUMBER     { if ($2 > MAX_RATE_LIMIT)
424                                     fatal("Invalid rate_limit %d",$2);
425                                   v->uv_rate_limit = $2;
426                                 }
427         | RATE_LIMIT            {
428
429                     warn("Expected number after rate_limit keyword, ignored");
430
431                                 }
432         | BOUNDARY bound        {
433
434                     struct vif_acl *v_acl;
435
436                     v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
437                     if (v_acl == NULL)
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;
445                     v->uv_acl = v_acl;
446
447                                 }
448         | BOUNDARY              {
449
450                 warn("Expected boundary spec after boundary keyword, ignored");
451
452                                 }
453         | REXMIT_PRUNES2        {
454
455                     v->uv_flags |= VIFF_REXMIT_PRUNES;
456
457                                 }
458         | REXMIT_PRUNES2 BOOLEAN {
459
460                     if ($2) {
461                         v->uv_flags |= VIFF_REXMIT_PRUNES;
462                     } else {
463                         v->uv_flags &= ~VIFF_REXMIT_PRUNES;
464                     }
465
466                                 }
467         | PASSIVE               {
468
469                     v->uv_flags |= VIFF_PASSIVE;
470
471                                 }
472         | NOFLOOD2              {
473
474                     v->uv_flags |= VIFF_NOFLOOD;
475
476                                 }
477         | NOTRANSIT             {
478
479                     v->uv_flags |= VIFF_NOTRANSIT;
480
481                                 }
482         | BLASTER               {
483
484                     v->uv_flags |= VIFF_BLASTER;
485                     blaster_alloc(v - uvifs);
486
487                                 }
488         | ALLOW_NONPRUNERS      {
489
490                     v->uv_flags |= VIFF_ALLOW_NONPRUNERS;
491
492                                 }
493         | PRUNE_LIFETIME2 NUMBER {
494
495                         if ($2 < MIN_PRUNE_LIFETIME) {
496                             warn("prune_lifetime %d must be at least %d",
497                                             $2, MIN_PRUNE_LIFETIME);
498                         } else {
499                             v->uv_prune_lifetime = $2;
500                         }
501
502                                 }
503         | ACCEPT filter         {
504
505                     if (v->uv_filter == NULL) {
506                         struct vif_filter *v_filter;
507
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");
517                     } else {
518                         struct vf_element *p;
519
520                         p = v->uv_filter->vf_filter;
521                         while (p->vfe_next)
522                             p = p->vfe_next;
523                         p->vfe_next = $2;
524                     }
525
526                                 }
527         | ACCEPT                {
528
529                 warn("Expected filter spec after accept keyword, ignored");
530
531                                 }
532         | DENY filter           {
533
534                     if (v->uv_filter == NULL) {
535                         struct vif_filter *v_filter;
536
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");
546                     } else {
547                         struct vf_element *p;
548
549                         p = v->uv_filter->vf_filter;
550                         while (p->vfe_next)
551                             p = p->vfe_next;
552                         p->vfe_next = $2;
553                     }
554
555                                 }
556         | DENY                  {
557
558                 warn("Expected filter spec after deny keyword, ignored");
559
560                                 }
561         | BIDIR                 {
562
563                     if (v->uv_filter == NULL) {
564                         fatal("bidir goes after filters");
565                     }
566                     v->uv_filter->vf_flags |= VFF_BIDIR;
567
568                                 }
569         ;
570
571 interface       : ADDR          { $$ = $1; }
572         | STRING                {
573                                   $$ = valid_if($1);
574                                   if ($$ == 0)
575                                         fatal("Invalid interface name %s",$1);
576                                 }
577         ;
578
579 addrname        : ADDR          { $$ = $1; }
580         | STRING                { struct hostent *hp;
581
582                                   if ((hp = gethostbyname($1)) == NULL ||
583                                         hp->h_length != sizeof($$))
584                                     fatal("No such host %s", $1);
585
586                                   if (hp->h_addr_list[1])
587                                     fatal("Hostname %s does not %s",
588                                         $1, "map to a unique address");
589
590                                   bcopy(hp->h_addr_list[0], &$$,
591                                             hp->h_length);
592                                 }
593
594 bound   : boundary              { $$ = $1; }
595         | STRING                { int i;
596
597                                   for (i=0; i < numbounds; i++) {
598                                     if (!strcmp(boundlist[i].name, $1)) {
599                                         $$ = boundlist[i].bound;
600                                         break;
601                                     }
602                                   }
603                                   if (i == numbounds) {
604                                     fatal("Invalid boundary name %s",$1);
605                                   }
606                                 }
607         ;
608
609 boundary        : ADDRMASK      {
610
611 #ifdef ALLOW_BLACK_HOLES
612                         if (!allow_black_holes)
613 #endif
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);
617                         }
618                         $$ = $1;
619
620                                 }
621         ;
622
623 addrmask        : ADDRMASK      { $$ = $1; }
624         | ADDR                  { $$.addr = $1; $$.mask = 0; }
625         ;
626
627 filter  :       filtlist        { $$ = $1; }
628         | STRING                { fatal("named filters no implemented yet"); }
629         ;
630
631 filtlist        : filtelement   { $$ = $1; }
632         | filtelement filtlist  { $1->vfe_next = $2; $$ = $1; }
633         ;
634
635 filtelement     : filtelem      { $$ = $1; }
636         | filtelem EXACT        { $1->vfe_flags |= VFEF_EXACT; $$ = $1; }
637         ;
638
639 filtelem        : ADDRMASK      {
640
641                         struct vf_element *vfe;
642
643                         vfe = (struct vf_element *)malloc(sizeof(struct vf_element));
644                         if (vfe == NULL)
645                             fatal("out of memory");
646
647                         vfe->vfe_addr = $1.addr;
648                         VAL_TO_MASK(vfe->vfe_mask, $1.mask);
649                         vfe->vfe_flags = 0;
650                         vfe->vfe_next = NULL;
651
652                         $$ = vfe;
653
654                                 }
655 %%
656 #ifdef __STDC__
657 static void
658 fatal(char *fmt, ...)
659 {
660         va_list ap;
661         char buf[MAXHOSTNAMELEN + 100];
662
663         va_start(ap, fmt);
664 #else
665 /*VARARGS1*/
666 static void
667 fatal(fmt, va_alist)
668 char *fmt;
669 va_dcl
670 {
671         va_list ap;
672         char buf[MAXHOSTNAMELEN + 100];
673
674         va_start(ap);
675 #endif
676         vsnprintf(buf, sizeof(buf), fmt, ap);
677         va_end(ap);
678
679         log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
680 }
681
682 #ifdef __STDC__
683 static void
684 warn(char *fmt, ...)
685 {
686         va_list ap;
687         char buf[200];
688
689         va_start(ap, fmt);
690 #else
691 /*VARARGS1*/
692 static void
693 warn(fmt, va_alist)
694 char *fmt;
695 va_dcl
696 {
697         va_list ap;
698         char buf[200];
699
700         va_start(ap);
701 #endif
702         vsnprintf(buf, sizeof(buf), fmt, ap);
703         va_end(ap);
704
705         log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
706 }
707
708 static void
709 yyerror(s)
710 char *s;
711 {
712         log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
713 }
714
715 static char *
716 next_word()
717 {
718         static char buf[1024];
719         static char *p=NULL;
720         char *q;
721
722         while (1) {
723             if (!p || !*p) {
724                 lineno++;
725                 if (fgets(buf, sizeof(buf), f) == NULL)
726                     return NULL;
727                 p = buf;
728             }
729             while (*p && (*p == ' ' || *p == '\t'))     /* skip whitespace */
730                 p++;
731             if (*p == '#') {
732                 p = NULL;               /* skip comments */
733                 continue;
734             }
735             q = p;
736 #ifdef SNMP
737        if (*p == '"') {
738           p++;
739                while (*p && *p != '"' && *p != '\n')
740                       p++;              /* find next whitespace */
741           if (*p == '"')
742              p++;
743        } else
744 #endif
745             while (*p && *p != ' ' && *p != '\t' && *p != '\n')
746                 p++;            /* find next whitespace */
747             *p++ = '\0';        /* null-terminate string */
748
749             if (!*q) {
750                 p = NULL;
751                 continue;       /* if 0-length string, read another line */
752             }
753
754             return q;
755         }
756 }
757
758 /*
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).
763  */
764 static struct keyword {
765         char    *word;
766         int     val1;
767         int     val2;
768 } words[] = {
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 },
780         { "srcrt",              SRCRT },
781         { "sourceroute",        SRCRT },
782         { "boundary",           BOUNDARY },
783         { "netmask",            NETMASK },
784         { "igmpv1",             IGMPV1 },
785         { "altnet",             ALTNET },
786         { "name",               NAME },
787         { "accept",             ACCEPT },
788         { "deny",               DENY },
789         { "exact",              EXACT },
790         { "bidir",              BIDIR },
791         { "allow_nonpruners",   ALLOW_NONPRUNERS },
792 #ifdef ALLOW_BLACK_HOLES
793         { "allow_black_holes",  BLACK_HOLE },
794 #endif
795         { "noflood",            NOFLOOD, NOFLOOD2},
796         { "notransit",          NOTRANSIT },
797         { "blaster",            BLASTER },
798         { "rexmit_prunes",      REXMIT_PRUNES, REXMIT_PRUNES2 },
799         { "passive",            PASSIVE },
800         { "beside",             BESIDE },
801 #ifdef SNMP
802         { "sysName",            SYSNAM },
803         { "sysContact",         SYSCONTACT },
804         { "sysVersion",         SYSVERSION },
805         { "sysLocation",        SYSLOCATION },
806 #endif
807         { NULL,                 0 }
808 };
809
810
811 static int
812 yylex()
813 {
814         int n;
815         u_int32 addr;
816         char *q;
817         struct keyword *w;
818
819         if ((q = next_word()) == NULL) {
820                 return 0;
821         }
822
823         for (w = words; w->word; w++)
824                 if (!strcmp(q, w->word))
825                     return (state && w->val2) ? w->val2 : w->val1;
826
827         if (!strcmp(q,"on") || !strcmp(q,"yes")) {
828                 yylval.num = 1;
829                 return BOOLEAN;
830         }
831         if (!strcmp(q,"off") || !strcmp(q,"no")) {
832                 yylval.num = 0;
833                 return BOOLEAN;
834         }
835         if (!strcmp(q,"default")) {
836                 yylval.addrmask.mask = 0;
837                 yylval.addrmask.addr = 0;
838                 return ADDRMASK;
839         }
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;
844                         return ADDRMASK;
845                 }
846                 /* fall through to returning STRING */
847         }
848         if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
849                 if ((addr = inet_parse(s1,4)) != 0xffffffff &&
850                     inet_valid_host(addr)) { 
851                         yylval.addr = addr;
852                         return ADDR;
853                 }
854         }
855         if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
856                 yylval.addr = n;
857                 return ADDR;
858         }
859         if (sscanf(q,"%d%c",&n,s1) == 1) {
860                 yylval.num = n;
861                 return NUMBER;
862         }
863 #ifdef SNMP
864    if (*q=='"') {
865       if (q[ strlen(q)-1 ]=='"')
866          q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
867       yylval.ptr = q+1;
868       return STRING;
869    }
870 #endif
871         yylval.ptr = q;
872         return STRING;
873 }
874
875 void
876 config_vifs_from_file()
877 {
878         order = 0;
879         state = 0;
880         numbounds = 0;
881         lineno = 0;
882
883         if ((f = fopen(configfilename, "r")) == NULL) {
884             if (errno != ENOENT)
885                 log(LOG_ERR, errno, "can't open %s", configfilename);
886             return;
887         }
888
889         yyparse();
890
891         fclose(f);
892 }
893
894 static u_int32
895 valid_if(s)
896 char *s;
897 {
898         register vifi_t vifi;
899         register struct uvif *v;
900
901         for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
902             if (!strcmp(v->uv_name, s))
903                 return v->uv_lcl_addr;
904
905         return 0;
906 }
907
908 static struct ifreq *
909 ifconfaddr(ifcp, a)
910     struct ifconf *ifcp;
911     u_int32 a;
912 {
913     int n;
914     struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
915     struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
916
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)
920                     return (ifrp);
921 #ifdef HAVE_SA_LEN
922                 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
923                 if (n < sizeof(*ifrp))
924                         ++ifrp;
925                 else
926                         ifrp = (struct ifreq *)((char *)ifrp + n);
927 #else
928                 ++ifrp;
929 #endif
930     }
931     return (0);
932 }