xref: /openbsd-src/usr.sbin/bgpd/config.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: config.c,v 1.63 2016/01/26 18:35:01 mmcc 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 #include <sys/stat.h>
22 #include <sys/mman.h>
23 #include <sys/ioctl.h>
24 
25 #include <netmpls/mpls.h>
26 
27 #include <errno.h>
28 #include <ifaddrs.h>
29 #include <netdb.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "bgpd.h"
35 #include "session.h"
36 
37 u_int32_t	get_bgpid(void);
38 int		host_v4(const char *, struct bgpd_addr *, u_int8_t *);
39 int		host_v6(const char *, struct bgpd_addr *);
40 void		free_networks(struct network_head *);
41 void		free_rdomains(struct rdomain_head *);
42 
43 struct bgpd_config *
44 new_config(void)
45 {
46 	struct bgpd_config *conf;
47 
48 	if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
49 		fatal(NULL);
50 
51 	conf->min_holdtime = MIN_HOLDTIME;
52 	conf->bgpid = get_bgpid();
53 	conf->fib_priority = RTP_BGP;
54 
55 	if ((conf->csock = strdup(SOCKET_NAME)) == NULL)
56 		fatal(NULL);
57 
58 	if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
59 		fatal(NULL);
60 	if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) ==
61 	    NULL)
62 		fatal(NULL);
63 	if ((conf->mrt = calloc(1, sizeof(struct mrt_head))) == NULL)
64 		fatal(NULL);
65 
66 	/* init the various list for later */
67 	TAILQ_INIT(&conf->networks);
68 	SIMPLEQ_INIT(&conf->rdomains);
69 
70 	TAILQ_INIT(conf->filters);
71 	TAILQ_INIT(conf->listen_addrs);
72 	LIST_INIT(conf->mrt);
73 
74 	return (conf);
75 }
76 
77 void
78 free_networks(struct network_head *networks)
79 {
80 	struct network		*n;
81 
82 	while ((n = TAILQ_FIRST(networks)) != NULL) {
83 		TAILQ_REMOVE(networks, n, entry);
84 		filterset_free(&n->net.attrset);
85 		free(n);
86 	}
87 }
88 
89 void
90 free_rdomains(struct rdomain_head *rdomains)
91 {
92 	struct rdomain		*rd;
93 
94 	while ((rd = SIMPLEQ_FIRST(rdomains)) != NULL) {
95 		SIMPLEQ_REMOVE_HEAD(rdomains, entry);
96 		filterset_free(&rd->export);
97 		filterset_free(&rd->import);
98 		free_networks(&rd->net_l);
99 		free(rd);
100 	}
101 }
102 
103 void
104 free_config(struct bgpd_config *conf)
105 {
106 	struct listen_addr	*la;
107 	struct mrt		*m;
108 
109 	free_rdomains(&conf->rdomains);
110 	free_networks(&conf->networks);
111 	filterlist_free(conf->filters);
112 
113 	while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
114 		TAILQ_REMOVE(conf->listen_addrs, la, entry);
115 		free(la);
116 	}
117 	free(conf->listen_addrs);
118 
119 	while ((m = LIST_FIRST(conf->mrt)) != NULL) {
120 		LIST_REMOVE(m, entry);
121 		free(m);
122 	}
123 	free(conf->mrt);
124 
125 	free(conf->csock);
126 	free(conf->rcsock);
127 
128 	free(conf);
129 }
130 
131 int
132 merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
133     struct peer *peer_l)
134 {
135 	struct listen_addr	*nla, *ola, *next;
136 	struct network		*n;
137 	struct rdomain		*rd;
138 
139 	/*
140 	 * merge the freshly parsed conf into the running xconf
141 	 */
142 	if (!conf->as) {
143 		log_warnx("configuration error: AS not given");
144 		return (1);
145 	}
146 
147 	if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
148 		conf->clusterid = conf->bgpid;
149 
150 
151 	/* adjust FIB priority if changed */
152 	/* if xconf is uninitialized we get RTP_NONE */
153 	if (xconf->fib_priority != conf->fib_priority) {
154 		kr_fib_decouple_all(xconf->fib_priority);
155 		kr_fib_update_prio_all(conf->fib_priority);
156 		kr_fib_couple_all(conf->fib_priority);
157 	}
158 
159 	/* take over the easy config changes */
160 	xconf->flags = conf->flags;
161 	xconf->log = conf->log;
162 	xconf->bgpid = conf->bgpid;
163 	xconf->clusterid = conf->clusterid;
164 	xconf->as = conf->as;
165 	xconf->short_as = conf->short_as;
166 	xconf->holdtime = conf->holdtime;
167 	xconf->min_holdtime = conf->min_holdtime;
168 	xconf->connectretry = conf->connectretry;
169 	xconf->fib_priority = conf->fib_priority;
170 
171 	/* clear old control sockets and use new */
172 	free(xconf->csock);
173 	free(xconf->rcsock);
174 	xconf->csock = conf->csock;
175 	xconf->rcsock = conf->rcsock;
176 	/* set old one to NULL so we don't double free */
177 	conf->csock = NULL;
178 	conf->rcsock = NULL;
179 
180 	/* clear all current filters and take over the new ones */
181 	filterlist_free(xconf->filters);
182 	xconf->filters = conf->filters;
183 	conf->filters = NULL;
184 
185 	/* switch the network statements, but first remove the old ones */
186 	free_networks(&xconf->networks);
187 	while ((n = TAILQ_FIRST(&conf->networks)) != NULL) {
188 		TAILQ_REMOVE(&conf->networks, n, entry);
189 		TAILQ_INSERT_TAIL(&xconf->networks, n, entry);
190 	}
191 
192 	/* switch the rdomain configs, first remove the old ones */
193 	free_rdomains(&xconf->rdomains);
194 	while ((rd = SIMPLEQ_FIRST(&conf->rdomains)) != NULL) {
195 		SIMPLEQ_REMOVE_HEAD(&conf->rdomains, entry);
196 		SIMPLEQ_INSERT_TAIL(&xconf->rdomains, rd, entry);
197 	}
198 
199 	/*
200 	 * merge new listeners:
201 	 * -flag all existing ones as to be deleted
202 	 * -those that are in both new and old: flag to keep
203 	 * -new ones get inserted and flagged as to reinit
204 	 * -remove all that are still flagged for deletion
205 	 */
206 
207 	TAILQ_FOREACH(nla, xconf->listen_addrs, entry)
208 		nla->reconf = RECONF_DELETE;
209 
210 	/* no new listeners? preserve default ones */
211 	if (TAILQ_EMPTY(conf->listen_addrs))
212 		TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
213 			if (ola->flags & DEFAULT_LISTENER)
214 				ola->reconf = RECONF_KEEP;
215 	/* else loop over listeners and merge configs */
216 	for (nla = TAILQ_FIRST(conf->listen_addrs); nla != NULL; nla = next) {
217 		next = TAILQ_NEXT(nla, entry);
218 
219 		TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
220 			if (!memcmp(&nla->sa, &ola->sa, sizeof(nla->sa)))
221 				break;
222 
223 		if (ola == NULL) {
224 			/* new listener, copy over */
225 			TAILQ_REMOVE(conf->listen_addrs, nla, entry);
226 			TAILQ_INSERT_TAIL(xconf->listen_addrs, nla, entry);
227 			nla->reconf = RECONF_REINIT;
228 		} else		/* exists, just flag */
229 			ola->reconf = RECONF_KEEP;
230 	}
231 	/* finally clean up the original list and remove all stale entires */
232 	for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL; nla = next) {
233 		next = TAILQ_NEXT(nla, entry);
234 		if (nla->reconf == RECONF_DELETE) {
235 			TAILQ_REMOVE(xconf->listen_addrs, nla, entry);
236 			free(nla);
237 		}
238 	}
239 
240 	/* conf is merged so free it */
241 	free_config(conf);
242 
243 	return (0);
244 }
245 
246 u_int32_t
247 get_bgpid(void)
248 {
249 	struct ifaddrs		*ifap, *ifa;
250 	u_int32_t		 ip = 0, cur, localnet;
251 
252 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
253 
254 	if (getifaddrs(&ifap) == -1)
255 		fatal("getifaddrs");
256 
257 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
258 		if (ifa->ifa_addr->sa_family != AF_INET)
259 			continue;
260 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
261 		if ((cur & localnet) == localnet)	/* skip 127/8 */
262 			continue;
263 		if (ntohl(cur) > ntohl(ip))
264 			ip = cur;
265 	}
266 	freeifaddrs(ifap);
267 
268 	return (ip);
269 }
270 
271 int
272 host(const char *s, struct bgpd_addr *h, u_int8_t *len)
273 {
274 	int			 done = 0;
275 	int			 mask;
276 	char			*p, *ps;
277 	const char		*errstr;
278 
279 	if ((p = strrchr(s, '/')) != NULL) {
280 		mask = strtonum(p + 1, 0, 128, &errstr);
281 		if (errstr) {
282 			log_warnx("prefixlen is %s: %s", errstr, p + 1);
283 			return (0);
284 		}
285 		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
286 			fatal("host: malloc");
287 		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
288 	} else {
289 		if ((ps = strdup(s)) == NULL)
290 			fatal("host: strdup");
291 		mask = 128;
292 	}
293 
294 	bzero(h, sizeof(struct bgpd_addr));
295 
296 	/* IPv4 address? */
297 	if (!done)
298 		done = host_v4(s, h, len);
299 
300 	/* IPv6 address? */
301 	if (!done) {
302 		done = host_v6(ps, h);
303 		*len = mask;
304 	}
305 
306 	free(ps);
307 
308 	return (done);
309 }
310 
311 int
312 host_v4(const char *s, struct bgpd_addr *h, u_int8_t *len)
313 {
314 	struct in_addr		 ina;
315 	int			 bits = 32;
316 
317 	bzero(&ina, sizeof(struct in_addr));
318 	if (strrchr(s, '/') != NULL) {
319 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
320 			return (0);
321 	} else {
322 		if (inet_pton(AF_INET, s, &ina) != 1)
323 			return (0);
324 	}
325 
326 	h->aid = AID_INET;
327 	h->v4.s_addr = ina.s_addr;
328 	*len = bits;
329 
330 	return (1);
331 }
332 
333 int
334 host_v6(const char *s, struct bgpd_addr *h)
335 {
336 	struct addrinfo		 hints, *res;
337 
338 	bzero(&hints, sizeof(hints));
339 	hints.ai_family = AF_INET6;
340 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
341 	hints.ai_flags = AI_NUMERICHOST;
342 	if (getaddrinfo(s, "0", &hints, &res) == 0) {
343 		sa2addr(res->ai_addr, h);
344 		freeaddrinfo(res);
345 		return (1);
346 	}
347 
348 	return (0);
349 }
350 
351 void
352 prepare_listeners(struct bgpd_config *conf)
353 {
354 	struct listen_addr	*la, *next;
355 	int			 opt = 1;
356 
357 	if (TAILQ_EMPTY(conf->listen_addrs)) {
358 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
359 			fatal("setup_listeners calloc");
360 		la->fd = -1;
361 		la->flags = DEFAULT_LISTENER;
362 		la->reconf = RECONF_REINIT;
363 		la->sa.ss_len = sizeof(struct sockaddr_in);
364 		((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
365 		((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
366 		    htonl(INADDR_ANY);
367 		((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT);
368 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
369 
370 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
371 			fatal("setup_listeners calloc");
372 		la->fd = -1;
373 		la->flags = DEFAULT_LISTENER;
374 		la->reconf = RECONF_REINIT;
375 		la->sa.ss_len = sizeof(struct sockaddr_in6);
376 		((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
377 		((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT);
378 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
379 	}
380 
381 	for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) {
382 		next = TAILQ_NEXT(la, entry);
383 		if (la->reconf != RECONF_REINIT)
384 			continue;
385 
386 		if ((la->fd = socket(la->sa.ss_family,
387 		    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
388 		    IPPROTO_TCP)) == -1) {
389 			if (la->flags & DEFAULT_LISTENER && (errno ==
390 			    EAFNOSUPPORT || errno == EPROTONOSUPPORT)) {
391 				TAILQ_REMOVE(conf->listen_addrs, la, entry);
392 				free(la);
393 				continue;
394 			} else
395 				fatal("socket");
396 		}
397 
398 		opt = 1;
399 		if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR,
400 		    &opt, sizeof(opt)) == -1)
401 			fatal("setsockopt SO_REUSEADDR");
402 
403 		if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) ==
404 		    -1) {
405 			switch (la->sa.ss_family) {
406 			case AF_INET:
407 				log_warn("cannot bind to %s:%u",
408 				    log_sockaddr((struct sockaddr *)&la->sa),
409 				    ntohs(((struct sockaddr_in *)
410 				    &la->sa)->sin_port));
411 				break;
412 			case AF_INET6:
413 				log_warn("cannot bind to [%s]:%u",
414 				    log_sockaddr((struct sockaddr *)&la->sa),
415 				    ntohs(((struct sockaddr_in6 *)
416 				    &la->sa)->sin6_port));
417 				break;
418 			default:
419 				log_warn("cannot bind to %s",
420 				    log_sockaddr((struct sockaddr *)&la->sa));
421 				break;
422 			}
423 			close(la->fd);
424 			TAILQ_REMOVE(conf->listen_addrs, la, entry);
425 			free(la);
426 			continue;
427 		}
428 	}
429 }
430 
431 int
432 get_mpe_label(struct rdomain *r)
433 {
434 	struct  ifreq	ifr;
435 	struct shim_hdr	shim;
436 	int		s;
437 
438 	s = socket(AF_INET, SOCK_DGRAM, 0);
439 	if (s == -1)
440 		return (-1);
441 
442 	bzero(&shim, sizeof(shim));
443 	bzero(&ifr, sizeof(ifr));
444 	strlcpy(ifr.ifr_name, r->ifmpe, sizeof(ifr.ifr_name));
445 	ifr.ifr_data = (caddr_t)&shim;
446 
447 	if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
448 		close(s);
449 		return (-1);
450 	}
451 	close(s);
452 	r->label = shim.shim_label;
453 	return (0);
454 }
455