Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2010 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/stat.h>
     29 #include <sys/uio.h>
     30 #include <sys/wait.h>
     31 
     32 #include <netinet/in.h>
     33 #include <arpa/inet.h>
     34 
     35 #include <ctype.h>
     36 #include <errno.h>
     37 #include <signal.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <syslog.h>
     41 #include <unistd.h>
     42 
     43 #include "config.h"
     44 #include "common.h"
     45 #include "configure.h"
     46 #include "dhcp.h"
     47 #include "if-options.h"
     48 #include "if-pref.h"
     49 #include "net.h"
     50 #include "signals.h"
     51 
     52 #define DEFAULT_PATH	"PATH=/usr/bin:/usr/sbin:/bin:/sbin"
     53 
     54 /* Some systems have route metrics */
     55 #ifndef HAVE_ROUTE_METRIC
     56 # ifdef __linux__
     57 #  define HAVE_ROUTE_METRIC 1
     58 # endif
     59 # ifndef HAVE_ROUTE_METRIC
     60 #  define HAVE_ROUTE_METRIC 0
     61 # endif
     62 #endif
     63 
     64 static struct rt *routes;
     65 
     66 
     67 static int
     68 exec_script(char *const *argv, char *const *env)
     69 {
     70 	pid_t pid;
     71 	sigset_t full;
     72 	sigset_t old;
     73 
     74 	/* OK, we need to block signals */
     75 	sigfillset(&full);
     76 	sigprocmask(SIG_SETMASK, &full, &old);
     77 	signal_reset();
     78 
     79 	switch (pid = vfork()) {
     80 	case -1:
     81 		syslog(LOG_ERR, "vfork: %m");
     82 		break;
     83 	case 0:
     84 		sigprocmask(SIG_SETMASK, &old, NULL);
     85 		execve(argv[0], argv, env);
     86 		syslog(LOG_ERR, "%s: %m", argv[0]);
     87 		_exit(127);
     88 		/* NOTREACHED */
     89 	}
     90 
     91 	/* Restore our signals */
     92 	signal_setup();
     93 	sigprocmask(SIG_SETMASK, &old, NULL);
     94 	return pid;
     95 }
     96 
     97 static char *
     98 make_var(const char *prefix, const char *var)
     99 {
    100 	size_t len;
    101 	char *v;
    102 
    103 	len = strlen(prefix) + strlen(var) + 2;
    104 	v = xmalloc(len);
    105 	snprintf(v, len, "%s_%s", prefix, var);
    106 	return v;
    107 }
    108 
    109 
    110 static void
    111 append_config(char ***env, ssize_t *len,
    112     const char *prefix, const char *const *config)
    113 {
    114 	ssize_t i, j, e1;
    115 	char **ne, *eq;
    116 
    117 	if (config == NULL)
    118 		return;
    119 
    120 	ne = *env;
    121 	for (i = 0; config[i] != NULL; i++) {
    122 		eq = strchr(config[i], '=');
    123 		e1 = eq - config[i] + 1;
    124 		for (j = 0; j < *len; j++) {
    125 			if (strncmp(ne[j] + strlen(prefix) + 1,
    126 				config[i], e1) == 0)
    127 			{
    128 				free(ne[j]);
    129 				ne[j] = make_var(prefix, config[i]);
    130 				break;
    131 			}
    132 		}
    133 		if (j == *len) {
    134 			j++;
    135 			ne = xrealloc(ne, sizeof(char *) * (j + 1));
    136 			ne[j - 1] = make_var(prefix, config[i]);
    137 			*len = j;
    138 		}
    139 	}
    140 	*env = ne;
    141 }
    142 
    143 static size_t
    144 arraytostr(const char *const *argv, char **s)
    145 {
    146 	const char *const *ap;
    147 	char *p;
    148 	size_t len, l;
    149 
    150 	len = 0;
    151 	ap = argv;
    152 	while (*ap)
    153 		len += strlen(*ap++) + 1;
    154 	*s = p = xmalloc(len);
    155 	ap = argv;
    156 	while (*ap) {
    157 		l = strlen(*ap) + 1;
    158 		memcpy(p, *ap, l);
    159 		p += l;
    160 		ap++;
    161 	}
    162 	return len;
    163 }
    164 
    165 static ssize_t
    166 make_env(const struct interface *iface, char ***argv)
    167 {
    168 	char **env, *p;
    169 	ssize_t e, elen, l;
    170 	const struct if_options *ifo = iface->state->options;
    171 	const struct interface *ifp;
    172 
    173 	/* Make our env */
    174 	elen = 8;
    175 	env = xmalloc(sizeof(char *) * (elen + 1));
    176 	e = strlen("interface") + strlen(iface->name) + 2;
    177 	env[0] = xmalloc(e);
    178 	snprintf(env[0], e, "interface=%s", iface->name);
    179 	e = strlen("reason") + strlen(iface->state->reason) + 2;
    180 	env[1] = xmalloc(e);
    181 	snprintf(env[1], e, "reason=%s", iface->state->reason);
    182 	e = 20;
    183 	env[2] = xmalloc(e);
    184 	snprintf(env[2], e, "pid=%d", getpid());
    185 	env[3] = xmalloc(e);
    186 	snprintf(env[3], e, "ifmetric=%d", iface->metric);
    187 	env[4] = xmalloc(e);
    188 	snprintf(env[4], e, "ifwireless=%d", iface->wireless);
    189 	env[5] = xmalloc(e);
    190 	snprintf(env[5], e, "ifflags=%u", iface->flags);
    191 	env[6] = xmalloc(e);
    192 	snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
    193 	l = e = strlen("interface_order=");
    194 	for (ifp = ifaces; ifp; ifp = ifp->next)
    195 		e += strlen(ifp->name) + 1;
    196 	p = env[7] = xmalloc(e);
    197 	strlcpy(p, "interface_order=", e);
    198 	e -= l;
    199 	p += l;
    200 	for (ifp = ifaces; ifp; ifp = ifp->next) {
    201 		l = strlcpy(p, ifp->name, e);
    202 		p += l;
    203 		e -= l;
    204 		*p++ = ' ';
    205 		e--;
    206 	}
    207 	*--p = '\0';
    208 	if (*iface->state->profile) {
    209 		e = strlen("profile=") + strlen(iface->state->profile) + 2;
    210 		env[elen] = xmalloc(e);
    211 		snprintf(env[elen++], e, "profile=%s", iface->state->profile);
    212 	}
    213 	if (iface->wireless) {
    214 		e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
    215 		if (iface->state->new != NULL ||
    216 		    strcmp(iface->state->reason, "CARRIER") == 0)
    217 		{
    218 			env = xrealloc(env, sizeof(char *) * (elen + 2));
    219 			env[elen] = xmalloc(e);
    220 			snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
    221 		}
    222 		if (iface->state->old != NULL ||
    223 		    strcmp(iface->state->reason, "NOCARRIER") == 0)
    224 		{
    225 			env = xrealloc(env, sizeof(char *) * (elen + 2));
    226 			env[elen] = xmalloc(e);
    227 			snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
    228 		}
    229 	}
    230 	if (iface->state->old) {
    231 		e = configure_env(NULL, NULL, iface->state->old, ifo);
    232 		if (e > 0) {
    233 			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    234 			elen += configure_env(env + elen, "old",
    235 			    iface->state->old, ifo);
    236 		}
    237 		append_config(&env, &elen, "old",
    238 		    (const char *const *)ifo->config);
    239 	}
    240 	if (iface->state->new) {
    241 		e = configure_env(NULL, NULL, iface->state->new, ifo);
    242 		if (e > 0) {
    243 			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    244 			elen += configure_env(env + elen, "new",
    245 			    iface->state->new, ifo);
    246 		}
    247 		append_config(&env, &elen, "new",
    248 		    (const char *const *)ifo->config);
    249 	}
    250 
    251 	/* Add our base environment */
    252 	if (ifo->environ) {
    253 		e = 0;
    254 		while (ifo->environ[e++])
    255 			;
    256 		env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    257 		e = 0;
    258 		while (ifo->environ[e]) {
    259 			env[elen + e] = xstrdup(ifo->environ[e]);
    260 			e++;
    261 		}
    262 		elen += e;
    263 	}
    264 	env[elen] = '\0';
    265 
    266 	*argv = env;
    267 	return elen;
    268 }
    269 
    270 int
    271 send_interface(int fd, const struct interface *iface)
    272 {
    273 	char **env, **ep, *s;
    274 	ssize_t elen;
    275 	struct iovec iov[2];
    276 	int retval;
    277 
    278 	retval = 0;
    279 	make_env(iface, &env);
    280 	elen = arraytostr((const char *const *)env, &s);
    281 	iov[0].iov_base = &elen;
    282 	iov[0].iov_len = sizeof(ssize_t);
    283 	iov[1].iov_base = s;
    284 	iov[1].iov_len = elen;
    285 	retval = writev(fd, iov, 2);
    286 	ep = env;
    287 	while (*ep)
    288 		free(*ep++);
    289 	free(env);
    290 	free(s);
    291 	return retval;
    292 }
    293 
    294 int
    295 run_script(const struct interface *iface)
    296 {
    297 	char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
    298 	char **env = NULL, **ep;
    299 	char *path, *bigenv;
    300 	ssize_t e, elen = 0;
    301 	pid_t pid;
    302 	int status = 0;
    303 	const struct fd_list *fd;
    304 	struct iovec iov[2];
    305 
    306 	syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
    307 	    iface->name, argv[0], iface->state->reason);
    308 
    309 	/* Make our env */
    310 	elen = make_env(iface, &env);
    311 	env = xrealloc(env, sizeof(char *) * (elen + 2));
    312 	/* Add path to it */
    313 	path = getenv("PATH");
    314 	if (path) {
    315 		e = strlen("PATH") + strlen(path) + 2;
    316 		env[elen] = xmalloc(e);
    317 		snprintf(env[elen], e, "PATH=%s", path);
    318 	} else
    319 		env[elen] = xstrdup(DEFAULT_PATH);
    320 	env[++elen] = '\0';
    321 
    322 	pid = exec_script(argv, env);
    323 	if (pid == -1)
    324 		status = -1;
    325 	else if (pid != 0) {
    326 		/* Wait for the script to finish */
    327 		while (waitpid(pid, &status, 0) == -1) {
    328 			if (errno != EINTR) {
    329 				syslog(LOG_ERR, "waitpid: %m");
    330 				status = -1;
    331 				break;
    332 			}
    333 		}
    334 	}
    335 
    336 	/* Send to our listeners */
    337 	bigenv = NULL;
    338 	for (fd = fds; fd != NULL; fd = fd->next) {
    339 		if (fd->listener) {
    340 			if (bigenv == NULL) {
    341 				elen = arraytostr((const char *const *)env,
    342 				    &bigenv);
    343 				iov[0].iov_base = &elen;
    344 				iov[0].iov_len = sizeof(ssize_t);
    345 				iov[1].iov_base = bigenv;
    346 				iov[1].iov_len = elen;
    347 			}
    348 			if (writev(fd->fd, iov, 2) == -1)
    349 				syslog(LOG_ERR, "writev: %m");
    350 		}
    351 	}
    352 	free(bigenv);
    353 
    354 	/* Cleanup */
    355 	ep = env;
    356 	while (*ep)
    357 		free(*ep++);
    358 	free(env);
    359 	return status;
    360 }
    361 
    362 static struct rt *
    363 find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
    364     const struct rt *srt)
    365 {
    366 	struct rt *rt;
    367 
    368 	if (lrt)
    369 		*lrt = NULL;
    370 	for (rt = rts; rt; rt = rt->next) {
    371 		if (rt->dest.s_addr == r->dest.s_addr &&
    372 #if HAVE_ROUTE_METRIC
    373 		    (srt || (!rt->iface ||
    374 			rt->iface->metric == r->iface->metric)) &&
    375 #endif
    376                     (!srt || srt != rt) &&
    377 		    rt->net.s_addr == r->net.s_addr)
    378 			return rt;
    379 		if (lrt)
    380 			*lrt = rt;
    381 	}
    382 	return NULL;
    383 }
    384 
    385 static void
    386 desc_route(const char *cmd, const struct rt *rt, const char *ifname)
    387 {
    388 	char addr[sizeof("000.000.000.000") + 1];
    389 
    390 	strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
    391 	if (rt->gate.s_addr == INADDR_ANY)
    392 		syslog(LOG_DEBUG, "%s: %s route to %s/%d", ifname, cmd,
    393 		    addr, inet_ntocidr(rt->net));
    394 	else if (rt->gate.s_addr == rt->dest.s_addr &&
    395 	    rt->net.s_addr == INADDR_BROADCAST)
    396 		syslog(LOG_DEBUG, "%s: %s host route to %s", ifname, cmd,
    397 		    addr);
    398 	else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
    399 		syslog(LOG_DEBUG, "%s: %s default route via %s", ifname, cmd,
    400 		    inet_ntoa(rt->gate));
    401 	else
    402 		syslog(LOG_DEBUG, "%s: %s route to %s/%d via %s", ifname, cmd,
    403 		    addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
    404 }
    405 
    406 /* If something other than dhcpcd removes a route,
    407  * we need to remove it from our internal table. */
    408 int
    409 route_deleted(const struct rt *rt)
    410 {
    411 	struct rt *f, *l;
    412 
    413 	f = find_route(routes, rt, &l, NULL);
    414 	if (f == NULL)
    415 		return 0;
    416 	desc_route("removing", f, f->iface->name);
    417 	if (l)
    418 		l->next = f->next;
    419 	else
    420 		routes = f->next;
    421 	free(f);
    422 	return 1;
    423 }
    424 
    425 static int
    426 n_route(struct rt *rt, const struct interface *iface)
    427 {
    428 	/* Don't set default routes if not asked to */
    429 	if (rt->dest.s_addr == 0 &&
    430 	    rt->net.s_addr == 0 &&
    431 	    !(iface->state->options->options & DHCPCD_GATEWAY))
    432 		return -1;
    433 
    434 	desc_route("adding", rt, iface->name);
    435 	if (!add_route(iface, &rt->dest, &rt->net, &rt->gate, iface->metric))
    436 		return 0;
    437 	if (errno == EEXIST) {
    438 		/* Pretend we added the subnet route */
    439 		if (rt->dest.s_addr == (iface->addr.s_addr & iface->net.s_addr) &&
    440 		    rt->net.s_addr == iface->net.s_addr &&
    441 		    rt->gate.s_addr == 0)
    442 			return 0;
    443 		else
    444 			return -1;
    445 	}
    446 	syslog(LOG_ERR, "%s: add_route: %m", iface->name);
    447 	return -1;
    448 }
    449 
    450 static int
    451 c_route(struct rt *ort, struct rt *nrt, const struct interface *iface)
    452 {
    453 	/* Don't set default routes if not asked to */
    454 	if (nrt->dest.s_addr == 0 &&
    455 	    nrt->net.s_addr == 0 &&
    456 	    !(iface->state->options->options & DHCPCD_GATEWAY))
    457 		return -1;
    458 
    459 	desc_route("changing", nrt, iface->name);
    460 	/* We delete and add the route so that we can change metric.
    461 	 * This also has the nice side effect of flushing ARP entries so
    462 	 * we don't have to do that manually. */
    463 	del_route(ort->iface, &ort->dest, &ort->net, &ort->gate,
    464 	    ort->iface->metric);
    465 	if (!add_route(iface, &nrt->dest, &nrt->net, &nrt->gate,
    466 		iface->metric))
    467 		return 0;
    468 	syslog(LOG_ERR, "%s: add_route: %m", iface->name);
    469 	return -1;
    470 }
    471 
    472 static int
    473 d_route(struct rt *rt, const struct interface *iface, int metric)
    474 {
    475 	int retval;
    476 
    477 	desc_route("deleting", rt, iface->name);
    478 	retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
    479 	if (retval != 0 && errno != ENOENT && errno != ESRCH)
    480 		syslog(LOG_ERR,"%s: del_route: %m", iface->name);
    481 	return retval;
    482 }
    483 
    484 static struct rt *
    485 get_subnet_route(struct dhcp_message *dhcp)
    486 {
    487 	in_addr_t addr;
    488 	struct in_addr net;
    489 	struct rt *rt;
    490 
    491 	addr = dhcp->yiaddr;
    492 	if (addr == 0)
    493 		addr = dhcp->ciaddr;
    494 	/* Ensure we have all the needed values */
    495 	if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
    496 		net.s_addr = get_netmask(addr);
    497 	if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
    498 		return NULL;
    499 	rt = malloc(sizeof(*rt));
    500 	rt->dest.s_addr = addr & net.s_addr;
    501 	rt->net.s_addr = net.s_addr;
    502 	rt->gate.s_addr = 0;
    503 	return rt;
    504 }
    505 
    506 static struct rt *
    507 add_subnet_route(struct rt *rt, const struct interface *iface)
    508 {
    509 	struct rt *r;
    510 
    511 	if (iface->net.s_addr == INADDR_BROADCAST ||
    512 	    iface->net.s_addr == INADDR_ANY ||
    513 	    (iface->state->options->options &
    514 	     (DHCPCD_INFORM | DHCPCD_STATIC) &&
    515 	     iface->state->options->req_addr.s_addr == INADDR_ANY))
    516 		return rt;
    517 
    518 	r = xmalloc(sizeof(*r));
    519 	r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
    520 	r->net.s_addr = iface->net.s_addr;
    521 	r->gate.s_addr = 0;
    522 	r->next = rt;
    523 	return r;
    524 }
    525 
    526 static struct rt *
    527 get_routes(const struct interface *iface)
    528 {
    529 	struct rt *rt, *nrt = NULL, *r = NULL;
    530 
    531 	if (iface->state->options->routes != NULL) {
    532 		for (rt = iface->state->options->routes;
    533 		     rt != NULL;
    534 		     rt = rt->next)
    535 		{
    536 			if (rt->gate.s_addr == 0)
    537 				break;
    538 			if (r == NULL)
    539 				r = nrt = xmalloc(sizeof(*r));
    540 			else {
    541 				r->next = xmalloc(sizeof(*r));
    542 				r = r->next;
    543 			}
    544 			memcpy(r, rt, sizeof(*r));
    545 			r->next = NULL;
    546 		}
    547 		return nrt;
    548 	}
    549 
    550 	return get_option_routes(iface->state->new,
    551 	    iface->name, &iface->state->options->options);
    552 }
    553 
    554 /* Some DHCP servers add set host routes by setting the gateway
    555  * to the assinged IP address. This differs from our notion of a host route
    556  * where the gateway is the destination address, so we fix it. */
    557 static struct rt *
    558 massage_host_routes(struct rt *rt, const struct interface *iface)
    559 {
    560 	struct rt *r;
    561 
    562 	for (r = rt; r; r = r->next)
    563 		if (r->gate.s_addr == iface->addr.s_addr &&
    564 		    r->net.s_addr == INADDR_BROADCAST)
    565 			r->gate.s_addr = r->dest.s_addr;
    566 	return rt;
    567 }
    568 
    569 static struct rt *
    570 add_destination_route(struct rt *rt, const struct interface *iface)
    571 {
    572 	struct rt *r;
    573 
    574 	if (!(iface->flags & IFF_POINTOPOINT) ||
    575 	    !has_option_mask(iface->state->options->dstmask, DHO_ROUTER))
    576 		return rt;
    577 	r = xmalloc(sizeof(*r));
    578 	r->dest.s_addr = INADDR_ANY;
    579 	r->net.s_addr = INADDR_ANY;
    580 	r->gate.s_addr = iface->dst.s_addr;
    581 	r->next = rt;
    582 	return r;
    583 }
    584 
    585 /* We should check to ensure the routers are on the same subnet
    586  * OR supply a host route. If not, warn and add a host route. */
    587 static struct rt *
    588 add_router_host_route(struct rt *rt, const struct interface *ifp)
    589 {
    590 	struct rt *rtp, *rtl, *rtn;
    591 	const char *cp, *cp2, *cp3, *cplim;
    592 
    593 	for (rtp = rt, rtl = NULL; rtp; rtl = rtp, rtp = rtp->next) {
    594 		if (rtp->dest.s_addr != INADDR_ANY)
    595 			continue;
    596 		/* Scan for a route to match */
    597 		for (rtn = rt; rtn != rtp; rtn = rtn->next) {
    598 			/* match host */
    599 			if (rtn->dest.s_addr == rtp->gate.s_addr)
    600 				break;
    601 			/* match subnet */
    602 			cp = (const char *)&rtp->gate.s_addr;
    603 			cp2 = (const char *)&rtn->dest.s_addr;
    604 			cp3 = (const char *)&rtn->net.s_addr;
    605 			cplim = cp3 + sizeof(rtn->net.s_addr);
    606 			while (cp3 < cplim) {
    607 				if ((*cp++ ^ *cp2++) & *cp3++)
    608 					break;
    609 			}
    610 			if (cp3 == cplim)
    611 				break;
    612 		}
    613 		if (rtn != rtp)
    614 			continue;
    615 		if (ifp->flags & IFF_NOARP) {
    616 			syslog(LOG_WARNING,
    617 			    "%s: forcing router %s through interface",
    618 			    ifp->name, inet_ntoa(rtp->gate));
    619 			rtp->gate.s_addr = 0;
    620 			continue;
    621 		}
    622 		syslog(LOG_WARNING, "%s: router %s requires a host route",
    623 		    ifp->name, inet_ntoa(rtp->gate));
    624 		rtn = xmalloc(sizeof(*rtn));
    625 		rtn->dest.s_addr = rtp->gate.s_addr;
    626 		rtn->net.s_addr = INADDR_BROADCAST;
    627 		rtn->gate.s_addr = rtp->gate.s_addr;
    628 		rtn->next = rtp;
    629 		if (rtl == NULL)
    630 			rt = rtn;
    631 		else
    632 			rtl->next = rtn;
    633 	}
    634 	return rt;
    635 }
    636 
    637 void
    638 build_routes(void)
    639 {
    640 	struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
    641 	const struct interface *ifp;
    642 
    643 	if (avoid_routes) return;
    644 
    645 	for (ifp = ifaces; ifp; ifp = ifp->next) {
    646 		if (ifp->state->new == NULL)
    647 			continue;
    648 		dnr = get_routes(ifp);
    649 		dnr = massage_host_routes(dnr, ifp);
    650 		dnr = add_subnet_route(dnr, ifp);
    651 		dnr = add_router_host_route(dnr, ifp);
    652 		dnr = add_destination_route(dnr, ifp);
    653 		for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
    654 			rt->iface = ifp;
    655 			/* Is this route already in our table? */
    656 			if ((find_route(nrs, rt, NULL, NULL)) != NULL)
    657 				continue;
    658 			/* Do we already manage it? */
    659 			if ((or = find_route(routes, rt, &rtl, NULL))) {
    660 				if (or->iface != ifp ||
    661 				    rt->gate.s_addr != or->gate.s_addr)
    662 				{
    663 					if (c_route(or, rt, ifp) != 0)
    664 						continue;
    665 				}
    666 				if (rtl != NULL)
    667 					rtl->next = or->next;
    668 				else
    669 					routes = or->next;
    670 				free(or);
    671 			} else {
    672 				if (n_route(rt, ifp) != 0)
    673 					continue;
    674 			}
    675 			if (dnr == rt)
    676 				dnr = rtn;
    677 			else if (lrt)
    678 				lrt->next = rtn;
    679 			rt->next = nrs;
    680 			nrs = rt;
    681 		}
    682 		free_routes(dnr);
    683 	}
    684 
    685 	/* Remove old routes we used to manage */
    686 	for (rt = routes; rt; rt = rt->next) {
    687 		if (find_route(nrs, rt, NULL, NULL) == NULL)
    688 			d_route(rt, rt->iface, rt->iface->metric);
    689 	}
    690 
    691 	free_routes(routes);
    692 	routes = nrs;
    693 }
    694 
    695 static int
    696 delete_address(struct interface *iface)
    697 {
    698 	int retval;
    699 	struct if_options *ifo;
    700 
    701 	ifo = iface->state->options;
    702 	if (ifo->options & DHCPCD_INFORM ||
    703 	    (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
    704 		return 0;
    705 	syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
    706 	    iface->name,
    707 	    inet_ntoa(iface->addr),
    708 	    inet_ntocidr(iface->net));
    709 	retval = del_address(iface, &iface->addr, &iface->net);
    710 	if (retval == -1 && errno != EADDRNOTAVAIL)
    711 		syslog(LOG_ERR, "del_address: %m");
    712 	iface->addr.s_addr = 0;
    713 	iface->net.s_addr = 0;
    714 	return retval;
    715 }
    716 
    717 int
    718 configure(struct interface *iface)
    719 {
    720 	struct dhcp_message *dhcp = iface->state->new;
    721 	struct dhcp_lease *lease = &iface->state->lease;
    722 	struct if_options *ifo = iface->state->options;
    723 	struct rt *rt;
    724 
    725 	/* As we are now adjusting an interface, we need to ensure
    726 	 * we have them in the right order for routing and configuration. */
    727 	sort_interfaces();
    728 
    729 	if (dhcp == NULL) {
    730 		if (!(ifo->options & DHCPCD_PERSISTENT)) {
    731 			build_routes();
    732 			if (iface->addr.s_addr != 0)
    733 				delete_address(iface);
    734 			run_script(iface);
    735 		}
    736 		return 0;
    737 	}
    738 
    739 	/* This also changes netmask */
    740 	if (!(ifo->options & DHCPCD_INFORM) ||
    741 	    !has_address(iface->name, &lease->addr, &lease->net))
    742 	{
    743 		syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
    744 		    iface->name, inet_ntoa(lease->addr),
    745 		    inet_ntocidr(lease->net));
    746 		if (add_address(iface,
    747 			&lease->addr, &lease->net, &lease->brd) == -1 &&
    748 		    errno != EEXIST)
    749 		{
    750 			syslog(LOG_ERR, "add_address: %m");
    751 			return -1;
    752 		}
    753 	}
    754 
    755 	/* Now delete the old address if different */
    756 	if (iface->addr.s_addr != lease->addr.s_addr &&
    757 	    iface->addr.s_addr != 0)
    758 		delete_address(iface);
    759 
    760 	iface->addr.s_addr = lease->addr.s_addr;
    761 	iface->net.s_addr = lease->net.s_addr;
    762 
    763 	if (!avoid_routes) {
    764 		/* We need to delete the subnet route to have our metric or
    765 		 * prefer the interface. */
    766 		rt = get_subnet_route(dhcp);
    767 		if (rt != NULL) {
    768 			rt->iface = iface;
    769 			if (!find_route(routes, rt, NULL, NULL))
    770 				del_route(iface, &rt->dest, &rt->net, &rt->gate, 0);
    771 			free(rt);
    772 		}
    773 
    774 		build_routes();
    775 	}
    776 
    777 	if (!iface->state->lease.frominfo &&
    778 	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
    779 		if (write_lease(iface, dhcp) == -1)
    780 			syslog(LOG_ERR, "write_lease: %m");
    781 	run_script(iface);
    782 	return 0;
    783 }
    784