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