"Fossies" - the Fresh Open Source Software Archive

Member "openbgpd-6.5p0/src/bgpd/config.c" (25 Apr 2019, 15182 Bytes) of package /linux/privat/openbgpd-6.5p0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "config.c" see the Fossies "Dox" file reference documentation.

    1 /*  $OpenBSD: config.c,v 1.87 2019/03/31 16:57:38 claudio Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/types.h>
   20 #include <sys/socket.h>
   21 
   22 #include <errno.h>
   23 #include <ifaddrs.h>
   24 #include <netdb.h>
   25 #include <stdlib.h>
   26 #include <stdio.h>
   27 #include <string.h>
   28 #include <unistd.h>
   29 
   30 #include "bgpd.h"
   31 #include "session.h"
   32 #include "log.h"
   33 
   34 int     host_ip(const char *, struct bgpd_addr *, u_int8_t *);
   35 void        free_networks(struct network_head *);
   36 void        free_l3vpns(struct l3vpn_head *);
   37 
   38 struct bgpd_config *
   39 new_config(void)
   40 {
   41     struct bgpd_config  *conf;
   42 
   43     if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
   44         fatal(NULL);
   45 
   46     if ((conf->as_sets = calloc(1, sizeof(struct as_set_head))) == NULL)
   47         fatal(NULL);
   48     if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
   49         fatal(NULL);
   50     if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) ==
   51         NULL)
   52         fatal(NULL);
   53     if ((conf->mrt = calloc(1, sizeof(struct mrt_head))) == NULL)
   54         fatal(NULL);
   55 
   56     /* init the various list for later */
   57     TAILQ_INIT(&conf->peers);
   58     TAILQ_INIT(&conf->networks);
   59     SIMPLEQ_INIT(&conf->l3vpns);
   60     SIMPLEQ_INIT(&conf->prefixsets);
   61     SIMPLEQ_INIT(&conf->originsets);
   62     SIMPLEQ_INIT(&conf->rde_prefixsets);
   63     SIMPLEQ_INIT(&conf->rde_originsets);
   64     RB_INIT(&conf->roa);
   65     SIMPLEQ_INIT(conf->as_sets);
   66 
   67     TAILQ_INIT(conf->filters);
   68     TAILQ_INIT(conf->listen_addrs);
   69     LIST_INIT(conf->mrt);
   70 
   71     return (conf);
   72 }
   73 
   74 void
   75 copy_config(struct bgpd_config *to, struct bgpd_config *from)
   76 {
   77     to->flags = from->flags;
   78     to->log = from->log;
   79     to->default_tableid = from->default_tableid;
   80     to->bgpid = from->bgpid;
   81     to->clusterid = from->clusterid;
   82     to->as = from->as;
   83     to->short_as = from->short_as;
   84     to->holdtime = from->holdtime;
   85     to->min_holdtime = from->min_holdtime;
   86     to->connectretry = from->connectretry;
   87     to->fib_priority = from->fib_priority;
   88 }
   89 
   90 void
   91 free_networks(struct network_head *networks)
   92 {
   93     struct network      *n;
   94 
   95     while ((n = TAILQ_FIRST(networks)) != NULL) {
   96         TAILQ_REMOVE(networks, n, entry);
   97         filterset_free(&n->net.attrset);
   98         free(n);
   99     }
  100 }
  101 
  102 void
  103 free_l3vpns(struct l3vpn_head *l3vpns)
  104 {
  105     struct l3vpn        *vpn;
  106 
  107     while ((vpn = SIMPLEQ_FIRST(l3vpns)) != NULL) {
  108         SIMPLEQ_REMOVE_HEAD(l3vpns, entry);
  109         filterset_free(&vpn->export);
  110         filterset_free(&vpn->import);
  111         free_networks(&vpn->net_l);
  112         free(vpn);
  113     }
  114 }
  115 
  116 void
  117 free_prefixsets(struct prefixset_head *psh)
  118 {
  119     struct prefixset    *ps;
  120 
  121     while (!SIMPLEQ_EMPTY(psh)) {
  122         ps = SIMPLEQ_FIRST(psh);
  123         free_prefixtree(&ps->psitems);
  124         SIMPLEQ_REMOVE_HEAD(psh, entry);
  125         free(ps);
  126     }
  127 }
  128 
  129 void
  130 free_rde_prefixsets(struct rde_prefixset_head *psh)
  131 {
  132     struct rde_prefixset    *ps;
  133 
  134     if (psh == NULL)
  135         return;
  136 
  137     while (!SIMPLEQ_EMPTY(psh)) {
  138         ps = SIMPLEQ_FIRST(psh);
  139         trie_free(&ps->th);
  140         SIMPLEQ_REMOVE_HEAD(psh, entry);
  141         free(ps);
  142     }
  143 }
  144 
  145 void
  146 free_prefixtree(struct prefixset_tree *p)
  147 {
  148     struct prefixset_item   *psi, *npsi;
  149 
  150     RB_FOREACH_SAFE(psi, prefixset_tree, p, npsi) {
  151         RB_REMOVE(prefixset_tree, p, psi);
  152         set_free(psi->set);
  153         free(psi);
  154     }
  155 }
  156 
  157 void
  158 free_config(struct bgpd_config *conf)
  159 {
  160     struct peer     *p;
  161     struct listen_addr  *la;
  162     struct mrt      *m;
  163 
  164     free_l3vpns(&conf->l3vpns);
  165     free_networks(&conf->networks);
  166     filterlist_free(conf->filters);
  167     free_prefixsets(&conf->prefixsets);
  168     free_prefixsets(&conf->originsets);
  169     free_rde_prefixsets(&conf->rde_prefixsets);
  170     free_rde_prefixsets(&conf->rde_originsets);
  171     free_prefixtree(&conf->roa);
  172     as_sets_free(conf->as_sets);
  173 
  174     while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
  175         TAILQ_REMOVE(conf->listen_addrs, la, entry);
  176         free(la);
  177     }
  178     free(conf->listen_addrs);
  179 
  180     while ((m = LIST_FIRST(conf->mrt)) != NULL) {
  181         LIST_REMOVE(m, entry);
  182         free(m);
  183     }
  184     free(conf->mrt);
  185 
  186     while ((p = TAILQ_FIRST(&conf->peers)) != NULL) {
  187         TAILQ_REMOVE(&conf->peers, p, entry);
  188         free(p);
  189     }
  190 
  191     free(conf->csock);
  192     free(conf->rcsock);
  193 
  194     free(conf);
  195 }
  196 
  197 void
  198 merge_config(struct bgpd_config *xconf, struct bgpd_config *conf)
  199 {
  200     struct listen_addr  *nla, *ola, *next;
  201     struct network      *n;
  202     struct peer     *p, *np;
  203 
  204     /*
  205      * merge the freshly parsed conf into the running xconf
  206      */
  207     if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
  208         conf->clusterid = conf->bgpid;
  209 
  210     /* adjust FIB priority if changed */
  211     /* if xconf is uninitialized we get RTP_NONE */
  212     if (xconf->fib_priority != conf->fib_priority) {
  213         kr_fib_decouple_all(xconf->fib_priority);
  214         kr_fib_update_prio_all(conf->fib_priority);
  215         kr_fib_couple_all(conf->fib_priority);
  216     }
  217 
  218     /* take over the easy config changes */
  219     copy_config(xconf, conf);
  220 
  221     /* clear old control sockets and use new */
  222     free(xconf->csock);
  223     free(xconf->rcsock);
  224     xconf->csock = conf->csock;
  225     xconf->rcsock = conf->rcsock;
  226     /* set old one to NULL so we don't double free */
  227     conf->csock = NULL;
  228     conf->rcsock = NULL;
  229 
  230     /* clear all current filters and take over the new ones */
  231     filterlist_free(xconf->filters);
  232     xconf->filters = conf->filters;
  233     conf->filters = NULL;
  234 
  235     /* merge mrt config */
  236     mrt_mergeconfig(xconf->mrt, conf->mrt);
  237 
  238     /* switch the roa, first remove the old one */
  239     free_prefixtree(&xconf->roa);
  240     /* then move the RB tree root */
  241     RB_ROOT(&xconf->roa) = RB_ROOT(&conf->roa);
  242     RB_ROOT(&conf->roa) = NULL;
  243 
  244     /* switch the prefixsets, first remove the old ones */
  245     free_prefixsets(&xconf->prefixsets);
  246     SIMPLEQ_CONCAT(&xconf->prefixsets, &conf->prefixsets);
  247 
  248     /* switch the originsets, first remove the old ones */
  249     free_prefixsets(&xconf->originsets);
  250     SIMPLEQ_CONCAT(&xconf->originsets, &conf->originsets);
  251 
  252     /* switch the as_sets, first remove the old ones */
  253     as_sets_free(xconf->as_sets);
  254     xconf->as_sets = conf->as_sets;
  255     conf->as_sets = NULL;
  256 
  257     /* switch the network statements, but first remove the old ones */
  258     free_networks(&xconf->networks);
  259     while ((n = TAILQ_FIRST(&conf->networks)) != NULL) {
  260         TAILQ_REMOVE(&conf->networks, n, entry);
  261         TAILQ_INSERT_TAIL(&xconf->networks, n, entry);
  262     }
  263 
  264     /* switch the l3vpn configs, first remove the old ones */
  265     free_l3vpns(&xconf->l3vpns);
  266     SIMPLEQ_CONCAT(&xconf->l3vpns, &conf->l3vpns);
  267 
  268     /*
  269      * merge new listeners:
  270      * -flag all existing ones as to be deleted
  271      * -those that are in both new and old: flag to keep
  272      * -new ones get inserted and flagged as to reinit
  273      * -remove all that are still flagged for deletion
  274      */
  275 
  276     TAILQ_FOREACH(nla, xconf->listen_addrs, entry)
  277         nla->reconf = RECONF_DELETE;
  278 
  279     /* no new listeners? preserve default ones */
  280     if (TAILQ_EMPTY(conf->listen_addrs))
  281         TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
  282             if (ola->flags & DEFAULT_LISTENER)
  283                 ola->reconf = RECONF_KEEP;
  284     /* else loop over listeners and merge configs */
  285     for (nla = TAILQ_FIRST(conf->listen_addrs); nla != NULL; nla = next) {
  286         next = TAILQ_NEXT(nla, entry);
  287 
  288         TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
  289             if (!memcmp(&nla->sa, &ola->sa, sizeof(nla->sa)))
  290                 break;
  291 
  292         if (ola == NULL) {
  293             /* new listener, copy over */
  294             TAILQ_REMOVE(conf->listen_addrs, nla, entry);
  295             TAILQ_INSERT_TAIL(xconf->listen_addrs, nla, entry);
  296             nla->reconf = RECONF_REINIT;
  297         } else      /* exists, just flag */
  298             ola->reconf = RECONF_KEEP;
  299     }
  300     /* finally clean up the original list and remove all stale entires */
  301     for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL; nla = next) {
  302         next = TAILQ_NEXT(nla, entry);
  303         if (nla->reconf == RECONF_DELETE) {
  304             TAILQ_REMOVE(xconf->listen_addrs, nla, entry);
  305             free(nla);
  306         }
  307     }
  308 
  309     /*
  310      * merge peers:
  311      * - need to know which peers are new, replaced and removed
  312      * - first mark all new peers as RECONF_REINIT
  313      * - walk over old peers and check if there is a corresponding new
  314      *   peer if so mark it RECONF_KEEP. Remove all old peers.
  315      * - swap lists (old peer list is actually empty).
  316      */
  317     TAILQ_FOREACH(p, &conf->peers, entry)
  318         p->reconf_action = RECONF_REINIT;
  319     while ((p = TAILQ_FIRST(&xconf->peers)) != NULL) {
  320         np = getpeerbyid(conf, p->conf.id);
  321         if (np != NULL)
  322             np->reconf_action = RECONF_KEEP;
  323 
  324         TAILQ_REMOVE(&xconf->peers, p, entry);
  325         free(p);
  326     }
  327     TAILQ_CONCAT(&xconf->peers, &conf->peers, entry);
  328 
  329     /* conf is merged so free it */
  330     free_config(conf);
  331 }
  332 
  333 u_int32_t
  334 get_bgpid(void)
  335 {
  336     struct ifaddrs      *ifap, *ifa;
  337     u_int32_t        ip = 0, cur, localnet;
  338 
  339     localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
  340 
  341     if (getifaddrs(&ifap) == -1)
  342         fatal("getifaddrs");
  343 
  344     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
  345         if (ifa->ifa_addr->sa_family != AF_INET)
  346             continue;
  347         cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
  348         if ((cur & localnet) == localnet)   /* skip 127/8 */
  349             continue;
  350         if (ntohl(cur) > ntohl(ip))
  351             ip = cur;
  352     }
  353     freeifaddrs(ifap);
  354 
  355     return (ip);
  356 }
  357 
  358 int
  359 host(const char *s, struct bgpd_addr *h, u_int8_t *len)
  360 {
  361     int          mask = 128;
  362     char            *p, *ps;
  363     const char      *errstr;
  364 
  365     if ((ps = strdup(s)) == NULL)
  366         fatal("%s: strdup", __func__);
  367 
  368     if ((p = strrchr(ps, '/')) != NULL) {
  369         mask = strtonum(p+1, 0, 128, &errstr);
  370         if (errstr) {
  371             log_warnx("prefixlen is %s: %s", errstr, p);
  372             free(ps);
  373             return (0);
  374         }
  375         p[0] = '\0';
  376     }
  377 
  378     bzero(h, sizeof(*h));
  379 
  380     if (host_ip(ps, h, len) == 0) {
  381         free(ps);
  382         return (0);
  383     }
  384 
  385     if (p != NULL)
  386         *len = mask;
  387 
  388     free(ps);
  389     return (1);
  390 }
  391 
  392 int
  393 host_ip(const char *s, struct bgpd_addr *h, u_int8_t *len)
  394 {
  395     struct addrinfo      hints, *res;
  396     int          bits;
  397 
  398     bzero(&hints, sizeof(hints));
  399     hints.ai_family = AF_UNSPEC;
  400     hints.ai_socktype = SOCK_DGRAM; /*dummy*/
  401     hints.ai_flags = AI_NUMERICHOST;
  402     if (getaddrinfo(s, NULL, &hints, &res) == 0) {
  403         *len = res->ai_family == AF_INET6 ? 128 : 32;
  404         sa2addr(res->ai_addr, h, NULL);
  405         freeaddrinfo(res);
  406     } else {    /* ie. for 10/8 parsing */
  407         if ((bits = inet_net_pton(AF_INET, s, &h->v4, sizeof(h->v4))) == -1)
  408             return (0);
  409         *len = bits;
  410         h->aid = AID_INET;
  411     }
  412 
  413     return (1);
  414 }
  415 
  416 int
  417 prepare_listeners(struct bgpd_config *conf)
  418 {
  419     struct listen_addr  *la, *next;
  420     int          opt = 1;
  421     int          r = 0;
  422 
  423     if (TAILQ_EMPTY(conf->listen_addrs)) {
  424         if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
  425             fatal("setup_listeners calloc");
  426         la->fd = -1;
  427         la->flags = DEFAULT_LISTENER;
  428         la->reconf = RECONF_REINIT;
  429         la->sa_len = sizeof(struct sockaddr_in);
  430         ((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
  431         ((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
  432             htonl(INADDR_ANY);
  433         ((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT);
  434         TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
  435 
  436         if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
  437             fatal("setup_listeners calloc");
  438         la->fd = -1;
  439         la->flags = DEFAULT_LISTENER;
  440         la->reconf = RECONF_REINIT;
  441         la->sa_len = sizeof(struct sockaddr_in6);
  442         ((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
  443         ((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT);
  444         TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
  445     }
  446 
  447     for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) {
  448         next = TAILQ_NEXT(la, entry);
  449         if (la->reconf != RECONF_REINIT)
  450             continue;
  451 
  452         if ((la->fd = socket(la->sa.ss_family,
  453             SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
  454             IPPROTO_TCP)) == -1) {
  455             if (la->flags & DEFAULT_LISTENER && (errno ==
  456                 EAFNOSUPPORT || errno == EPROTONOSUPPORT)) {
  457                 TAILQ_REMOVE(conf->listen_addrs, la, entry);
  458                 free(la);
  459                 continue;
  460             } else
  461                 fatal("socket");
  462         }
  463 
  464         opt = 1;
  465         if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR,
  466             &opt, sizeof(opt)) == -1)
  467             fatal("setsockopt SO_REUSEADDR");
  468 
  469 #ifdef IPV6_V6ONLY
  470         if (la->sa.ss_family == AF_INET6) {
  471             opt = 1;
  472             if (setsockopt(la->fd, IPPROTO_IPV6, IPV6_V6ONLY,
  473                 &opt, sizeof(opt)) == -1)
  474                 fatal("setsockopt IPV6_V6ONLY");
  475         }
  476 #endif
  477 
  478         if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa_len) ==
  479             -1) {
  480             switch (la->sa.ss_family) {
  481             case AF_INET:
  482                 log_warn("cannot bind to %s:%u",
  483                     log_sockaddr((struct sockaddr *)&la->sa,
  484                     la->sa_len), ntohs(((struct sockaddr_in *)
  485                     &la->sa)->sin_port));
  486                 break;
  487             case AF_INET6:
  488                 log_warn("cannot bind to [%s]:%u",
  489                     log_sockaddr((struct sockaddr *)&la->sa,
  490                     la->sa_len), ntohs(((struct sockaddr_in6 *)
  491                     &la->sa)->sin6_port));
  492                 break;
  493             default:
  494                 log_warn("cannot bind to %s",
  495                     log_sockaddr((struct sockaddr *)&la->sa,
  496                     la->sa_len));
  497                 break;
  498             }
  499             close(la->fd);
  500             TAILQ_REMOVE(conf->listen_addrs, la, entry);
  501             free(la);
  502             r = -1;
  503             continue;
  504         }
  505     }
  506 
  507     return (r);
  508 }
  509 
  510 void
  511 copy_filterset(struct filter_set_head *source, struct filter_set_head *dest)
  512 {
  513     struct filter_set   *s, *t;
  514 
  515     if (source == NULL)
  516         return;
  517 
  518     TAILQ_FOREACH(s, source, entry) {
  519         if ((t = malloc(sizeof(struct filter_set))) == NULL)
  520             fatal(NULL);
  521         memcpy(t, s, sizeof(struct filter_set));
  522         TAILQ_INSERT_TAIL(dest, t, entry);
  523     }
  524 }
  525 
  526 void
  527 expand_networks(struct bgpd_config *c)
  528 {
  529     struct network      *n, *m, *tmp;
  530     struct network_head *nw = &c->networks;
  531     struct prefixset    *ps;
  532     struct prefixset_item   *psi;
  533 
  534     TAILQ_FOREACH_SAFE(n, nw, entry, tmp) {
  535         if (n->net.type == NETWORK_PREFIXSET) {
  536             TAILQ_REMOVE(nw, n, entry);
  537             if ((ps = find_prefixset(n->net.psname, &c->prefixsets))
  538                 == NULL)
  539                 fatal("%s: prefixset %s not found", __func__,
  540                     n->net.psname);
  541             RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
  542                 if ((m = calloc(1, sizeof(struct network)))
  543                     == NULL)
  544                     fatal(NULL);
  545                 memcpy(&m->net.prefix, &psi->p.addr,
  546                     sizeof(m->net.prefix));
  547                 m->net.prefixlen = psi->p.len;
  548                 TAILQ_INIT(&m->net.attrset);
  549                 copy_filterset(&n->net.attrset,
  550                     &m->net.attrset);
  551                 TAILQ_INSERT_TAIL(nw, m, entry);
  552             }
  553             filterset_free(&n->net.attrset);
  554             free(n);
  555         }
  556     }
  557 }
  558 
  559 int
  560 prefixset_cmp(struct prefixset_item *a, struct prefixset_item *b)
  561 {
  562     int i;
  563 
  564     if (a->p.addr.aid < b->p.addr.aid)
  565         return (-1);
  566     if (a->p.addr.aid > b->p.addr.aid)
  567         return (1);
  568 
  569     switch (a->p.addr.aid) {
  570     case AID_INET:
  571         if (ntohl(a->p.addr.v4.s_addr) < ntohl(b->p.addr.v4.s_addr))
  572             return (-1);
  573         if (ntohl(a->p.addr.v4.s_addr) > ntohl(b->p.addr.v4.s_addr))
  574             return (1);
  575         break;
  576     case AID_INET6:
  577         i = memcmp(&a->p.addr.v6, &b->p.addr.v6,
  578             sizeof(struct in6_addr));
  579         if (i > 0)
  580             return (1);
  581         if (i < 0)
  582             return (-1);
  583         break;
  584     default:
  585         fatalx("%s: unknown af", __func__);
  586     }
  587     if (a->p.len < b->p.len)
  588         return (-1);
  589     if (a->p.len > b->p.len)
  590         return (1);
  591     if (a->p.len_min < b->p.len_min)
  592         return (-1);
  593     if (a->p.len_min > b->p.len_min)
  594         return (1);
  595     if (a->p.len_max < b->p.len_max)
  596         return (-1);
  597     if (a->p.len_max > b->p.len_max)
  598         return (1);
  599     return (0);
  600 }
  601 
  602 RB_GENERATE(prefixset_tree, prefixset_item, entry, prefixset_cmp);