GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/config.c Lines: 115 230 50.0 %
Date: 2017-11-13 Branches: 41 129 31.8 %

Line Branch Exec Source
1
/*	$OpenBSD: config.c,v 1.67 2017/05/29 09:56:33 benno 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 <stdio.h>
32
#include <string.h>
33
#include <unistd.h>
34
35
#include "bgpd.h"
36
#include "session.h"
37
#include "log.h"
38
39
u_int32_t	get_bgpid(void);
40
int		host_v4(const char *, struct bgpd_addr *, u_int8_t *);
41
int		host_v6(const char *, struct bgpd_addr *);
42
void		free_networks(struct network_head *);
43
void		free_rdomains(struct rdomain_head *);
44
45
struct bgpd_config *
46
new_config(void)
47
{
48
	struct bgpd_config	*conf;
49
50
48
	if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
51
		fatal(NULL);
52
53
24
	conf->min_holdtime = MIN_HOLDTIME;
54
24
	conf->bgpid = get_bgpid();
55
24
	conf->fib_priority = RTP_BGP;
56
24
	conf->default_tableid = getrtable();
57
58
48
	if (asprintf(&conf->csock, "%s.%d", SOCKET_NAME,
59
24
	    conf->default_tableid) == -1)
60
		fatal(NULL);
61
62
24
	if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
63
		fatal(NULL);
64
24
	if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) ==
65
	    NULL)
66
		fatal(NULL);
67
24
	if ((conf->mrt = calloc(1, sizeof(struct mrt_head))) == NULL)
68
		fatal(NULL);
69
70
	/* init the various list for later */
71
24
	TAILQ_INIT(&conf->networks);
72
24
	SIMPLEQ_INIT(&conf->rdomains);
73
74
24
	TAILQ_INIT(conf->filters);
75
24
	TAILQ_INIT(conf->listen_addrs);
76
24
	LIST_INIT(conf->mrt);
77
78
24
	return (conf);
79
}
80
81
void
82
free_networks(struct network_head *networks)
83
{
84
	struct network		*n;
85
86
72
	while ((n = TAILQ_FIRST(networks)) != NULL) {
87
		TAILQ_REMOVE(networks, n, entry);
88
		filterset_free(&n->net.attrset);
89
		free(n);
90
	}
91
24
}
92
93
void
94
free_rdomains(struct rdomain_head *rdomains)
95
{
96
	struct rdomain		*rd;
97
98
72
	while ((rd = SIMPLEQ_FIRST(rdomains)) != NULL) {
99
		SIMPLEQ_REMOVE_HEAD(rdomains, entry);
100
		filterset_free(&rd->export);
101
		filterset_free(&rd->import);
102
		free_networks(&rd->net_l);
103
		free(rd);
104
	}
105
24
}
106
107
void
108
free_config(struct bgpd_config *conf)
109
{
110
	struct listen_addr	*la;
111
	struct mrt		*m;
112
113
24
	free_rdomains(&conf->rdomains);
114
12
	free_networks(&conf->networks);
115
12
	filterlist_free(conf->filters);
116
117
24
	while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
118
		TAILQ_REMOVE(conf->listen_addrs, la, entry);
119
		free(la);
120
	}
121
12
	free(conf->listen_addrs);
122
123
24
	while ((m = LIST_FIRST(conf->mrt)) != NULL) {
124
		LIST_REMOVE(m, entry);
125
		free(m);
126
	}
127
12
	free(conf->mrt);
128
129
12
	free(conf->csock);
130
12
	free(conf->rcsock);
131
132
12
	free(conf);
133
12
}
134
135
int
136
merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
137
    struct peer *peer_l)
138
{
139
	struct listen_addr	*nla, *ola, *next;
140
	struct network		*n;
141
	struct rdomain		*rd;
142
143
	/*
144
	 * merge the freshly parsed conf into the running xconf
145
	 */
146
24
	if (!conf->as) {
147
		log_warnx("configuration error: AS not given");
148
		return (1);
149
	}
150
151

12
	if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
152
		conf->clusterid = conf->bgpid;
153
154
155
	/* adjust FIB priority if changed */
156
	/* if xconf is uninitialized we get RTP_NONE */
157
12
	if (xconf->fib_priority != conf->fib_priority) {
158
		kr_fib_decouple_all(xconf->fib_priority);
159
		kr_fib_update_prio_all(conf->fib_priority);
160
		kr_fib_couple_all(conf->fib_priority);
161
	}
162
163
	/* take over the easy config changes */
164
12
	xconf->flags = conf->flags;
165
12
	xconf->log = conf->log;
166
12
	xconf->bgpid = conf->bgpid;
167
12
	xconf->clusterid = conf->clusterid;
168
12
	xconf->as = conf->as;
169
12
	xconf->short_as = conf->short_as;
170
12
	xconf->holdtime = conf->holdtime;
171
12
	xconf->min_holdtime = conf->min_holdtime;
172
12
	xconf->connectretry = conf->connectretry;
173
12
	xconf->fib_priority = conf->fib_priority;
174
175
	/* clear old control sockets and use new */
176
12
	free(xconf->csock);
177
12
	free(xconf->rcsock);
178
12
	xconf->csock = conf->csock;
179
12
	xconf->rcsock = conf->rcsock;
180
	/* set old one to NULL so we don't double free */
181
12
	conf->csock = NULL;
182
12
	conf->rcsock = NULL;
183
184
	/* clear all current filters and take over the new ones */
185
12
	filterlist_free(xconf->filters);
186
12
	xconf->filters = conf->filters;
187
12
	conf->filters = NULL;
188
189
	/* switch the network statements, but first remove the old ones */
190
12
	free_networks(&xconf->networks);
191
24
	while ((n = TAILQ_FIRST(&conf->networks)) != NULL) {
192
		TAILQ_REMOVE(&conf->networks, n, entry);
193
		TAILQ_INSERT_TAIL(&xconf->networks, n, entry);
194
	}
195
196
	/* switch the rdomain configs, first remove the old ones */
197
12
	free_rdomains(&xconf->rdomains);
198
24
	while ((rd = SIMPLEQ_FIRST(&conf->rdomains)) != NULL) {
199
		SIMPLEQ_REMOVE_HEAD(&conf->rdomains, entry);
200
		SIMPLEQ_INSERT_TAIL(&xconf->rdomains, rd, entry);
201
	}
202
203
	/*
204
	 * merge new listeners:
205
	 * -flag all existing ones as to be deleted
206
	 * -those that are in both new and old: flag to keep
207
	 * -new ones get inserted and flagged as to reinit
208
	 * -remove all that are still flagged for deletion
209
	 */
210
211
24
	TAILQ_FOREACH(nla, xconf->listen_addrs, entry)
212
		nla->reconf = RECONF_DELETE;
213
214
	/* no new listeners? preserve default ones */
215
12
	if (TAILQ_EMPTY(conf->listen_addrs))
216
24
		TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
217
			if (ola->flags & DEFAULT_LISTENER)
218
				ola->reconf = RECONF_KEEP;
219
	/* else loop over listeners and merge configs */
220
24
	for (nla = TAILQ_FIRST(conf->listen_addrs); nla != NULL; nla = next) {
221
		next = TAILQ_NEXT(nla, entry);
222
223
		TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
224
			if (!memcmp(&nla->sa, &ola->sa, sizeof(nla->sa)))
225
				break;
226
227
		if (ola == NULL) {
228
			/* new listener, copy over */
229
			TAILQ_REMOVE(conf->listen_addrs, nla, entry);
230
			TAILQ_INSERT_TAIL(xconf->listen_addrs, nla, entry);
231
			nla->reconf = RECONF_REINIT;
232
		} else		/* exists, just flag */
233
			ola->reconf = RECONF_KEEP;
234
	}
235
	/* finally clean up the original list and remove all stale entires */
236
24
	for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL; nla = next) {
237
		next = TAILQ_NEXT(nla, entry);
238
		if (nla->reconf == RECONF_DELETE) {
239
			TAILQ_REMOVE(xconf->listen_addrs, nla, entry);
240
			free(nla);
241
		}
242
	}
243
244
	/* conf is merged so free it */
245
12
	free_config(conf);
246
247
12
	return (0);
248
12
}
249
250
u_int32_t
251
get_bgpid(void)
252
{
253
48
	struct ifaddrs		*ifap, *ifa;
254
	u_int32_t		 ip = 0, cur, localnet;
255
256
	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
257
258
24
	if (getifaddrs(&ifap) == -1)
259
		fatal("getifaddrs");
260
261
600
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
262
276
		if (ifa->ifa_addr->sa_family != AF_INET)
263
			continue;
264
66
		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
265
66
		if ((cur & localnet) == localnet)	/* skip 127/8 */
266
			continue;
267
42
		if (ntohl(cur) > ntohl(ip))
268
42
			ip = cur;
269
	}
270
24
	freeifaddrs(ifap);
271
272
24
	return (ip);
273
24
}
274
275
int
276
host(const char *s, struct bgpd_addr *h, u_int8_t *len)
277
{
278
	int			 done = 0;
279
	int			 mask;
280
	char			*p, *ps;
281
304
	const char		*errstr;
282
283
152
	if ((p = strrchr(s, '/')) != NULL) {
284
100
		mask = strtonum(p + 1, 0, 128, &errstr);
285
100
		if (errstr) {
286
			log_warnx("prefixlen is %s: %s", errstr, p + 1);
287
			return (0);
288
		}
289
100
		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
290
			fatal("host: malloc");
291
100
		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
292
100
	} else {
293
52
		if ((ps = strdup(s)) == NULL)
294
			fatal("host: strdup");
295
		mask = 128;
296
	}
297
298
152
	bzero(h, sizeof(struct bgpd_addr));
299
300
	/* IPv4 address? */
301
152
	if (!done)
302
152
		done = host_v4(s, h, len);
303
304
	/* IPv6 address? */
305
152
	if (!done) {
306
40
		done = host_v6(ps, h);
307
40
		*len = mask;
308
40
	}
309
310
152
	free(ps);
311
312
152
	return (done);
313
152
}
314
315
int
316
host_v4(const char *s, struct bgpd_addr *h, u_int8_t *len)
317
{
318
304
	struct in_addr		 ina;
319
	int			 bits = 32;
320
321
152
	bzero(&ina, sizeof(struct in_addr));
322
152
	if (strrchr(s, '/') != NULL) {
323
100
		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
324
40
			return (0);
325
	} else {
326
52
		if (inet_pton(AF_INET, s, &ina) != 1)
327
			return (0);
328
	}
329
330
112
	h->aid = AID_INET;
331
112
	h->v4.s_addr = ina.s_addr;
332
112
	*len = bits;
333
334
112
	return (1);
335
152
}
336
337
int
338
host_v6(const char *s, struct bgpd_addr *h)
339
{
340
80
	struct addrinfo		 hints, *res;
341
342
40
	bzero(&hints, sizeof(hints));
343
40
	hints.ai_family = AF_INET6;
344
40
	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
345
40
	hints.ai_flags = AI_NUMERICHOST;
346
40
	if (getaddrinfo(s, "0", &hints, &res) == 0) {
347
40
		sa2addr(res->ai_addr, h);
348
40
		freeaddrinfo(res);
349
40
		return (1);
350
	}
351
352
	return (0);
353
40
}
354
355
void
356
prepare_listeners(struct bgpd_config *conf)
357
{
358
	struct listen_addr	*la, *next;
359
	int			 opt = 1;
360
361
	if (TAILQ_EMPTY(conf->listen_addrs)) {
362
		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
363
			fatal("setup_listeners calloc");
364
		la->fd = -1;
365
		la->flags = DEFAULT_LISTENER;
366
		la->reconf = RECONF_REINIT;
367
		la->sa.ss_len = sizeof(struct sockaddr_in);
368
		((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
369
		((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
370
		    htonl(INADDR_ANY);
371
		((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT);
372
		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
373
374
		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
375
			fatal("setup_listeners calloc");
376
		la->fd = -1;
377
		la->flags = DEFAULT_LISTENER;
378
		la->reconf = RECONF_REINIT;
379
		la->sa.ss_len = sizeof(struct sockaddr_in6);
380
		((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
381
		((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT);
382
		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
383
	}
384
385
	for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) {
386
		next = TAILQ_NEXT(la, entry);
387
		if (la->reconf != RECONF_REINIT)
388
			continue;
389
390
		if ((la->fd = socket(la->sa.ss_family,
391
		    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
392
		    IPPROTO_TCP)) == -1) {
393
			if (la->flags & DEFAULT_LISTENER && (errno ==
394
			    EAFNOSUPPORT || errno == EPROTONOSUPPORT)) {
395
				TAILQ_REMOVE(conf->listen_addrs, la, entry);
396
				free(la);
397
				continue;
398
			} else
399
				fatal("socket");
400
		}
401
402
		opt = 1;
403
		if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR,
404
		    &opt, sizeof(opt)) == -1)
405
			fatal("setsockopt SO_REUSEADDR");
406
407
		if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) ==
408
		    -1) {
409
			switch (la->sa.ss_family) {
410
			case AF_INET:
411
				log_warn("cannot bind to %s:%u",
412
				    log_sockaddr((struct sockaddr *)&la->sa),
413
				    ntohs(((struct sockaddr_in *)
414
				    &la->sa)->sin_port));
415
				break;
416
			case AF_INET6:
417
				log_warn("cannot bind to [%s]:%u",
418
				    log_sockaddr((struct sockaddr *)&la->sa),
419
				    ntohs(((struct sockaddr_in6 *)
420
				    &la->sa)->sin6_port));
421
				break;
422
			default:
423
				log_warn("cannot bind to %s",
424
				    log_sockaddr((struct sockaddr *)&la->sa));
425
				break;
426
			}
427
			close(la->fd);
428
			TAILQ_REMOVE(conf->listen_addrs, la, entry);
429
			free(la);
430
			continue;
431
		}
432
	}
433
}
434
435
int
436
get_mpe_label(struct rdomain *r)
437
{
438
	struct  ifreq	ifr;
439
	struct shim_hdr	shim;
440
	int		s;
441
442
	s = socket(AF_INET, SOCK_DGRAM, 0);
443
	if (s == -1)
444
		return (-1);
445
446
	bzero(&shim, sizeof(shim));
447
	bzero(&ifr, sizeof(ifr));
448
	strlcpy(ifr.ifr_name, r->ifmpe, sizeof(ifr.ifr_name));
449
	ifr.ifr_data = (caddr_t)&shim;
450
451
	if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
452
		close(s);
453
		return (-1);
454
	}
455
	close(s);
456
	r->label = shim.shim_label;
457
	return (0);
458
}