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