xref: /openbsd-src/usr.sbin/bgpd/config.c (revision 6c15f9439856b686a1403406c0408483e82f917b)
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