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