1*6c15f943Sclaudio /* $OpenBSD: config.c,v 1.113 2024/12/13 19:21:03 claudio Exp $ */ 2a16c0992Shenning 3a16c0992Shenning /* 447ae44cbShenning * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> 5a16c0992Shenning * 6a16c0992Shenning * Permission to use, copy, modify, and distribute this software for any 7a16c0992Shenning * purpose with or without fee is hereby granted, provided that the above 8a16c0992Shenning * copyright notice and this permission notice appear in all copies. 9a16c0992Shenning * 10a16c0992Shenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a16c0992Shenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a16c0992Shenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a16c0992Shenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a16c0992Shenning * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a16c0992Shenning * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a16c0992Shenning * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a16c0992Shenning */ 18a16c0992Shenning 19a16c0992Shenning #include <sys/types.h> 20a16c0992Shenning #include <sys/socket.h> 21a16c0992Shenning 22a16c0992Shenning #include <errno.h> 23a16c0992Shenning #include <ifaddrs.h> 2465fe1613Shenning #include <netdb.h> 2544f7a62cSclaudio #include <stddef.h> 26a16c0992Shenning #include <stdlib.h> 278d7b500cSbenno #include <stdio.h> 28096179b2Shenning #include <string.h> 29a16c0992Shenning #include <unistd.h> 30a16c0992Shenning 31a16c0992Shenning #include "bgpd.h" 329d3ea286Shenning #include "session.h" 335e3f6f95Sbenno #include "log.h" 34a16c0992Shenning 3539386878Sclaudio int host_ip(const char *, struct bgpd_addr *, uint8_t *); 36e3b8c3f4Sclaudio void free_networks(struct network_head *); 3744f7a62cSclaudio void free_flowspecs(struct flowspec_tree *); 38a16c0992Shenning 39d288d268Sclaudio struct bgpd_config * 40d288d268Sclaudio new_config(void) 41d288d268Sclaudio { 42d288d268Sclaudio struct bgpd_config *conf; 43d288d268Sclaudio 44d288d268Sclaudio if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) 45d288d268Sclaudio fatal(NULL); 46d288d268Sclaudio 47d288d268Sclaudio if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL) 48d288d268Sclaudio fatal(NULL); 49d288d268Sclaudio if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) == 50d288d268Sclaudio NULL) 51d288d268Sclaudio fatal(NULL); 52d288d268Sclaudio if ((conf->mrt = calloc(1, sizeof(struct mrt_head))) == NULL) 53d288d268Sclaudio fatal(NULL); 54d288d268Sclaudio 55d288d268Sclaudio /* init the various list for later */ 567876190cSclaudio RB_INIT(&conf->peers); 57d288d268Sclaudio TAILQ_INIT(&conf->networks); 5844f7a62cSclaudio RB_INIT(&conf->flowspecs); 594e0c4e97Sclaudio SIMPLEQ_INIT(&conf->l3vpns); 606f1dba6eSclaudio SIMPLEQ_INIT(&conf->prefixsets); 616f1dba6eSclaudio SIMPLEQ_INIT(&conf->originsets); 62e8d21d8aSclaudio SIMPLEQ_INIT(&conf->rde_prefixsets); 63e8d21d8aSclaudio SIMPLEQ_INIT(&conf->rde_originsets); 646f1dba6eSclaudio RB_INIT(&conf->roa); 65ff84f55eSclaudio RB_INIT(&conf->aspa); 66965dc109Sclaudio SIMPLEQ_INIT(&conf->as_sets); 67bd9df44eSclaudio SIMPLEQ_INIT(&conf->rtrs); 68d288d268Sclaudio 69d288d268Sclaudio TAILQ_INIT(conf->filters); 70d288d268Sclaudio TAILQ_INIT(conf->listen_addrs); 71d288d268Sclaudio LIST_INIT(conf->mrt); 72d288d268Sclaudio 73d288d268Sclaudio return (conf); 74d288d268Sclaudio } 75d288d268Sclaudio 76d288d268Sclaudio void 77e8d21d8aSclaudio copy_config(struct bgpd_config *to, struct bgpd_config *from) 78e8d21d8aSclaudio { 79e8d21d8aSclaudio to->flags = from->flags; 80e8d21d8aSclaudio to->log = from->log; 81e8d21d8aSclaudio to->default_tableid = from->default_tableid; 82e8d21d8aSclaudio to->bgpid = from->bgpid; 83e8d21d8aSclaudio to->clusterid = from->clusterid; 84e8d21d8aSclaudio to->as = from->as; 85e8d21d8aSclaudio to->short_as = from->short_as; 86e8d21d8aSclaudio to->holdtime = from->holdtime; 87e8d21d8aSclaudio to->min_holdtime = from->min_holdtime; 88*6c15f943Sclaudio to->staletime = from->staletime; 89e8d21d8aSclaudio to->connectretry = from->connectretry; 90e8d21d8aSclaudio to->fib_priority = from->fib_priority; 9189ee02f7Sclaudio to->filtered_in_locrib = from->filtered_in_locrib; 92e8d21d8aSclaudio } 93e8d21d8aSclaudio 94e8d21d8aSclaudio void 958bf72ef0Sclaudio network_free(struct network *n) 968bf72ef0Sclaudio { 978bf72ef0Sclaudio rtlabel_unref(n->net.rtlabel); 988bf72ef0Sclaudio filterset_free(&n->net.attrset); 998bf72ef0Sclaudio free(n); 1008bf72ef0Sclaudio } 1018bf72ef0Sclaudio 1028bf72ef0Sclaudio void 103e3b8c3f4Sclaudio free_networks(struct network_head *networks) 104e3b8c3f4Sclaudio { 105e3b8c3f4Sclaudio struct network *n; 106e3b8c3f4Sclaudio 107e3b8c3f4Sclaudio while ((n = TAILQ_FIRST(networks)) != NULL) { 108e3b8c3f4Sclaudio TAILQ_REMOVE(networks, n, entry); 1098bf72ef0Sclaudio network_free(n); 110e3b8c3f4Sclaudio } 111e3b8c3f4Sclaudio } 112e3b8c3f4Sclaudio 11344f7a62cSclaudio struct flowspec_config * 11444f7a62cSclaudio flowspec_alloc(uint8_t aid, int len) 11544f7a62cSclaudio { 11644f7a62cSclaudio struct flowspec_config *conf; 11744f7a62cSclaudio struct flowspec *flow; 11844f7a62cSclaudio 11944f7a62cSclaudio flow = malloc(FLOWSPEC_SIZE + len); 12044f7a62cSclaudio if (flow == NULL) 12144f7a62cSclaudio return NULL; 12244f7a62cSclaudio memset(flow, 0, FLOWSPEC_SIZE); 12344f7a62cSclaudio 12444f7a62cSclaudio conf = calloc(1, sizeof(*conf)); 12544f7a62cSclaudio if (conf == NULL) { 12644f7a62cSclaudio free(flow); 12744f7a62cSclaudio return NULL; 12844f7a62cSclaudio } 12944f7a62cSclaudio 13044f7a62cSclaudio conf->flow = flow; 13144f7a62cSclaudio TAILQ_INIT(&conf->attrset); 13244f7a62cSclaudio flow->len = len; 13344f7a62cSclaudio flow->aid = aid; 13444f7a62cSclaudio 13544f7a62cSclaudio return conf; 13644f7a62cSclaudio } 13744f7a62cSclaudio 13844f7a62cSclaudio void 13944f7a62cSclaudio flowspec_free(struct flowspec_config *f) 14044f7a62cSclaudio { 14144f7a62cSclaudio filterset_free(&f->attrset); 14244f7a62cSclaudio free(f->flow); 14344f7a62cSclaudio free(f); 14444f7a62cSclaudio } 14544f7a62cSclaudio 14644f7a62cSclaudio void 14744f7a62cSclaudio free_flowspecs(struct flowspec_tree *flowspecs) 14844f7a62cSclaudio { 14944f7a62cSclaudio struct flowspec_config *f, *nf; 15044f7a62cSclaudio 15144f7a62cSclaudio RB_FOREACH_SAFE(f, flowspec_tree, flowspecs, nf) { 15244f7a62cSclaudio RB_REMOVE(flowspec_tree, flowspecs, f); 15344f7a62cSclaudio flowspec_free(f); 15444f7a62cSclaudio } 15544f7a62cSclaudio } 15644f7a62cSclaudio 157e3b8c3f4Sclaudio void 1584e0c4e97Sclaudio free_l3vpns(struct l3vpn_head *l3vpns) 159d288d268Sclaudio { 1604e0c4e97Sclaudio struct l3vpn *vpn; 161e3b8c3f4Sclaudio 1624e0c4e97Sclaudio while ((vpn = SIMPLEQ_FIRST(l3vpns)) != NULL) { 1634e0c4e97Sclaudio SIMPLEQ_REMOVE_HEAD(l3vpns, entry); 1644e0c4e97Sclaudio filterset_free(&vpn->export); 1654e0c4e97Sclaudio filterset_free(&vpn->import); 1664e0c4e97Sclaudio free_networks(&vpn->net_l); 1674e0c4e97Sclaudio free(vpn); 168e3b8c3f4Sclaudio } 169e3b8c3f4Sclaudio } 170e3b8c3f4Sclaudio 171e3b8c3f4Sclaudio void 172441aaadcSbenno free_prefixsets(struct prefixset_head *psh) 173441aaadcSbenno { 174441aaadcSbenno struct prefixset *ps; 175441aaadcSbenno 176441aaadcSbenno while (!SIMPLEQ_EMPTY(psh)) { 177441aaadcSbenno ps = SIMPLEQ_FIRST(psh); 1786aa533f4Sclaudio free_roatree(&ps->roaitems); 1796f1dba6eSclaudio free_prefixtree(&ps->psitems); 180441aaadcSbenno SIMPLEQ_REMOVE_HEAD(psh, entry); 181441aaadcSbenno free(ps); 182441aaadcSbenno } 1836f1dba6eSclaudio } 1846f1dba6eSclaudio 1856f1dba6eSclaudio void 186e8d21d8aSclaudio free_rde_prefixsets(struct rde_prefixset_head *psh) 187e8d21d8aSclaudio { 188e8d21d8aSclaudio struct rde_prefixset *ps; 189e8d21d8aSclaudio 190e8d21d8aSclaudio if (psh == NULL) 191e8d21d8aSclaudio return; 192e8d21d8aSclaudio 193e8d21d8aSclaudio while (!SIMPLEQ_EMPTY(psh)) { 194e8d21d8aSclaudio ps = SIMPLEQ_FIRST(psh); 195e8d21d8aSclaudio trie_free(&ps->th); 196e8d21d8aSclaudio SIMPLEQ_REMOVE_HEAD(psh, entry); 197e8d21d8aSclaudio free(ps); 198e8d21d8aSclaudio } 199e8d21d8aSclaudio } 200e8d21d8aSclaudio 201e8d21d8aSclaudio void 2026f1dba6eSclaudio free_prefixtree(struct prefixset_tree *p) 2036f1dba6eSclaudio { 2046f1dba6eSclaudio struct prefixset_item *psi, *npsi; 2056f1dba6eSclaudio 2066f1dba6eSclaudio RB_FOREACH_SAFE(psi, prefixset_tree, p, npsi) { 2076f1dba6eSclaudio RB_REMOVE(prefixset_tree, p, psi); 2086f1dba6eSclaudio free(psi); 2096f1dba6eSclaudio } 210441aaadcSbenno } 211441aaadcSbenno 212441aaadcSbenno void 2136aa533f4Sclaudio free_roatree(struct roa_tree *r) 2146aa533f4Sclaudio { 2156aa533f4Sclaudio struct roa *roa, *nroa; 2166aa533f4Sclaudio 2176aa533f4Sclaudio RB_FOREACH_SAFE(roa, roa_tree, r, nroa) { 2186aa533f4Sclaudio RB_REMOVE(roa_tree, r, roa); 2196aa533f4Sclaudio free(roa); 2206aa533f4Sclaudio } 2216aa533f4Sclaudio } 2226aa533f4Sclaudio 2236aa533f4Sclaudio void 224ff84f55eSclaudio free_aspa(struct aspa_set *aspa) 225ff84f55eSclaudio { 226ff84f55eSclaudio if (aspa == NULL) 227ff84f55eSclaudio return; 228ff84f55eSclaudio free(aspa->tas); 229ff84f55eSclaudio free(aspa); 230ff84f55eSclaudio } 231ff84f55eSclaudio 232ff84f55eSclaudio void 233ff84f55eSclaudio free_aspatree(struct aspa_tree *a) 234ff84f55eSclaudio { 235ff84f55eSclaudio struct aspa_set *aspa, *naspa; 236ff84f55eSclaudio 237ff84f55eSclaudio RB_FOREACH_SAFE(aspa, aspa_tree, a, naspa) { 238ff84f55eSclaudio RB_REMOVE(aspa_tree, a, aspa); 239ff84f55eSclaudio free_aspa(aspa); 240ff84f55eSclaudio } 241ff84f55eSclaudio } 242ff84f55eSclaudio 243ff84f55eSclaudio void 244bd9df44eSclaudio free_rtrs(struct rtr_config_head *rh) 245bd9df44eSclaudio { 246bd9df44eSclaudio struct rtr_config *r; 247bd9df44eSclaudio 248bd9df44eSclaudio while (!SIMPLEQ_EMPTY(rh)) { 249bd9df44eSclaudio r = SIMPLEQ_FIRST(rh); 250bd9df44eSclaudio SIMPLEQ_REMOVE_HEAD(rh, entry); 251bd9df44eSclaudio free(r); 252bd9df44eSclaudio } 253bd9df44eSclaudio } 254bd9df44eSclaudio 255bd9df44eSclaudio void 256e3b8c3f4Sclaudio free_config(struct bgpd_config *conf) 257e3b8c3f4Sclaudio { 2587876190cSclaudio struct peer *p, *next; 259d288d268Sclaudio struct listen_addr *la; 260d288d268Sclaudio struct mrt *m; 261d288d268Sclaudio 2624e0c4e97Sclaudio free_l3vpns(&conf->l3vpns); 263e3b8c3f4Sclaudio free_networks(&conf->networks); 26444f7a62cSclaudio free_flowspecs(&conf->flowspecs); 265d288d268Sclaudio filterlist_free(conf->filters); 2666f1dba6eSclaudio free_prefixsets(&conf->prefixsets); 2676f1dba6eSclaudio free_prefixsets(&conf->originsets); 268e8d21d8aSclaudio free_rde_prefixsets(&conf->rde_prefixsets); 269e8d21d8aSclaudio free_rde_prefixsets(&conf->rde_originsets); 270965dc109Sclaudio as_sets_free(&conf->as_sets); 2716aa533f4Sclaudio free_roatree(&conf->roa); 272ff84f55eSclaudio free_aspatree(&conf->aspa); 273bd9df44eSclaudio free_rtrs(&conf->rtrs); 274d288d268Sclaudio 275d288d268Sclaudio while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { 276d288d268Sclaudio TAILQ_REMOVE(conf->listen_addrs, la, entry); 277d288d268Sclaudio free(la); 278d288d268Sclaudio } 279d288d268Sclaudio free(conf->listen_addrs); 280d288d268Sclaudio 281d288d268Sclaudio while ((m = LIST_FIRST(conf->mrt)) != NULL) { 282d288d268Sclaudio LIST_REMOVE(m, entry); 283d288d268Sclaudio free(m); 284d288d268Sclaudio } 285d288d268Sclaudio free(conf->mrt); 286d288d268Sclaudio 2877876190cSclaudio RB_FOREACH_SAFE(p, peer_head, &conf->peers, next) { 2887876190cSclaudio RB_REMOVE(peer_head, &conf->peers, p); 28982fc6237Sclaudio free(p); 29082fc6237Sclaudio } 29182fc6237Sclaudio 292d288d268Sclaudio free(conf->csock); 293d288d268Sclaudio free(conf->rcsock); 294d288d268Sclaudio 295d288d268Sclaudio free(conf); 296d288d268Sclaudio } 297d288d268Sclaudio 298e8d21d8aSclaudio void 29982fc6237Sclaudio merge_config(struct bgpd_config *xconf, struct bgpd_config *conf) 300a16c0992Shenning { 30147ae44cbShenning struct listen_addr *nla, *ola, *next; 3027876190cSclaudio struct peer *p, *np, *nextp; 30344f7a62cSclaudio struct flowspec_config *f, *nextf, *xf; 30447ae44cbShenning 30547ae44cbShenning /* 30647ae44cbShenning * merge the freshly parsed conf into the running xconf 30747ae44cbShenning */ 30827e1f569Sclaudio 309c1652e54Sclaudio /* adjust FIB priority if changed */ 310d7aaadcdSmmcc /* if xconf is uninitialized we get RTP_NONE */ 311d288d268Sclaudio if (xconf->fib_priority != conf->fib_priority) { 312859a8563Sclaudio kr_fib_decouple_all(); 313859a8563Sclaudio kr_fib_prio_set(conf->fib_priority); 314859a8563Sclaudio kr_fib_couple_all(); 315c1652e54Sclaudio } 316c1652e54Sclaudio 317d288d268Sclaudio /* take over the easy config changes */ 318e8d21d8aSclaudio copy_config(xconf, conf); 319a2828004Shenning 320d288d268Sclaudio /* clear old control sockets and use new */ 321d288d268Sclaudio free(xconf->csock); 322d288d268Sclaudio free(xconf->rcsock); 323d288d268Sclaudio xconf->csock = conf->csock; 324d288d268Sclaudio xconf->rcsock = conf->rcsock; 325d288d268Sclaudio /* set old one to NULL so we don't double free */ 326d288d268Sclaudio conf->csock = NULL; 327d288d268Sclaudio conf->rcsock = NULL; 32847ae44cbShenning 329d288d268Sclaudio /* clear all current filters and take over the new ones */ 330d288d268Sclaudio filterlist_free(xconf->filters); 331d288d268Sclaudio xconf->filters = conf->filters; 332d288d268Sclaudio conf->filters = NULL; 333d288d268Sclaudio 334043e486bSclaudio /* merge mrt config */ 335043e486bSclaudio mrt_mergeconfig(xconf->mrt, conf->mrt); 336043e486bSclaudio 3376f1dba6eSclaudio /* switch the roa, first remove the old one */ 3386aa533f4Sclaudio free_roatree(&xconf->roa); 3396f1dba6eSclaudio /* then move the RB tree root */ 3406f1dba6eSclaudio RB_ROOT(&xconf->roa) = RB_ROOT(&conf->roa); 3416f1dba6eSclaudio RB_ROOT(&conf->roa) = NULL; 342a8e18e82Sclaudio 343ff84f55eSclaudio /* switch the aspa, first remove the old one */ 344ff84f55eSclaudio free_aspatree(&xconf->aspa); 345ff84f55eSclaudio /* then move the RB tree root */ 346ff84f55eSclaudio RB_ROOT(&xconf->aspa) = RB_ROOT(&conf->aspa); 347ff84f55eSclaudio RB_ROOT(&conf->aspa) = NULL; 348ff84f55eSclaudio 349bd9df44eSclaudio /* switch the rtr_configs, first remove the old ones */ 350bd9df44eSclaudio free_rtrs(&xconf->rtrs); 351bd9df44eSclaudio SIMPLEQ_CONCAT(&xconf->rtrs, &conf->rtrs); 352bd9df44eSclaudio 3536f1dba6eSclaudio /* switch the prefixsets, first remove the old ones */ 3546f1dba6eSclaudio free_prefixsets(&xconf->prefixsets); 3556f1dba6eSclaudio SIMPLEQ_CONCAT(&xconf->prefixsets, &conf->prefixsets); 3566f1dba6eSclaudio 3576f1dba6eSclaudio /* switch the originsets, first remove the old ones */ 3586f1dba6eSclaudio free_prefixsets(&xconf->originsets); 3596f1dba6eSclaudio SIMPLEQ_CONCAT(&xconf->originsets, &conf->originsets); 360502ece1dSclaudio 361a8e18e82Sclaudio /* switch the as_sets, first remove the old ones */ 362965dc109Sclaudio as_sets_free(&xconf->as_sets); 363965dc109Sclaudio SIMPLEQ_CONCAT(&xconf->as_sets, &conf->as_sets); 364a8e18e82Sclaudio 365d288d268Sclaudio /* switch the network statements, but first remove the old ones */ 366e3b8c3f4Sclaudio free_networks(&xconf->networks); 36731d99e09Sbket TAILQ_CONCAT(&xconf->networks, &conf->networks, entry); 368d288d268Sclaudio 36944f7a62cSclaudio /* 37044f7a62cSclaudio * Merge the flowspec statements. Mark the old ones for deletion 37144f7a62cSclaudio * which happens when the flowspec is sent to the RDE. 37244f7a62cSclaudio */ 37344f7a62cSclaudio RB_FOREACH(f, flowspec_tree, &xconf->flowspecs) 37444f7a62cSclaudio f->reconf_action = RECONF_DELETE; 37544f7a62cSclaudio 37644f7a62cSclaudio RB_FOREACH_SAFE(f, flowspec_tree, &conf->flowspecs, nextf) { 37744f7a62cSclaudio RB_REMOVE(flowspec_tree, &conf->flowspecs, f); 37844f7a62cSclaudio 37944f7a62cSclaudio xf = RB_INSERT(flowspec_tree, &xconf->flowspecs, f); 38044f7a62cSclaudio if (xf != NULL) { 38144f7a62cSclaudio filterset_free(&xf->attrset); 38244f7a62cSclaudio filterset_move(&f->attrset, &xf->attrset); 38344f7a62cSclaudio flowspec_free(f); 38444f7a62cSclaudio xf->reconf_action = RECONF_KEEP; 38544f7a62cSclaudio } else 38644f7a62cSclaudio f->reconf_action = RECONF_KEEP; 38744f7a62cSclaudio } 38844f7a62cSclaudio 3894e0c4e97Sclaudio /* switch the l3vpn configs, first remove the old ones */ 3904e0c4e97Sclaudio free_l3vpns(&xconf->l3vpns); 3914e0c4e97Sclaudio SIMPLEQ_CONCAT(&xconf->l3vpns, &conf->l3vpns); 392e3b8c3f4Sclaudio 39347ae44cbShenning /* 39447ae44cbShenning * merge new listeners: 39547ae44cbShenning * -flag all existing ones as to be deleted 39647ae44cbShenning * -those that are in both new and old: flag to keep 39747ae44cbShenning * -new ones get inserted and flagged as to reinit 39847ae44cbShenning * -remove all that are still flagged for deletion 39947ae44cbShenning */ 40047ae44cbShenning 40147ae44cbShenning TAILQ_FOREACH(nla, xconf->listen_addrs, entry) 40247ae44cbShenning nla->reconf = RECONF_DELETE; 40347ae44cbShenning 40447ae44cbShenning /* no new listeners? preserve default ones */ 405d288d268Sclaudio if (TAILQ_EMPTY(conf->listen_addrs)) 40647ae44cbShenning TAILQ_FOREACH(ola, xconf->listen_addrs, entry) 40747ae44cbShenning if (ola->flags & DEFAULT_LISTENER) 40847ae44cbShenning ola->reconf = RECONF_KEEP; 409d288d268Sclaudio /* else loop over listeners and merge configs */ 410d288d268Sclaudio for (nla = TAILQ_FIRST(conf->listen_addrs); nla != NULL; nla = next) { 41147ae44cbShenning next = TAILQ_NEXT(nla, entry); 41247ae44cbShenning 41347ae44cbShenning TAILQ_FOREACH(ola, xconf->listen_addrs, entry) 414d288d268Sclaudio if (!memcmp(&nla->sa, &ola->sa, sizeof(nla->sa))) 41547ae44cbShenning break; 41647ae44cbShenning 41747ae44cbShenning if (ola == NULL) { 41847ae44cbShenning /* new listener, copy over */ 419d288d268Sclaudio TAILQ_REMOVE(conf->listen_addrs, nla, entry); 420d288d268Sclaudio TAILQ_INSERT_TAIL(xconf->listen_addrs, nla, entry); 42147ae44cbShenning nla->reconf = RECONF_REINIT; 42247ae44cbShenning } else /* exists, just flag */ 42347ae44cbShenning ola->reconf = RECONF_KEEP; 42447ae44cbShenning } 4253a50f0a9Sjmc /* finally clean up the original list and remove all stale entries */ 426d288d268Sclaudio for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL; nla = next) { 42747ae44cbShenning next = TAILQ_NEXT(nla, entry); 42847ae44cbShenning if (nla->reconf == RECONF_DELETE) { 42947ae44cbShenning TAILQ_REMOVE(xconf->listen_addrs, nla, entry); 43047ae44cbShenning free(nla); 43147ae44cbShenning } 43247ae44cbShenning } 43347ae44cbShenning 43482fc6237Sclaudio /* 43582fc6237Sclaudio * merge peers: 43682fc6237Sclaudio * - need to know which peers are new, replaced and removed 43782fc6237Sclaudio * - walk over old peers and check if there is a corresponding new 4387f893e0cSclaudio * peer if so mark it RECONF_KEEP. Mark all old peers RECONF_DELETE. 43982fc6237Sclaudio */ 4407876190cSclaudio RB_FOREACH_SAFE(p, peer_head, &xconf->peers, nextp) { 44182fc6237Sclaudio np = getpeerbyid(conf, p->conf.id); 442c2bef38bSclaudio if (np != NULL) { 44382fc6237Sclaudio np->reconf_action = RECONF_KEEP; 444d7629114Sclaudio /* keep the auth state since parent needs it */ 445d7629114Sclaudio np->auth_state = p->auth_state; 44682fc6237Sclaudio 4477876190cSclaudio RB_REMOVE(peer_head, &xconf->peers, p); 44882fc6237Sclaudio free(p); 4497f893e0cSclaudio } else { 4507f893e0cSclaudio p->reconf_action = RECONF_DELETE; 4517f893e0cSclaudio } 45282fc6237Sclaudio } 4537876190cSclaudio RB_FOREACH_SAFE(np, peer_head, &conf->peers, nextp) { 4547876190cSclaudio RB_REMOVE(peer_head, &conf->peers, np); 4557876190cSclaudio if (RB_INSERT(peer_head, &xconf->peers, np) != NULL) 4567876190cSclaudio fatalx("%s: peer tree is corrupt", __func__); 4577876190cSclaudio } 45882fc6237Sclaudio 459d288d268Sclaudio /* conf is merged so free it */ 460d288d268Sclaudio free_config(conf); 461a16c0992Shenning } 462a16c0992Shenning 4637f893e0cSclaudio void 4647f893e0cSclaudio free_deleted_peers(struct bgpd_config *conf) 4657f893e0cSclaudio { 4667f893e0cSclaudio struct peer *p, *nextp; 4677f893e0cSclaudio 4687f893e0cSclaudio RB_FOREACH_SAFE(p, peer_head, &conf->peers, nextp) { 4697f893e0cSclaudio if (p->reconf_action == RECONF_DELETE) { 4707f893e0cSclaudio /* peer no longer exists, clear pfkey state */ 471d7629114Sclaudio pfkey_remove(&p->auth_state); 4727f893e0cSclaudio RB_REMOVE(peer_head, &conf->peers, p); 4737f893e0cSclaudio free(p); 4747f893e0cSclaudio } 4757f893e0cSclaudio } 4767f893e0cSclaudio } 4777f893e0cSclaudio 47839386878Sclaudio uint32_t 479a16c0992Shenning get_bgpid(void) 480a16c0992Shenning { 481a16c0992Shenning struct ifaddrs *ifap, *ifa; 48239386878Sclaudio uint32_t ip = 0, cur, localnet; 483a16c0992Shenning 484bcd6516bSclaudio localnet = INADDR_LOOPBACK & IN_CLASSA_NET; 485a16c0992Shenning 486ec5480d4Shenning if (getifaddrs(&ifap) == -1) 487f87a5020Shenning fatal("getifaddrs"); 488a16c0992Shenning 489a16c0992Shenning for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 490f75399dcSclaudio if (ifa->ifa_addr == NULL || 491f75399dcSclaudio ifa->ifa_addr->sa_family != AF_INET) 492a16c0992Shenning continue; 493a16c0992Shenning cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 494bcd6516bSclaudio cur = ntohl(cur); 495a16c0992Shenning if ((cur & localnet) == localnet) /* skip 127/8 */ 496a16c0992Shenning continue; 497bcd6516bSclaudio if (cur > ip) 498a16c0992Shenning ip = cur; 499a16c0992Shenning } 500a16c0992Shenning freeifaddrs(ifap); 501a16c0992Shenning 502a16c0992Shenning return (ip); 503a16c0992Shenning } 50499694a25Shenning 50599694a25Shenning int 50639386878Sclaudio host(const char *s, struct bgpd_addr *h, uint8_t *len) 50765fe1613Shenning { 5088a771c97Skn int mask = 128; 5093b834e87Sclaudio char *p, *ps; 5103b834e87Sclaudio const char *errstr; 51165fe1613Shenning 5128a771c97Skn if ((ps = strdup(s)) == NULL) 5138a771c97Skn fatal("%s: strdup", __func__); 5148a771c97Skn 5158a771c97Skn if ((p = strrchr(ps, '/')) != NULL) { 5163b834e87Sclaudio mask = strtonum(p+1, 0, 128, &errstr); 5173b834e87Sclaudio if (errstr) { 5188a771c97Skn log_warnx("prefixlen is %s: %s", errstr, p); 5193d365c58Smestre free(ps); 52065fe1613Shenning return (0); 52165fe1613Shenning } 5228a771c97Skn p[0] = '\0'; 52365fe1613Shenning } 52465fe1613Shenning 525eafe309eSclaudio memset(h, 0, sizeof(*h)); 52665fe1613Shenning 5278a771c97Skn if (host_ip(ps, h, len) == 0) { 5288a771c97Skn free(ps); 5298a771c97Skn return (0); 5308a771c97Skn } 53165fe1613Shenning 5328a771c97Skn if (p != NULL) 53365fe1613Shenning *len = mask; 53465fe1613Shenning 53565fe1613Shenning free(ps); 53665fe1613Shenning return (1); 53765fe1613Shenning } 53865fe1613Shenning 53965fe1613Shenning int 54039386878Sclaudio host_ip(const char *s, struct bgpd_addr *h, uint8_t *len) 54165fe1613Shenning { 54265fe1613Shenning struct addrinfo hints, *res; 5438a771c97Skn int bits; 54465fe1613Shenning 545eafe309eSclaudio memset(&hints, 0, sizeof(hints)); 5468a771c97Skn hints.ai_family = AF_UNSPEC; 54765fe1613Shenning hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 54865fe1613Shenning hints.ai_flags = AI_NUMERICHOST; 5498a771c97Skn if (getaddrinfo(s, NULL, &hints, &res) == 0) { 5508a771c97Skn *len = res->ai_family == AF_INET6 ? 128 : 32; 551a27d9e33Sclaudio sa2addr(res->ai_addr, h, NULL); 552e005ea11Shenning freeaddrinfo(res); 5538a771c97Skn } else { /* ie. for 10/8 parsing */ 5548bf72ef0Sclaudio if ((bits = inet_net_pton(AF_INET, s, &h->v4, 5558bf72ef0Sclaudio sizeof(h->v4))) == -1) 5568a771c97Skn return (0); 5578a771c97Skn *len = bits; 5588a771c97Skn h->aid = AID_INET; 55965fe1613Shenning } 56065fe1613Shenning 5618a771c97Skn return (1); 56265fe1613Shenning } 5639584c7ffShenning 5641adf6159Sremi int 5659584c7ffShenning prepare_listeners(struct bgpd_config *conf) 5669584c7ffShenning { 56724d07492Shenning struct listen_addr *la, *next; 5689584c7ffShenning int opt = 1; 5691adf6159Sremi int r = 0; 5709584c7ffShenning 57124d07492Shenning for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) { 57224d07492Shenning next = TAILQ_NEXT(la, entry); 57347ae44cbShenning if (la->reconf != RECONF_REINIT) 57447ae44cbShenning continue; 57547ae44cbShenning 5765ba20998Sclaudio if ((la->fd = socket(la->sa.ss_family, 5775ba20998Sclaudio SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 57824d07492Shenning IPPROTO_TCP)) == -1) { 57924d07492Shenning if (la->flags & DEFAULT_LISTENER && (errno == 58024d07492Shenning EAFNOSUPPORT || errno == EPROTONOSUPPORT)) { 58124d07492Shenning TAILQ_REMOVE(conf->listen_addrs, la, entry); 58224d07492Shenning free(la); 58324d07492Shenning continue; 58424d07492Shenning } else 5859584c7ffShenning fatal("socket"); 58624d07492Shenning } 5879584c7ffShenning 5889584c7ffShenning opt = 1; 58947ae44cbShenning if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR, 5909584c7ffShenning &opt, sizeof(opt)) == -1) 591af642664Sdlg fatal("setsockopt SO_REUSEADDR"); 5929584c7ffShenning 593255fe563Sclaudio if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa_len) == 5949584c7ffShenning -1) { 59575021d26Shenning switch (la->sa.ss_family) { 59675021d26Shenning case AF_INET: 59775021d26Shenning log_warn("cannot bind to %s:%u", 598255fe563Sclaudio log_sockaddr((struct sockaddr *)&la->sa, 599255fe563Sclaudio la->sa_len), ntohs(((struct sockaddr_in *) 60075021d26Shenning &la->sa)->sin_port)); 60175021d26Shenning break; 60275021d26Shenning case AF_INET6: 60375021d26Shenning log_warn("cannot bind to [%s]:%u", 604255fe563Sclaudio log_sockaddr((struct sockaddr *)&la->sa, 605255fe563Sclaudio la->sa_len), ntohs(((struct sockaddr_in6 *) 60675021d26Shenning &la->sa)->sin6_port)); 60775021d26Shenning break; 60875021d26Shenning default: 6099584c7ffShenning log_warn("cannot bind to %s", 610255fe563Sclaudio log_sockaddr((struct sockaddr *)&la->sa, 611255fe563Sclaudio la->sa_len)); 61275021d26Shenning break; 61375021d26Shenning } 6149584c7ffShenning close(la->fd); 6155c1f49cbShenning TAILQ_REMOVE(conf->listen_addrs, la, entry); 6165c1f49cbShenning free(la); 6171adf6159Sremi r = -1; 6185c1f49cbShenning continue; 6199584c7ffShenning } 6209584c7ffShenning } 6211adf6159Sremi 6221adf6159Sremi return (r); 6239584c7ffShenning } 624610bcb44Sclaudio 62547feec7cSbenno void 6268bf72ef0Sclaudio expand_networks(struct bgpd_config *c, struct network_head *nw) 62747feec7cSbenno { 62847feec7cSbenno struct network *n, *m, *tmp; 62947feec7cSbenno struct prefixset *ps; 63047feec7cSbenno struct prefixset_item *psi; 63147feec7cSbenno 63247feec7cSbenno TAILQ_FOREACH_SAFE(n, nw, entry, tmp) { 63347feec7cSbenno if (n->net.type == NETWORK_PREFIXSET) { 63447feec7cSbenno TAILQ_REMOVE(nw, n, entry); 6356f1dba6eSclaudio if ((ps = find_prefixset(n->net.psname, &c->prefixsets)) 63647feec7cSbenno == NULL) 63747feec7cSbenno fatal("%s: prefixset %s not found", __func__, 63847feec7cSbenno n->net.psname); 639d32b24c8Sclaudio RB_FOREACH(psi, prefixset_tree, &ps->psitems) { 64047feec7cSbenno if ((m = calloc(1, sizeof(struct network))) 64147feec7cSbenno == NULL) 64247feec7cSbenno fatal(NULL); 64347feec7cSbenno memcpy(&m->net.prefix, &psi->p.addr, 64447feec7cSbenno sizeof(m->net.prefix)); 64547feec7cSbenno m->net.prefixlen = psi->p.len; 646dcd4a44dSclaudio filterset_copy(&n->net.attrset, 64747feec7cSbenno &m->net.attrset); 64847feec7cSbenno TAILQ_INSERT_TAIL(nw, m, entry); 64947feec7cSbenno } 6508bf72ef0Sclaudio network_free(n); 65147feec7cSbenno } 65247feec7cSbenno } 65347feec7cSbenno } 654d32b24c8Sclaudio 6556aa533f4Sclaudio static inline int 656d32b24c8Sclaudio prefixset_cmp(struct prefixset_item *a, struct prefixset_item *b) 657d32b24c8Sclaudio { 658d32b24c8Sclaudio int i; 659d32b24c8Sclaudio 660d32b24c8Sclaudio if (a->p.addr.aid < b->p.addr.aid) 661d32b24c8Sclaudio return (-1); 662d32b24c8Sclaudio if (a->p.addr.aid > b->p.addr.aid) 663d32b24c8Sclaudio return (1); 664d32b24c8Sclaudio 665d32b24c8Sclaudio switch (a->p.addr.aid) { 666d32b24c8Sclaudio case AID_INET: 667b818c07eSclaudio i = memcmp(&a->p.addr.v4, &b->p.addr.v4, 668b818c07eSclaudio sizeof(struct in_addr)); 669d32b24c8Sclaudio break; 670d32b24c8Sclaudio case AID_INET6: 671d32b24c8Sclaudio i = memcmp(&a->p.addr.v6, &b->p.addr.v6, 672d32b24c8Sclaudio sizeof(struct in6_addr)); 673d32b24c8Sclaudio break; 674d32b24c8Sclaudio default: 675d32b24c8Sclaudio fatalx("%s: unknown af", __func__); 676d32b24c8Sclaudio } 677b818c07eSclaudio if (i > 0) 678b818c07eSclaudio return (1); 679b818c07eSclaudio if (i < 0) 680b818c07eSclaudio return (-1); 681d32b24c8Sclaudio if (a->p.len < b->p.len) 682d32b24c8Sclaudio return (-1); 683d32b24c8Sclaudio if (a->p.len > b->p.len) 684d32b24c8Sclaudio return (1); 685d32b24c8Sclaudio if (a->p.len_min < b->p.len_min) 686d32b24c8Sclaudio return (-1); 687d32b24c8Sclaudio if (a->p.len_min > b->p.len_min) 688d32b24c8Sclaudio return (1); 689d32b24c8Sclaudio if (a->p.len_max < b->p.len_max) 690d32b24c8Sclaudio return (-1); 691d32b24c8Sclaudio if (a->p.len_max > b->p.len_max) 692d32b24c8Sclaudio return (1); 693d32b24c8Sclaudio return (0); 694d32b24c8Sclaudio } 695d32b24c8Sclaudio 696d32b24c8Sclaudio RB_GENERATE(prefixset_tree, prefixset_item, entry, prefixset_cmp); 6976aa533f4Sclaudio 698ff84f55eSclaudio static inline int 6996aa533f4Sclaudio roa_cmp(struct roa *a, struct roa *b) 7006aa533f4Sclaudio { 701b818c07eSclaudio int i; 7026aa533f4Sclaudio 703b818c07eSclaudio if (a->aid < b->aid) 704b818c07eSclaudio return (-1); 705b818c07eSclaudio if (a->aid > b->aid) 706b818c07eSclaudio return (1); 707b818c07eSclaudio 708b818c07eSclaudio switch (a->aid) { 709b818c07eSclaudio case AID_INET: 710b818c07eSclaudio i = memcmp(&a->prefix.inet, &b->prefix.inet, 711b818c07eSclaudio sizeof(struct in_addr)); 712b818c07eSclaudio break; 713b818c07eSclaudio case AID_INET6: 714b818c07eSclaudio i = memcmp(&a->prefix.inet6, &b->prefix.inet6, 715b818c07eSclaudio sizeof(struct in6_addr)); 716b818c07eSclaudio break; 717b818c07eSclaudio default: 718b818c07eSclaudio fatalx("%s: unknown af", __func__); 7196aa533f4Sclaudio } 720b818c07eSclaudio if (i > 0) 721b818c07eSclaudio return (1); 722b818c07eSclaudio if (i < 0) 723b818c07eSclaudio return (-1); 724b818c07eSclaudio if (a->prefixlen < b->prefixlen) 725b818c07eSclaudio return (-1); 726b818c07eSclaudio if (a->prefixlen > b->prefixlen) 727b818c07eSclaudio return (1); 7286aa533f4Sclaudio 729b818c07eSclaudio if (a->asnum < b->asnum) 730b818c07eSclaudio return (-1); 731b818c07eSclaudio if (a->asnum > b->asnum) 732b818c07eSclaudio return (1); 733b818c07eSclaudio 734b818c07eSclaudio if (a->maxlen < b->maxlen) 735b818c07eSclaudio return (-1); 736b818c07eSclaudio if (a->maxlen > b->maxlen) 737b818c07eSclaudio return (1); 738b818c07eSclaudio 739b818c07eSclaudio return (0); 7406aa533f4Sclaudio } 7416aa533f4Sclaudio 7426aa533f4Sclaudio RB_GENERATE(roa_tree, roa, entry, roa_cmp); 743ff84f55eSclaudio 744ff84f55eSclaudio static inline int 745ff84f55eSclaudio aspa_cmp(struct aspa_set *a, struct aspa_set *b) 746ff84f55eSclaudio { 747ff84f55eSclaudio if (a->as < b->as) 748ff84f55eSclaudio return (-1); 749ff84f55eSclaudio if (a->as > b->as) 750ff84f55eSclaudio return (1); 751ff84f55eSclaudio return (0); 752ff84f55eSclaudio } 753ff84f55eSclaudio 754ff84f55eSclaudio RB_GENERATE(aspa_tree, aspa_set, entry, aspa_cmp); 75544f7a62cSclaudio 75644f7a62cSclaudio static inline int 75744f7a62cSclaudio flowspec_config_cmp(struct flowspec_config *a, struct flowspec_config *b) 75844f7a62cSclaudio { 75944f7a62cSclaudio if (a->flow->aid < b->flow->aid) 76044f7a62cSclaudio return -1; 76144f7a62cSclaudio if (a->flow->aid > b->flow->aid) 76244f7a62cSclaudio return 1; 76344f7a62cSclaudio 76444f7a62cSclaudio return flowspec_cmp(a->flow->data, a->flow->len, 76544f7a62cSclaudio b->flow->data, b->flow->len, a->flow->aid == AID_FLOWSPECv6); 76644f7a62cSclaudio } 76744f7a62cSclaudio 76844f7a62cSclaudio RB_GENERATE(flowspec_tree, flowspec_config, entry, flowspec_config_cmp); 769