GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/config.c Lines: 0 217 0.0 %
Date: 2016-12-06 Branches: 0 137 0.0 %

Line Branch Exec Source
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
}