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