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