xref: /openbsd-src/usr.sbin/bgpd/config.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: config.c,v 1.57 2013/11/13 09:14:48 florian 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 
41 int
42 merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
43     struct peer *peer_l, struct listen_addrs *listen_addrs)
44 {
45 	struct listen_addr			*nla, *ola, *next;
46 
47 	/*
48 	 * merge the freshly parsed conf into the running xconf
49 	 */
50 
51 	/* preserve cmd line opts */
52 	conf->opts = xconf->opts;
53 
54 	if (!conf->as) {
55 		log_warnx("configuration error: AS not given");
56 		return (1);
57 	}
58 
59 	if (!conf->min_holdtime)
60 		conf->min_holdtime = MIN_HOLDTIME;
61 
62 	if (!conf->bgpid)
63 		conf->bgpid = get_bgpid();
64 
65 	if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
66 		conf->clusterid = conf->bgpid;
67 
68 	if (!conf->fib_priority)
69 		conf->fib_priority = RTP_BGP;
70 
71 	free(xconf->csock);
72 	free(xconf->rcsock);
73 
74 	conf->listen_addrs = xconf->listen_addrs;
75 	memcpy(xconf, conf, sizeof(struct bgpd_config));
76 
77 	if (conf->listen_addrs == NULL) {
78 		/* there is no old conf, just copy new one over */
79 		xconf->listen_addrs = listen_addrs;
80 		TAILQ_FOREACH(nla, xconf->listen_addrs, entry)
81 			nla->reconf = RECONF_REINIT;
82 
83 	} else {
84 		/*
85 		 * merge new listeners:
86 		 * -flag all existing ones as to be deleted
87 		 * -those that are in both new and old: flag to keep
88 		 * -new ones get inserted and flagged as to reinit
89 		 * -remove all that are still flagged for deletion
90 		 */
91 
92 		TAILQ_FOREACH(nla, xconf->listen_addrs, entry)
93 			nla->reconf = RECONF_DELETE;
94 
95 		/* no new listeners? preserve default ones */
96 		if (TAILQ_EMPTY(listen_addrs))
97 			TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
98 				if (ola->flags & DEFAULT_LISTENER)
99 					ola->reconf = RECONF_KEEP;
100 
101 		for (nla = TAILQ_FIRST(listen_addrs); nla != NULL; nla = next) {
102 			next = TAILQ_NEXT(nla, entry);
103 
104 			TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
105 				if (!memcmp(&nla->sa, &ola->sa,
106 				    sizeof(nla->sa)))
107 					break;
108 
109 			if (ola == NULL) {
110 				/* new listener, copy over */
111 				TAILQ_REMOVE(listen_addrs, nla, entry);
112 				TAILQ_INSERT_TAIL(xconf->listen_addrs,
113 				    nla, entry);
114 				nla->reconf = RECONF_REINIT;
115 			} else		/* exists, just flag */
116 				ola->reconf = RECONF_KEEP;
117 		}
118 
119 		for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL;
120 		    nla = next) {
121 			next = TAILQ_NEXT(nla, entry);
122 			if (nla->reconf == RECONF_DELETE) {
123 				TAILQ_REMOVE(xconf->listen_addrs, nla, entry);
124 				free(nla);
125 			}
126 		}
127 
128 		while ((ola = TAILQ_FIRST(listen_addrs)) != NULL) {
129 			TAILQ_REMOVE(listen_addrs, ola, entry);
130 			free(ola);
131 		}
132 		free(listen_addrs);
133 	}
134 
135 	return (0);
136 }
137 
138 u_int32_t
139 get_bgpid(void)
140 {
141 	struct ifaddrs		*ifap, *ifa;
142 	u_int32_t		 ip = 0, cur, localnet;
143 
144 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
145 
146 	if (getifaddrs(&ifap) == -1)
147 		fatal("getifaddrs");
148 
149 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
150 		if (ifa->ifa_addr->sa_family != AF_INET)
151 			continue;
152 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
153 		if ((cur & localnet) == localnet)	/* skip 127/8 */
154 			continue;
155 		if (ntohl(cur) > ntohl(ip))
156 			ip = cur;
157 	}
158 	freeifaddrs(ifap);
159 
160 	return (ip);
161 }
162 
163 int
164 host(const char *s, struct bgpd_addr *h, u_int8_t *len)
165 {
166 	int			 done = 0;
167 	int			 mask;
168 	char			*p, *ps;
169 	const char		*errstr;
170 
171 	if ((p = strrchr(s, '/')) != NULL) {
172 		mask = strtonum(p + 1, 0, 128, &errstr);
173 		if (errstr) {
174 			log_warnx("prefixlen is %s: %s", errstr, p + 1);
175 			return (0);
176 		}
177 		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
178 			fatal("host: malloc");
179 		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
180 	} else {
181 		if ((ps = strdup(s)) == NULL)
182 			fatal("host: strdup");
183 		mask = 128;
184 	}
185 
186 	bzero(h, sizeof(struct bgpd_addr));
187 
188 	/* IPv4 address? */
189 	if (!done)
190 		done = host_v4(s, h, len);
191 
192 	/* IPv6 address? */
193 	if (!done) {
194 		done = host_v6(ps, h);
195 		*len = mask;
196 	}
197 
198 	free(ps);
199 
200 	return (done);
201 }
202 
203 int
204 host_v4(const char *s, struct bgpd_addr *h, u_int8_t *len)
205 {
206 	struct in_addr		 ina;
207 	int			 bits = 32;
208 
209 	bzero(&ina, sizeof(struct in_addr));
210 	if (strrchr(s, '/') != NULL) {
211 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
212 			return (0);
213 	} else {
214 		if (inet_pton(AF_INET, s, &ina) != 1)
215 			return (0);
216 	}
217 
218 	h->aid = AID_INET;
219 	h->v4.s_addr = ina.s_addr;
220 	*len = bits;
221 
222 	return (1);
223 }
224 
225 int
226 host_v6(const char *s, struct bgpd_addr *h)
227 {
228 	struct addrinfo		 hints, *res;
229 
230 	bzero(&hints, sizeof(hints));
231 	hints.ai_family = AF_INET6;
232 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
233 	hints.ai_flags = AI_NUMERICHOST;
234 	if (getaddrinfo(s, "0", &hints, &res) == 0) {
235 		sa2addr(res->ai_addr, h);
236 		freeaddrinfo(res);
237 		return (1);
238 	}
239 
240 	return (0);
241 }
242 
243 void
244 prepare_listeners(struct bgpd_config *conf)
245 {
246 	struct listen_addr	*la, *next;
247 	int			 opt = 1;
248 
249 	if (TAILQ_EMPTY(conf->listen_addrs)) {
250 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
251 			fatal("setup_listeners calloc");
252 		la->fd = -1;
253 		la->flags = DEFAULT_LISTENER;
254 		la->reconf = RECONF_REINIT;
255 		la->sa.ss_len = sizeof(struct sockaddr_in);
256 		((struct sockaddr_in *)&la->sa)->sin_family = AF_INET;
257 		((struct sockaddr_in *)&la->sa)->sin_addr.s_addr =
258 		    htonl(INADDR_ANY);
259 		((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT);
260 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
261 
262 		if ((la = calloc(1, sizeof(struct listen_addr))) == NULL)
263 			fatal("setup_listeners calloc");
264 		la->fd = -1;
265 		la->flags = DEFAULT_LISTENER;
266 		la->reconf = RECONF_REINIT;
267 		la->sa.ss_len = sizeof(struct sockaddr_in6);
268 		((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6;
269 		((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT);
270 		TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
271 	}
272 
273 	for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) {
274 		next = TAILQ_NEXT(la, entry);
275 		if (la->reconf != RECONF_REINIT)
276 			continue;
277 
278 		if ((la->fd = socket(la->sa.ss_family, SOCK_STREAM,
279 		    IPPROTO_TCP)) == -1) {
280 			if (la->flags & DEFAULT_LISTENER && (errno ==
281 			    EAFNOSUPPORT || errno == EPROTONOSUPPORT)) {
282 				TAILQ_REMOVE(conf->listen_addrs, la, entry);
283 				free(la);
284 				continue;
285 			} else
286 				fatal("socket");
287 		}
288 
289 		opt = 1;
290 		if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR,
291 		    &opt, sizeof(opt)) == -1)
292 			fatal("setsockopt SO_REUSEADDR");
293 
294 		if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) ==
295 		    -1) {
296 			switch (la->sa.ss_family) {
297 			case AF_INET:
298 				log_warn("cannot bind to %s:%u",
299 				    log_sockaddr((struct sockaddr *)&la->sa),
300 				    ntohs(((struct sockaddr_in *)
301 				    &la->sa)->sin_port));
302 				break;
303 			case AF_INET6:
304 				log_warn("cannot bind to [%s]:%u",
305 				    log_sockaddr((struct sockaddr *)&la->sa),
306 				    ntohs(((struct sockaddr_in6 *)
307 				    &la->sa)->sin6_port));
308 				break;
309 			default:
310 				log_warn("cannot bind to %s",
311 				    log_sockaddr((struct sockaddr *)&la->sa));
312 				break;
313 			}
314 			close(la->fd);
315 			TAILQ_REMOVE(conf->listen_addrs, la, entry);
316 			free(la);
317 			continue;
318 		}
319 	}
320 }
321 
322 int
323 get_mpe_label(struct rdomain *r)
324 {
325 	struct  ifreq	ifr;
326 	struct shim_hdr	shim;
327 	int		s;
328 
329 	s = socket(AF_INET, SOCK_DGRAM, 0);
330 	if (s == -1)
331 		return (-1);
332 
333 	bzero(&shim, sizeof(shim));
334 	bzero(&ifr, sizeof(ifr));
335 	strlcpy(ifr.ifr_name, r->ifmpe, sizeof(ifr.ifr_name));
336 	ifr.ifr_data = (caddr_t)&shim;
337 
338 	if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
339 		close(s);
340 		return (-1);
341 	}
342 	close(s);
343 	r->label = shim.shim_label;
344 	return (0);
345 }
346