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