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