"Fossies" - the Fresh Open Source Software Archive

Member "ospfd/parse.y" (5 Jun 2009, 26619 Bytes) of package /linux/privat/old/openospfd-4.6.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bison source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 /*  $OpenBSD: parse.y,v 1.67 2009/06/05 04:12:52 claudio Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
    5  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
    6  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
    7  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
    8  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
    9  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
   10  *
   11  * Permission to use, copy, modify, and distribute this software for any
   12  * purpose with or without fee is hereby granted, provided that the above
   13  * copyright notice and this permission notice appear in all copies.
   14  *
   15  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   22  */
   23 
   24 %{
   25 #include <sys/types.h>
   26 #include <sys/socket.h>
   27 #include <sys/stat.h>
   28 #include <netinet/in.h>
   29 #include <arpa/inet.h>
   30 #include <ctype.h>
   31 #include <err.h>
   32 #include <errno.h>
   33 #include <unistd.h>
   34 #include <ifaddrs.h>
   35 #include <limits.h>
   36 #include <stdarg.h>
   37 #include <stdio.h>
   38 #include <string.h>
   39 
   40 #include "ospf.h"
   41 #include "ospfd.h"
   42 #include "ospfe.h"
   43 #include "log.h"
   44 
   45 TAILQ_HEAD(files, file)      files = TAILQ_HEAD_INITIALIZER(files);
   46 static struct file {
   47     TAILQ_ENTRY(file)    entry;
   48     FILE            *stream;
   49     char            *name;
   50     int          lineno;
   51     int          errors;
   52 } *file, *topfile;
   53 struct file *pushfile(const char *, int);
   54 int      popfile(void);
   55 int      check_file_secrecy(int, const char *);
   56 int      yyparse(void);
   57 int      yylex(void);
   58 int      yyerror(const char *, ...);
   59 int      kw_cmp(const void *, const void *);
   60 int      lookup(char *);
   61 int      lgetc(int);
   62 int      lungetc(int);
   63 int      findeol(void);
   64 
   65 TAILQ_HEAD(symhead, sym)     symhead = TAILQ_HEAD_INITIALIZER(symhead);
   66 struct sym {
   67     TAILQ_ENTRY(sym)     entry;
   68     int          used;
   69     int          persist;
   70     char            *nam;
   71     char            *val;
   72 };
   73 int      symset(const char *, const char *, int);
   74 char        *symget(const char *);
   75 
   76 void         clear_config(struct ospfd_conf *xconf);
   77 u_int32_t    get_rtr_id(void);
   78 int      host(const char *, struct in_addr *, struct in_addr *);
   79 
   80 static struct ospfd_conf    *conf;
   81 static int           errors = 0;
   82 
   83 struct area *area = NULL;
   84 struct iface    *iface = NULL;
   85 
   86 struct config_defaults {
   87     char        auth_key[MAX_SIMPLE_AUTH_LEN];
   88     struct auth_md_head  md_list;
   89     u_int32_t   dead_interval;
   90     u_int16_t   transmit_delay;
   91     u_int16_t   hello_interval;
   92     u_int16_t   rxmt_interval;
   93     u_int16_t   metric;
   94     enum auth_type  auth_type;
   95     u_int8_t    auth_keyid;
   96     u_int8_t    priority;
   97 };
   98 
   99 struct config_defaults   globaldefs;
  100 struct config_defaults   areadefs;
  101 struct config_defaults   ifacedefs;
  102 struct config_defaults  *defs;
  103 
  104 struct area *conf_get_area(struct in_addr);
  105 struct iface    *conf_get_if(struct kif *, struct kif_addr *);
  106 
  107 typedef struct {
  108     union {
  109         int64_t      number;
  110         char        *string;
  111         struct redistribute *redist;
  112     } v;
  113     int lineno;
  114 } YYSTYPE;
  115 
  116 %}
  117 
  118 %token  AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL RDOMAIN
  119 %token  RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
  120 %token  AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
  121 %token  METRIC PASSIVE
  122 %token  HELLOINTERVAL TRANSMITDELAY
  123 %token  RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
  124 %token  SET TYPE
  125 %token  YES NO
  126 %token  DEMOTE
  127 %token  ERROR
  128 %token  <v.string>  STRING
  129 %token  <v.number>  NUMBER
  130 %type   <v.number>  yesno no optlist optlist_l option demotecount
  131 %type   <v.string>  string
  132 %type   <v.redist>  redistribute
  133 
  134 %%
  135 
  136 grammar     : /* empty */
  137         | grammar '\n'
  138         | grammar conf_main '\n'
  139         | grammar varset '\n'
  140         | grammar area '\n'
  141         | grammar error '\n'        { file->errors++; }
  142         ;
  143 
  144 string      : string STRING {
  145             if (asprintf(&$$, "%s %s", $1, $2) == -1) {
  146                 free($1);
  147                 free($2);
  148                 yyerror("string: asprintf");
  149                 YYERROR;
  150             }
  151             free($1);
  152             free($2);
  153         }
  154         | STRING
  155         ;
  156 
  157 yesno       : YES   { $$ = 1; }
  158         | NO    { $$ = 0; }
  159         ;
  160 
  161 no      : /* empty */   { $$ = 0; }
  162         | NO        { $$ = 1; }
  163         ;
  164 
  165 varset      : STRING '=' string     {
  166             if (conf->opts & OSPFD_OPT_VERBOSE)
  167                 printf("%s = \"%s\"\n", $1, $3);
  168             if (symset($1, $3, 0) == -1)
  169                 fatal("cannot store variable");
  170             free($1);
  171             free($3);
  172         }
  173         ;
  174 
  175 conf_main   : ROUTERID STRING {
  176             if (!inet_aton($2, &conf->rtr_id)) {
  177                 yyerror("error parsing router-id");
  178                 free($2);
  179                 YYERROR;
  180             }
  181             free($2);
  182         }
  183         | FIBUPDATE yesno {
  184             if ($2 == 0)
  185                 conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
  186             else
  187                 conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
  188         }
  189         | redistribute {
  190             SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
  191             conf->redistribute = 1;
  192         }
  193         | RTLABEL STRING EXTTAG NUMBER {
  194             if ($4 < 0 || $4 > UINT_MAX) {
  195                 yyerror("invalid external route tag");
  196                 free($2);
  197                 YYERROR;
  198             }
  199             rtlabel_tag(rtlabel_name2id($2), $4);
  200             free($2);
  201         }
  202         | RDOMAIN NUMBER {
  203             if ($2 < 0 || $2 > RT_TABLEID_MAX) {
  204                 yyerror("invalid rdomain");
  205                 YYERROR;
  206             }
  207             conf->rdomain = $2;
  208         }
  209         | RFC1583COMPAT yesno {
  210             conf->rfc1583compat = $2;
  211         }
  212         | SPFDELAY NUMBER {
  213             if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
  214                 yyerror("spf-delay out of range "
  215                     "(%d-%d)", MIN_SPF_DELAY,
  216                     MAX_SPF_DELAY);
  217                 YYERROR;
  218             }
  219             conf->spf_delay = $2;
  220         }
  221         | SPFHOLDTIME NUMBER {
  222             if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
  223                 yyerror("spf-holdtime out of range "
  224                     "(%d-%d)", MIN_SPF_HOLDTIME,
  225                     MAX_SPF_HOLDTIME);
  226                 YYERROR;
  227             }
  228             conf->spf_hold_time = $2;
  229         }
  230         | STUB ROUTER yesno {
  231             if ($3)
  232                 conf->flags |= OSPFD_FLAG_STUB_ROUTER;
  233             else
  234                 /* allow to force non stub mode */
  235                 conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
  236         }
  237         | defaults
  238         ;
  239 
  240 
  241 redistribute    : no REDISTRIBUTE NUMBER '/' NUMBER optlist {
  242             struct redistribute *r;
  243 
  244             if ((r = calloc(1, sizeof(*r))) == NULL)
  245                 fatal(NULL);
  246             r->type = REDIST_ADDR;
  247             if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) {
  248                 yyerror("bad network: %llu/%llu", $3, $5);
  249                 free(r);
  250                 YYERROR;
  251             }
  252             r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT);
  253             r->mask.s_addr = prefixlen2mask($5);
  254 
  255             if ($1)
  256                 r->type |= REDIST_NO;
  257             r->metric = $6;
  258             $$ = r;
  259         }
  260         | no REDISTRIBUTE STRING optlist {
  261             struct redistribute *r;
  262 
  263             if ((r = calloc(1, sizeof(*r))) == NULL)
  264                 fatal(NULL);
  265             if (!strcmp($3, "default"))
  266                 r->type = REDIST_DEFAULT;
  267             else if (!strcmp($3, "static"))
  268                 r->type = REDIST_STATIC;
  269             else if (!strcmp($3, "connected"))
  270                 r->type = REDIST_CONNECTED;
  271             else if (host($3, &r->addr, &r->mask))
  272                 r->type = REDIST_ADDR;
  273             else {
  274                 yyerror("unknown redistribute type");
  275                 free($3);
  276                 free(r);
  277                 YYERROR;
  278             }
  279 
  280             if ($1)
  281                 r->type |= REDIST_NO;
  282             r->metric = $4;
  283             free($3);
  284             $$ = r;
  285         }
  286         | no REDISTRIBUTE RTLABEL STRING optlist {
  287             struct redistribute *r;
  288 
  289             if ((r = calloc(1, sizeof(*r))) == NULL)
  290                 fatal(NULL);
  291             r->type = REDIST_LABEL;
  292             r->label = rtlabel_name2id($4);
  293             if ($1)
  294                 r->type |= REDIST_NO;
  295             r->metric = $5;
  296             free($4);
  297 
  298             $$ = r;
  299         }
  300         ;
  301 
  302 optlist     : /* empty */           { $$ = DEFAULT_REDIST_METRIC; }
  303         | SET option            {
  304             $$ = $2;
  305             if (($$ & LSA_METRIC_MASK) == 0)
  306                 $$ |= DEFAULT_REDIST_METRIC;
  307         }
  308         | SET optnl '{' optnl optlist_l optnl '}'   {
  309             $$ = $5;
  310             if (($$ & LSA_METRIC_MASK) == 0)
  311                 $$ |= DEFAULT_REDIST_METRIC;
  312         }
  313         ;
  314 
  315 optlist_l   : optlist_l comma option {
  316             if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
  317                 yyerror("redistribute type already defined");
  318                 YYERROR;
  319             }
  320             if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
  321                 yyerror("redistribute metric already defined");
  322                 YYERROR;
  323             }
  324             $$ = $1 | $3;
  325         }
  326         | option { $$ = $1; }
  327         ;
  328 
  329 option      : METRIC NUMBER {
  330             if ($2 == 0 || $2 > MAX_METRIC) {
  331                 yyerror("invalid redistribute metric");
  332                 YYERROR;
  333             }
  334             $$ = $2;
  335         }
  336         | TYPE NUMBER {
  337             switch ($2) {
  338             case 1:
  339                 $$ = 0;
  340                 break;
  341             case 2:
  342                 $$ = LSA_ASEXT_E_FLAG;
  343                 break;
  344             default:
  345                 yyerror("only external type 1 and 2 allowed");
  346                 YYERROR;
  347             }
  348         }
  349         ;
  350 
  351 authmd      : AUTHMD NUMBER STRING {
  352             if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
  353                 yyerror("auth-md key-id out of range "
  354                     "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
  355                 free($3);
  356                 YYERROR;
  357             }
  358             if (strlen($3) > MD5_DIGEST_LENGTH) {
  359                 yyerror("auth-md key length out of range "
  360                     "(max length %d)",
  361                     MD5_DIGEST_LENGTH);
  362                 free($3);
  363                 YYERROR;
  364             }
  365             md_list_add(&defs->md_list, $2, $3);
  366             free($3);
  367         }
  368 
  369 authmdkeyid : AUTHMDKEYID NUMBER {
  370             if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
  371                 yyerror("auth-md-keyid out of range "
  372                     "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
  373                 YYERROR;
  374             }
  375             defs->auth_keyid = $2;
  376         }
  377 
  378 authtype    : AUTHTYPE STRING {
  379             enum auth_type  type;
  380 
  381             if (!strcmp($2, "none"))
  382                 type = AUTH_NONE;
  383             else if (!strcmp($2, "simple"))
  384                 type = AUTH_SIMPLE;
  385             else if (!strcmp($2, "crypt"))
  386                 type = AUTH_CRYPT;
  387             else {
  388                 yyerror("unknown auth-type");
  389                 free($2);
  390                 YYERROR;
  391             }
  392             free($2);
  393             defs->auth_type = type;
  394         }
  395         ;
  396 
  397 authkey     : AUTHKEY STRING {
  398             if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
  399                 yyerror("auth-key too long (max length %d)",
  400                     MAX_SIMPLE_AUTH_LEN);
  401                     free($2);
  402                     YYERROR;
  403             }
  404             strncpy(defs->auth_key, $2,
  405                 sizeof(defs->auth_key));
  406             free($2);
  407         }
  408         ;
  409 
  410 defaults    : METRIC NUMBER {
  411             if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
  412                 yyerror("metric out of range (%d-%d)",
  413                     MIN_METRIC, MAX_METRIC);
  414                 YYERROR;
  415             }
  416             defs->metric = $2;
  417         }
  418         | ROUTERPRIORITY NUMBER {
  419             if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
  420                 yyerror("router-priority out of range (%d-%d)",
  421                     MIN_PRIORITY, MAX_PRIORITY);
  422                 YYERROR;
  423             }
  424             defs->priority = $2;
  425         }
  426         | ROUTERDEADTIME NUMBER {
  427             if ($2 < MIN_RTR_DEAD_TIME || $2 > MAX_RTR_DEAD_TIME) {
  428                 yyerror("router-dead-time out of range (%d-%d)",
  429                     MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
  430                 YYERROR;
  431             }
  432             defs->dead_interval = $2;
  433         }
  434         | TRANSMITDELAY NUMBER {
  435             if ($2 < MIN_TRANSMIT_DELAY ||
  436                 $2 > MAX_TRANSMIT_DELAY) {
  437                 yyerror("transmit-delay out of range (%d-%d)",
  438                     MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
  439                 YYERROR;
  440             }
  441             defs->transmit_delay = $2;
  442         }
  443         | HELLOINTERVAL NUMBER {
  444             if ($2 < MIN_HELLO_INTERVAL ||
  445                 $2 > MAX_HELLO_INTERVAL) {
  446                 yyerror("hello-interval out of range (%d-%d)",
  447                     MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
  448                 YYERROR;
  449             }
  450             defs->hello_interval = $2;
  451         }
  452         | RETRANSMITINTERVAL NUMBER {
  453             if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
  454                 yyerror("retransmit-interval out of range "
  455                     "(%d-%d)", MIN_RXMT_INTERVAL,
  456                     MAX_RXMT_INTERVAL);
  457                 YYERROR;
  458             }
  459             defs->rxmt_interval = $2;
  460         }
  461         | authtype
  462         | authkey
  463         | authmdkeyid
  464         | authmd
  465         ;
  466 
  467 optnl       : '\n' optnl
  468         |
  469         ;
  470 
  471 nl      : '\n' optnl        /* one newline or more */
  472         ;
  473 
  474 comma       : ','
  475         | /*empty*/
  476         ;
  477 
  478 area        : AREA STRING {
  479             struct in_addr  id;
  480             if (inet_aton($2, &id) == 0) {
  481                 yyerror("error parsing area");
  482                 free($2);
  483                 YYERROR;
  484             }
  485             free($2);
  486             area = conf_get_area(id);
  487 
  488             memcpy(&areadefs, defs, sizeof(areadefs));
  489             md_list_copy(&areadefs.md_list, &defs->md_list);
  490             defs = &areadefs;
  491         } '{' optnl areaopts_l '}' {
  492             area = NULL;
  493             md_list_clr(&defs->md_list);
  494             defs = &globaldefs;
  495         }
  496         ;
  497 
  498 demotecount : NUMBER    { $$ = $1; }
  499         | /*empty*/ { $$ = 1; }
  500         ;
  501 
  502 areaopts_l  : areaopts_l areaoptsl nl
  503         | areaoptsl optnl
  504         ;
  505 
  506 areaoptsl   : interface
  507         | DEMOTE STRING demotecount {
  508             if ($3 < 1 || $3 > 255) {
  509                 yyerror("demote count out of range (1-255)");
  510                 free($2);
  511                 YYERROR;
  512             }
  513             area->demote_level = $3;
  514             if (strlcpy(area->demote_group, $2,
  515                 sizeof(area->demote_group)) >=
  516                 sizeof(area->demote_group)) {
  517                 yyerror("demote group name \"%s\" too long");
  518                 free($2);
  519                 YYERROR;
  520             }
  521             free($2);
  522             if (carp_demote_init(area->demote_group,
  523                 conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
  524                 yyerror("error initializing group \"%s\"",
  525                     area->demote_group);
  526                 YYERROR;
  527             }
  528         }
  529         | defaults
  530         | STUB          { area->stub = 1; }
  531         | STUB redistribute {
  532             area->stub = 1;
  533             if ($2->type != REDIST_DEFAULT) {
  534                 yyerror("bad redistribute option");
  535                 YYERROR;
  536             }
  537             if (!SIMPLEQ_EMPTY(&area->redist_list)) {
  538                 yyerror("area redistribute option only "
  539                     "allowed once");
  540                 YYERROR;
  541             }
  542             SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry);
  543         }
  544         ;
  545 
  546 interface   : INTERFACE STRING  {
  547             struct kif  *kif;
  548             struct kif_addr *ka = NULL;
  549             char        *s;
  550             struct in_addr   addr;
  551 
  552             s = strchr($2, ':');
  553             if (s) {
  554                 *s++ = '\0';
  555                 if (inet_aton(s, &addr) == 0) {
  556                     yyerror(
  557                         "error parsing interface address");
  558                     free($2);
  559                     YYERROR;
  560                 }
  561             } else
  562                 addr.s_addr = 0;
  563 
  564             if ((kif = kif_findname($2, addr, &ka)) == NULL) {
  565                 yyerror("unknown interface %s", $2);
  566                 free($2);
  567                 YYERROR;
  568             }
  569             if (ka == NULL) {
  570                 if (s)
  571                     yyerror("address %s not configured on "
  572                         "interface %s", s, $2);
  573                 else
  574                     yyerror("unnumbered interface %s", $2);
  575                 free($2);
  576                 YYERROR;
  577             }
  578             free($2);
  579             iface = conf_get_if(kif, ka);
  580             if (iface == NULL)
  581                 YYERROR;
  582             iface->area = area;
  583             LIST_INSERT_HEAD(&area->iface_list, iface, entry);
  584 
  585             memcpy(&ifacedefs, defs, sizeof(ifacedefs));
  586             md_list_copy(&ifacedefs.md_list, &defs->md_list);
  587             defs = &ifacedefs;
  588         } interface_block {
  589             iface->dead_interval = defs->dead_interval;
  590             iface->transmit_delay = defs->transmit_delay;
  591             iface->hello_interval = defs->hello_interval;
  592             iface->rxmt_interval = defs->rxmt_interval;
  593             iface->metric = defs->metric;
  594             iface->priority = defs->priority;
  595             iface->auth_type = defs->auth_type;
  596             iface->auth_keyid = defs->auth_keyid;
  597             memcpy(iface->auth_key, defs->auth_key,
  598                 sizeof(iface->auth_key));
  599             md_list_copy(&iface->auth_md_list, &defs->md_list);
  600             md_list_clr(&defs->md_list);
  601             iface = NULL;
  602             /* interface is always part of an area */
  603             defs = &areadefs;
  604         }
  605         ;
  606 
  607 interface_block : '{' optnl interfaceopts_l '}'
  608         | '{' optnl '}'
  609         |
  610         ;
  611 
  612 interfaceopts_l : interfaceopts_l interfaceoptsl nl
  613         | interfaceoptsl optnl
  614         ;
  615 
  616 interfaceoptsl  : PASSIVE       { iface->passive = 1; }
  617         | DEMOTE STRING     {
  618             if (strlcpy(iface->demote_group, $2,
  619                 sizeof(iface->demote_group)) >=
  620                 sizeof(iface->demote_group)) {
  621                 yyerror("demote group name \"%s\" too long");
  622                 free($2);
  623                 YYERROR;
  624             }
  625             free($2);
  626             if (carp_demote_init(iface->demote_group,
  627                 conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
  628                 yyerror("error initializing group \"%s\"",
  629                     iface->demote_group);
  630                 YYERROR;
  631             }
  632         }
  633         | defaults
  634         ;
  635 
  636 %%
  637 
  638 struct keywords {
  639     const char  *k_name;
  640     int      k_val;
  641 };
  642 
  643 int
  644 yyerror(const char *fmt, ...)
  645 {
  646     va_list ap;
  647 
  648     file->errors++;
  649     va_start(ap, fmt);
  650     fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
  651     vfprintf(stderr, fmt, ap);
  652     fprintf(stderr, "\n");
  653     va_end(ap);
  654     return (0);
  655 }
  656 
  657 int
  658 kw_cmp(const void *k, const void *e)
  659 {
  660     return (strcmp(k, ((const struct keywords *)e)->k_name));
  661 }
  662 
  663 int
  664 lookup(char *s)
  665 {
  666     /* this has to be sorted always */
  667     static const struct keywords keywords[] = {
  668         {"area",        AREA},
  669         {"auth-key",        AUTHKEY},
  670         {"auth-md",     AUTHMD},
  671         {"auth-md-keyid",   AUTHMDKEYID},
  672         {"auth-type",       AUTHTYPE},
  673         {"demote",      DEMOTE},
  674         {"external-tag",    EXTTAG},
  675         {"fib-update",      FIBUPDATE},
  676         {"hello-interval",  HELLOINTERVAL},
  677         {"interface",       INTERFACE},
  678         {"metric",      METRIC},
  679         {"no",          NO},
  680         {"passive",     PASSIVE},
  681         {"rdomain",     RDOMAIN},
  682         {"redistribute",    REDISTRIBUTE},
  683         {"retransmit-interval", RETRANSMITINTERVAL},
  684         {"rfc1583compat",   RFC1583COMPAT},
  685         {"router",      ROUTER},
  686         {"router-dead-time",    ROUTERDEADTIME},
  687         {"router-id",       ROUTERID},
  688         {"router-priority", ROUTERPRIORITY},
  689         {"rtlabel",     RTLABEL},
  690         {"set",         SET},
  691         {"spf-delay",       SPFDELAY},
  692         {"spf-holdtime",    SPFHOLDTIME},
  693         {"stub",        STUB},
  694         {"transmit-delay",  TRANSMITDELAY},
  695         {"type",        TYPE},
  696         {"yes",         YES}
  697     };
  698     const struct keywords   *p;
  699 
  700     p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
  701         sizeof(keywords[0]), kw_cmp);
  702 
  703     if (p)
  704         return (p->k_val);
  705     else
  706         return (STRING);
  707 }
  708 
  709 #define MAXPUSHBACK 128
  710 
  711 char    *parsebuf;
  712 int  parseindex;
  713 char     pushback_buffer[MAXPUSHBACK];
  714 int  pushback_index = 0;
  715 
  716 int
  717 lgetc(int quotec)
  718 {
  719     int     c, next;
  720 
  721     if (parsebuf) {
  722         /* Read character from the parsebuffer instead of input. */
  723         if (parseindex >= 0) {
  724             c = parsebuf[parseindex++];
  725             if (c != '\0')
  726                 return (c);
  727             parsebuf = NULL;
  728         } else
  729             parseindex++;
  730     }
  731 
  732     if (pushback_index)
  733         return (pushback_buffer[--pushback_index]);
  734 
  735     if (quotec) {
  736         if ((c = getc(file->stream)) == EOF) {
  737             yyerror("reached end of file while parsing "
  738                 "quoted string");
  739             if (file == topfile || popfile() == EOF)
  740                 return (EOF);
  741             return (quotec);
  742         }
  743         return (c);
  744     }
  745 
  746     while ((c = getc(file->stream)) == '\\') {
  747         next = getc(file->stream);
  748         if (next != '\n') {
  749             c = next;
  750             break;
  751         }
  752         yylval.lineno = file->lineno;
  753         file->lineno++;
  754     }
  755 
  756     while (c == EOF) {
  757         if (file == topfile || popfile() == EOF)
  758             return (EOF);
  759         c = getc(file->stream);
  760     }
  761     return (c);
  762 }
  763 
  764 int
  765 lungetc(int c)
  766 {
  767     if (c == EOF)
  768         return (EOF);
  769     if (parsebuf) {
  770         parseindex--;
  771         if (parseindex >= 0)
  772             return (c);
  773     }
  774     if (pushback_index < MAXPUSHBACK-1)
  775         return (pushback_buffer[pushback_index++] = c);
  776     else
  777         return (EOF);
  778 }
  779 
  780 int
  781 findeol(void)
  782 {
  783     int c;
  784 
  785     parsebuf = NULL;
  786 
  787     /* skip to either EOF or the first real EOL */
  788     while (1) {
  789         if (pushback_index)
  790             c = pushback_buffer[--pushback_index];
  791         else
  792             c = lgetc(0);
  793         if (c == '\n') {
  794             file->lineno++;
  795             break;
  796         }
  797         if (c == EOF)
  798             break;
  799     }
  800     return (ERROR);
  801 }
  802 
  803 int
  804 yylex(void)
  805 {
  806     char     buf[8096];
  807     char    *p, *val;
  808     int  quotec, next, c;
  809     int  token;
  810 
  811 top:
  812     p = buf;
  813     while ((c = lgetc(0)) == ' ' || c == '\t')
  814         ; /* nothing */
  815 
  816     yylval.lineno = file->lineno;
  817     if (c == '#')
  818         while ((c = lgetc(0)) != '\n' && c != EOF)
  819             ; /* nothing */
  820     if (c == '$' && parsebuf == NULL) {
  821         while (1) {
  822             if ((c = lgetc(0)) == EOF)
  823                 return (0);
  824 
  825             if (p + 1 >= buf + sizeof(buf) - 1) {
  826                 yyerror("string too long");
  827                 return (findeol());
  828             }
  829             if (isalnum(c) || c == '_') {
  830                 *p++ = (char)c;
  831                 continue;
  832             }
  833             *p = '\0';
  834             lungetc(c);
  835             break;
  836         }
  837         val = symget(buf);
  838         if (val == NULL) {
  839             yyerror("macro '%s' not defined", buf);
  840             return (findeol());
  841         }
  842         parsebuf = val;
  843         parseindex = 0;
  844         goto top;
  845     }
  846 
  847     switch (c) {
  848     case '\'':
  849     case '"':
  850         quotec = c;
  851         while (1) {
  852             if ((c = lgetc(quotec)) == EOF)
  853                 return (0);
  854             if (c == '\n') {
  855                 file->lineno++;
  856                 continue;
  857             } else if (c == '\\') {
  858                 if ((next = lgetc(quotec)) == EOF)
  859                     return (0);
  860                 if (next == quotec || c == ' ' || c == '\t')
  861                     c = next;
  862                 else if (next == '\n')
  863                     continue;
  864                 else
  865                     lungetc(next);
  866             } else if (c == quotec) {
  867                 *p = '\0';
  868                 break;
  869             }
  870             if (p + 1 >= buf + sizeof(buf) - 1) {
  871                 yyerror("string too long");
  872                 return (findeol());
  873             }
  874             *p++ = (char)c;
  875         }
  876         yylval.v.string = strdup(buf);
  877         if (yylval.v.string == NULL)
  878             err(1, "yylex: strdup");
  879         return (STRING);
  880     }
  881 
  882 #define allowed_to_end_number(x) \
  883     (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
  884 
  885     if (c == '-' || isdigit(c)) {
  886         do {
  887             *p++ = c;
  888             if ((unsigned)(p-buf) >= sizeof(buf)) {
  889                 yyerror("string too long");
  890                 return (findeol());
  891             }
  892         } while ((c = lgetc(0)) != EOF && isdigit(c));
  893         lungetc(c);
  894         if (p == buf + 1 && buf[0] == '-')
  895             goto nodigits;
  896         if (c == EOF || allowed_to_end_number(c)) {
  897             const char *errstr = NULL;
  898 
  899             *p = '\0';
  900             yylval.v.number = strtonum(buf, LLONG_MIN,
  901                 LLONG_MAX, &errstr);
  902             if (errstr) {
  903                 yyerror("\"%s\" invalid number: %s",
  904                     buf, errstr);
  905                 return (findeol());
  906             }
  907             return (NUMBER);
  908         } else {
  909 nodigits:
  910             while (p > buf + 1)
  911                 lungetc(*--p);
  912             c = *--p;
  913             if (c == '-')
  914                 return (c);
  915         }
  916     }
  917 
  918 #define allowed_in_string(x) \
  919     (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
  920     x != '{' && x != '}' && \
  921     x != '!' && x != '=' && x != '#' && \
  922     x != ','))
  923 
  924     if (isalnum(c) || c == ':' || c == '_') {
  925         do {
  926             *p++ = c;
  927             if ((unsigned)(p-buf) >= sizeof(buf)) {
  928                 yyerror("string too long");
  929                 return (findeol());
  930             }
  931         } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
  932         lungetc(c);
  933         *p = '\0';
  934         if ((token = lookup(buf)) == STRING)
  935             if ((yylval.v.string = strdup(buf)) == NULL)
  936                 err(1, "yylex: strdup");
  937         return (token);
  938     }
  939     if (c == '\n') {
  940         yylval.lineno = file->lineno;
  941         file->lineno++;
  942     }
  943     if (c == EOF)
  944         return (0);
  945     return (c);
  946 }
  947 
  948 int
  949 check_file_secrecy(int fd, const char *fname)
  950 {
  951     struct stat st;
  952 
  953     if (fstat(fd, &st)) {
  954         log_warn("cannot stat %s", fname);
  955         return (-1);
  956     }
  957     if (st.st_uid != 0 && st.st_uid != getuid()) {
  958         log_warnx("%s: owner not root or current user", fname);
  959         return (-1);
  960     }
  961     if (st.st_mode & (S_IRWXG | S_IRWXO)) {
  962         log_warnx("%s: group/world readable/writeable", fname);
  963         return (-1);
  964     }
  965     return (0);
  966 }
  967 
  968 struct file *
  969 pushfile(const char *name, int secret)
  970 {
  971     struct file *nfile;
  972 
  973     if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
  974         log_warn("malloc");
  975         return (NULL);
  976     }
  977     if ((nfile->name = strdup(name)) == NULL) {
  978         log_warn("malloc");
  979         free(nfile);
  980         return (NULL);
  981     }
  982     if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
  983         log_warn("%s", nfile->name);
  984         free(nfile->name);
  985         free(nfile);
  986         return (NULL);
  987     } else if (secret &&
  988         check_file_secrecy(fileno(nfile->stream), nfile->name)) {
  989         fclose(nfile->stream);
  990         free(nfile->name);
  991         free(nfile);
  992         return (NULL);
  993     }
  994     nfile->lineno = 1;
  995     TAILQ_INSERT_TAIL(&files, nfile, entry);
  996     return (nfile);
  997 }
  998 
  999 int
 1000 popfile(void)
 1001 {
 1002     struct file *prev;
 1003 
 1004     if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
 1005         prev->errors += file->errors;
 1006 
 1007     TAILQ_REMOVE(&files, file, entry);
 1008     fclose(file->stream);
 1009     free(file->name);
 1010     free(file);
 1011     file = prev;
 1012     return (file ? 0 : EOF);
 1013 }
 1014 
 1015 struct ospfd_conf *
 1016 parse_config(char *filename, int opts)
 1017 {
 1018     struct sym  *sym, *next;
 1019 
 1020     if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
 1021         fatal("parse_config");
 1022     conf->opts = opts;
 1023     if (conf->opts & OSPFD_OPT_STUB_ROUTER)
 1024         conf->flags |= OSPFD_FLAG_STUB_ROUTER;
 1025 
 1026     bzero(&globaldefs, sizeof(globaldefs));
 1027     defs = &globaldefs;
 1028     TAILQ_INIT(&defs->md_list);
 1029     defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
 1030     defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
 1031     defs->hello_interval = DEFAULT_HELLO_INTERVAL;
 1032     defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
 1033     defs->metric = DEFAULT_METRIC;
 1034     defs->priority = DEFAULT_PRIORITY;
 1035 
 1036     conf->spf_delay = DEFAULT_SPF_DELAY;
 1037     conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
 1038     conf->spf_state = SPF_IDLE;
 1039 
 1040     if ((file = pushfile(filename, !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
 1041         free(conf);
 1042         return (NULL);
 1043     }
 1044     topfile = file;
 1045 
 1046     LIST_INIT(&conf->area_list);
 1047     LIST_INIT(&conf->cand_list);
 1048     SIMPLEQ_INIT(&conf->redist_list);
 1049 
 1050     yyparse();
 1051     errors = file->errors;
 1052     popfile();
 1053 
 1054     /* Free macros and check which have not been used. */
 1055     for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
 1056         next = TAILQ_NEXT(sym, entry);
 1057         if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
 1058             fprintf(stderr, "warning: macro '%s' not "
 1059                 "used\n", sym->nam);
 1060         if (!sym->persist) {
 1061             free(sym->nam);
 1062             free(sym->val);
 1063             TAILQ_REMOVE(&symhead, sym, entry);
 1064             free(sym);
 1065         }
 1066     }
 1067 
 1068     /* free global config defaults */
 1069     md_list_clr(&globaldefs.md_list);
 1070 
 1071     if (errors) {
 1072         clear_config(conf);
 1073         return (NULL);
 1074     }
 1075 
 1076     if (conf->rtr_id.s_addr == 0)
 1077         conf->rtr_id.s_addr = get_rtr_id();
 1078 
 1079     return (conf);
 1080 }
 1081 
 1082 int
 1083 symset(const char *nam, const char *val, int persist)
 1084 {
 1085     struct sym  *sym;
 1086 
 1087     for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
 1088         sym = TAILQ_NEXT(sym, entry))
 1089         ;   /* nothing */
 1090 
 1091     if (sym != NULL) {
 1092         if (sym->persist == 1)
 1093             return (0);
 1094         else {
 1095             free(sym->nam);
 1096             free(sym->val);
 1097             TAILQ_REMOVE(&symhead, sym, entry);
 1098             free(sym);
 1099         }
 1100     }
 1101     if ((sym = calloc(1, sizeof(*sym))) == NULL)
 1102         return (-1);
 1103 
 1104     sym->nam = strdup(nam);
 1105     if (sym->nam == NULL) {
 1106         free(sym);
 1107         return (-1);
 1108     }
 1109     sym->val = strdup(val);
 1110     if (sym->val == NULL) {
 1111         free(sym->nam);
 1112         free(sym);
 1113         return (-1);
 1114     }
 1115     sym->used = 0;
 1116     sym->persist = persist;
 1117     TAILQ_INSERT_TAIL(&symhead, sym, entry);
 1118     return (0);
 1119 }
 1120 
 1121 int
 1122 cmdline_symset(char *s)
 1123 {
 1124     char    *sym, *val;
 1125     int ret;
 1126     size_t  len;
 1127 
 1128     if ((val = strrchr(s, '=')) == NULL)
 1129         return (-1);
 1130 
 1131     len = strlen(s) - strlen(val) + 1;
 1132     if ((sym = malloc(len)) == NULL)
 1133         errx(1, "cmdline_symset: malloc");
 1134 
 1135     strlcpy(sym, s, len);
 1136 
 1137     ret = symset(sym, val + 1, 1);
 1138     free(sym);
 1139 
 1140     return (ret);
 1141 }
 1142 
 1143 char *
 1144 symget(const char *nam)
 1145 {
 1146     struct sym  *sym;
 1147 
 1148     TAILQ_FOREACH(sym, &symhead, entry)
 1149         if (strcmp(nam, sym->nam) == 0) {
 1150             sym->used = 1;
 1151             return (sym->val);
 1152         }
 1153     return (NULL);
 1154 }
 1155 
 1156 struct area *
 1157 conf_get_area(struct in_addr id)
 1158 {
 1159     struct area *a;
 1160 
 1161     a = area_find(conf, id);
 1162     if (a)
 1163         return (a);
 1164     a = area_new();
 1165     LIST_INSERT_HEAD(&conf->area_list, a, entry);
 1166 
 1167     a->id.s_addr = id.s_addr;
 1168 
 1169     return (a);
 1170 }
 1171 
 1172 struct iface *
 1173 conf_get_if(struct kif *kif, struct kif_addr *ka)
 1174 {
 1175     struct area *a;
 1176     struct iface    *i;
 1177 
 1178     LIST_FOREACH(a, &conf->area_list, entry)
 1179         LIST_FOREACH(i, &a->iface_list, entry)
 1180             if (i->ifindex == kif->ifindex &&
 1181                 i->addr.s_addr == ka->addr.s_addr) {
 1182                 yyerror("interface %s already configured",
 1183                     kif->ifname);
 1184                 return (NULL);
 1185             }
 1186 
 1187     i = if_new(kif, ka);
 1188     i->auth_keyid = 1;
 1189 
 1190     return (i);
 1191 }
 1192 
 1193 void
 1194 clear_config(struct ospfd_conf *xconf)
 1195 {
 1196     struct area *a;
 1197 
 1198     while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
 1199         LIST_REMOVE(a, entry);
 1200         area_del(a);
 1201     }
 1202 
 1203     free(xconf);
 1204 }
 1205 
 1206 u_int32_t
 1207 get_rtr_id(void)
 1208 {
 1209     struct ifaddrs      *ifap, *ifa;
 1210     u_int32_t        ip = 0, cur, localnet;
 1211 
 1212     localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
 1213 
 1214     if (getifaddrs(&ifap) == -1)
 1215         fatal("getifaddrs");
 1216 
 1217     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
 1218         if (ifa->ifa_addr->sa_family != AF_INET)
 1219             continue;
 1220         cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
 1221         if ((cur & localnet) == localnet)   /* skip 127/8 */
 1222             continue;
 1223         if (ntohl(cur) < ntohl(ip) || ip == 0)
 1224             ip = cur;
 1225     }
 1226     freeifaddrs(ifap);
 1227 
 1228     if (ip == 0)
 1229         fatal("router-id is 0.0.0.0");
 1230 
 1231     return (ip);
 1232 }
 1233 
 1234 int
 1235 host(const char *s, struct in_addr *addr, struct in_addr *mask)
 1236 {
 1237     struct in_addr       ina;
 1238     int          bits = 32;
 1239 
 1240     bzero(&ina, sizeof(struct in_addr));
 1241     if (strrchr(s, '/') != NULL) {
 1242         if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
 1243             return (0);
 1244     } else {
 1245         if (inet_pton(AF_INET, s, &ina) != 1)
 1246             return (0);
 1247     }
 1248 
 1249     addr->s_addr = ina.s_addr;
 1250     mask->s_addr = prefixlen2mask(bits);
 1251 
 1252     return (1);
 1253 }