Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2012 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 "ipv6rs.h"
     50 #include "net.h"
     51 #include "signals.h"
     52 
     53 #define DEFAULT_PATH	"PATH=/usr/bin:/usr/sbin:/bin:/sbin"
     54 
     55 /* Some systems have route metrics */
     56 #ifndef HAVE_ROUTE_METRIC
     57 # ifdef __linux__
     58 #  define HAVE_ROUTE_METRIC 1
     59 # endif
     60 # ifndef HAVE_ROUTE_METRIC
     61 #  define HAVE_ROUTE_METRIC 0
     62 # endif
     63 #endif
     64 
     65 static struct rt *routes;
     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, const char *reason, 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 	int dhcp, ra;
    173 
    174 	dhcp = ra = 0;
    175 	if (strcmp(reason, "ROUTERADVERT") == 0)
    176 		ra = 1;
    177 	else
    178 		dhcp = 1;
    179 
    180 	/* When dumping the lease, we only want to report interface and
    181 	   reason - the other interface variables are meaningless */
    182 	if (options & DHCPCD_DUMPLEASE)
    183 		elen = 2;
    184 	else
    185 		elen = 10;
    186 
    187 	/* Make our env */
    188 	env = xmalloc(sizeof(char *) * (elen + 1));
    189 	e = strlen("interface") + strlen(iface->name) + 2;
    190 	env[0] = xmalloc(e);
    191 	snprintf(env[0], e, "interface=%s", iface->name);
    192 	e = strlen("reason") + strlen(reason) + 2;
    193 	env[1] = xmalloc(e);
    194 	snprintf(env[1], e, "reason=%s", reason);
    195 	if (options & DHCPCD_DUMPLEASE)
    196 		goto dumplease;
    197 
    198  	e = 20;
    199 	env[2] = xmalloc(e);
    200 	snprintf(env[2], e, "pid=%d", getpid());
    201 	env[3] = xmalloc(e);
    202 	snprintf(env[3], e, "ifmetric=%d", iface->metric);
    203 	env[4] = xmalloc(e);
    204 	snprintf(env[4], e, "ifwireless=%d", iface->wireless);
    205 	env[5] = xmalloc(e);
    206 	snprintf(env[5], e, "ifflags=%u", iface->flags);
    207 	env[6] = xmalloc(e);
    208 	snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
    209 	l = e = strlen("interface_order=");
    210 	for (ifp = ifaces; ifp; ifp = ifp->next)
    211 		e += strlen(ifp->name) + 1;
    212 	p = env[7] = xmalloc(e);
    213 	strlcpy(p, "interface_order=", e);
    214 	e -= l;
    215 	p += l;
    216 	for (ifp = ifaces; ifp; ifp = ifp->next) {
    217 		l = strlcpy(p, ifp->name, e);
    218 		p += l;
    219 		e -= l;
    220 		*p++ = ' ';
    221 		e--;
    222 	}
    223 	*--p = '\0';
    224 	if ((dhcp && iface->state->new) || (ra && iface->ras)) {
    225 		env[8] = strdup("if_up=true");
    226 		env[9] = strdup("if_down=false");
    227 	} else {
    228 		env[8] = strdup("if_up=false");
    229 		env[9] = strdup("if_down=true");
    230 	}
    231 	if (*iface->state->profile) {
    232 		e = strlen("profile=") + strlen(iface->state->profile) + 2;
    233 		env[elen] = xmalloc(e);
    234 		snprintf(env[elen++], e, "profile=%s", iface->state->profile);
    235 	}
    236 	if (iface->wireless) {
    237 		e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
    238 		if (iface->state->new != NULL ||
    239 		    strcmp(iface->state->reason, "CARRIER") == 0)
    240 		{
    241 			env = xrealloc(env, sizeof(char *) * (elen + 2));
    242 			env[elen] = xmalloc(e);
    243 			snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
    244 		}
    245 		if (iface->state->old != NULL ||
    246 		    strcmp(iface->state->reason, "NOCARRIER") == 0)
    247 		{
    248 			env = xrealloc(env, sizeof(char *) * (elen + 2));
    249 			env[elen] = xmalloc(e);
    250 			snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
    251 		}
    252 	}
    253 	if (dhcp && iface->state->old) {
    254 		e = configure_env(NULL, NULL, iface->state->old, ifo);
    255 		if (e > 0) {
    256 			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    257 			elen += configure_env(env + elen, "old",
    258 			    iface->state->old, ifo);
    259 		}
    260 		append_config(&env, &elen, "old",
    261 		    (const char *const *)ifo->config);
    262 	}
    263 
    264 dumplease:
    265 	if (dhcp && iface->state->new) {
    266 		e = configure_env(NULL, NULL, iface->state->new, ifo);
    267 		if (e > 0) {
    268 			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    269 			elen += configure_env(env + elen, "new",
    270 			    iface->state->new, ifo);
    271 		}
    272 		append_config(&env, &elen, "new",
    273 		    (const char *const *)ifo->config);
    274 	}
    275 	if (ra) {
    276 		e = ipv6rs_env(NULL, NULL, iface);
    277 		if (e > 0) {
    278 			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    279 			elen += ipv6rs_env(env + elen, NULL, iface);
    280 		}
    281 	}
    282 
    283 	/* Add our base environment */
    284 	if (ifo->environ) {
    285 		e = 0;
    286 		while (ifo->environ[e++])
    287 			;
    288 		env = xrealloc(env, sizeof(char *) * (elen + e + 1));
    289 		e = 0;
    290 		while (ifo->environ[e]) {
    291 			env[elen + e] = xstrdup(ifo->environ[e]);
    292 			e++;
    293 		}
    294 		elen += e;
    295 	}
    296 	env[elen] = '\0';
    297 
    298 	*argv = env;
    299 	return elen;
    300 }
    301 
    302 static int
    303 send_interface1(int fd, const struct interface *iface, const char *reason)
    304 {
    305 	char **env, **ep, *s;
    306 	ssize_t elen;
    307 	struct iovec iov[2];
    308 	int retval;
    309 
    310 	retval = 0;
    311 	make_env(iface, reason, &env);
    312 	elen = arraytostr((const char *const *)env, &s);
    313 	iov[0].iov_base = &elen;
    314 	iov[0].iov_len = sizeof(ssize_t);
    315 	iov[1].iov_base = s;
    316 	iov[1].iov_len = elen;
    317 	retval = writev(fd, iov, 2);
    318 	ep = env;
    319 	while (*ep)
    320 		free(*ep++);
    321 	free(env);
    322 	free(s);
    323 	return retval;
    324 }
    325 
    326 int
    327 send_interface(int fd, const struct interface *iface)
    328 {
    329 	int retval = 0;
    330 	if (send_interface1(fd, iface, iface->state->reason) == -1)
    331 		retval = -1;
    332 	if (iface->ras) {
    333 		if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
    334 			retval = -1;
    335 	}
    336 	return retval;
    337 }
    338 
    339 int
    340 run_script_reason(const struct interface *iface, const char *reason)
    341 {
    342 	char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
    343 	char **env = NULL, **ep;
    344 	char *path, *bigenv;
    345 	ssize_t e, elen = 0;
    346 	pid_t pid;
    347 	int status = 0;
    348 	const struct fd_list *fd;
    349 	struct iovec iov[2];
    350 
    351 	if (iface->state->options->script == NULL ||
    352 	    iface->state->options->script[0] == '\0' ||
    353 	    strcmp(iface->state->options->script, "/dev/null") == 0)
    354 		return 0;
    355 
    356 	if (reason == NULL)
    357 		reason = iface->state->reason;
    358 	syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
    359 	    iface->name, argv[0], reason);
    360 
    361 	/* Make our env */
    362 	elen = make_env(iface, reason, &env);
    363 	env = xrealloc(env, sizeof(char *) * (elen + 2));
    364 	/* Add path to it */
    365 	path = getenv("PATH");
    366 	if (path) {
    367 		e = strlen("PATH") + strlen(path) + 2;
    368 		env[elen] = xmalloc(e);
    369 		snprintf(env[elen], e, "PATH=%s", path);
    370 	} else
    371 		env[elen] = xstrdup(DEFAULT_PATH);
    372 	env[++elen] = '\0';
    373 
    374 	pid = exec_script(argv, env);
    375 	if (pid == -1)
    376 		status = -1;
    377 	else if (pid != 0) {
    378 		/* Wait for the script to finish */
    379 		while (waitpid(pid, &status, 0) == -1) {
    380 			if (errno != EINTR) {
    381 				syslog(LOG_ERR, "waitpid: %m");
    382 				status = -1;
    383 				break;
    384 			}
    385 		}
    386 	}
    387 
    388 	/* Send to our listeners */
    389 	bigenv = NULL;
    390 	for (fd = fds; fd != NULL; fd = fd->next) {
    391 		if (fd->listener) {
    392 			if (bigenv == NULL) {
    393 				elen = arraytostr((const char *const *)env,
    394 				    &bigenv);
    395 				iov[0].iov_base = &elen;
    396 				iov[0].iov_len = sizeof(ssize_t);
    397 				iov[1].iov_base = bigenv;
    398 				iov[1].iov_len = elen;
    399 			}
    400 			if (writev(fd->fd, iov, 2) == -1)
    401 				syslog(LOG_ERR, "writev: %m");
    402 		}
    403 	}
    404 	free(bigenv);
    405 
    406 	/* Cleanup */
    407 	ep = env;
    408 	while (*ep)
    409 		free(*ep++);
    410 	free(env);
    411 	return status;
    412 }
    413 
    414 static struct rt *
    415 find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
    416     const struct rt *srt)
    417 {
    418 	struct rt *rt;
    419 
    420 	if (lrt)
    421 		*lrt = NULL;
    422 	for (rt = rts; rt; rt = rt->next) {
    423 		if (rt->dest.s_addr == r->dest.s_addr &&
    424 #if HAVE_ROUTE_METRIC
    425 		    (srt || (!rt->iface ||
    426 			rt->iface->metric == r->iface->metric)) &&
    427 #endif
    428                     (!srt || srt != rt) &&
    429 		    rt->net.s_addr == r->net.s_addr)
    430 			return rt;
    431 		if (lrt)
    432 			*lrt = rt;
    433 	}
    434 	return NULL;
    435 }
    436 
    437 static void
    438 desc_route(const char *cmd, const struct rt *rt)
    439 {
    440 	char addr[sizeof("000.000.000.000") + 1];
    441 	const char *ifname = rt->iface->name;
    442 
    443 	strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
    444 	if (rt->gate.s_addr == INADDR_ANY)
    445 		syslog(LOG_DEBUG, "%s: %s route to %s/%d", ifname, cmd,
    446 		    addr, inet_ntocidr(rt->net));
    447 	else if (rt->gate.s_addr == rt->dest.s_addr &&
    448 	    rt->net.s_addr == INADDR_BROADCAST)
    449 		syslog(LOG_DEBUG, "%s: %s host route to %s", ifname, cmd,
    450 		    addr);
    451 	else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
    452 		syslog(LOG_DEBUG, "%s: %s default route via %s", ifname, cmd,
    453 		    inet_ntoa(rt->gate));
    454 	else
    455 		syslog(LOG_DEBUG, "%s: %s route to %s/%d via %s", ifname, cmd,
    456 		    addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
    457 }
    458 
    459 /* If something other than dhcpcd removes a route,
    460  * we need to remove it from our internal table. */
    461 int
    462 route_deleted(const struct rt *rt)
    463 {
    464 	struct rt *f, *l;
    465 
    466 	f = find_route(routes, rt, &l, NULL);
    467 	if (f == NULL)
    468 		return 0;
    469 	desc_route("removing", f);
    470 	if (l)
    471 		l->next = f->next;
    472 	else
    473 		routes = f->next;
    474 	free(f);
    475 	return 1;
    476 }
    477 
    478 static int
    479 n_route(struct rt *rt)
    480 {
    481 	/* Don't set default routes if not asked to */
    482 	if (rt->dest.s_addr == 0 &&
    483 	    rt->net.s_addr == 0 &&
    484 	    !(rt->iface->state->options->options & DHCPCD_GATEWAY))
    485 		return -1;
    486 
    487 	desc_route("adding", rt);
    488 	if (!add_route(rt))
    489 		return 0;
    490 	if (errno == EEXIST) {
    491 		/* Pretend we added the subnet route */
    492 		if (rt->dest.s_addr ==
    493 		    (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
    494 		    rt->net.s_addr == rt->iface->net.s_addr &&
    495 		    rt->gate.s_addr == 0)
    496 			return 0;
    497 		else
    498 			return -1;
    499 	}
    500 	syslog(LOG_ERR, "%s: add_route: %m", rt->iface->name);
    501 	return -1;
    502 }
    503 
    504 static int
    505 c_route(struct rt *ort, struct rt *nrt)
    506 {
    507 	/* Don't set default routes if not asked to */
    508 	if (nrt->dest.s_addr == 0 &&
    509 	    nrt->net.s_addr == 0 &&
    510 	    !(nrt->iface->state->options->options & DHCPCD_GATEWAY))
    511 		return -1;
    512 
    513 	desc_route("changing", nrt);
    514 	/* We delete and add the route so that we can change metric.
    515 	 * This also has the nice side effect of flushing ARP entries so
    516 	 * we don't have to do that manually. */
    517 	del_route(ort);
    518 	if (!add_route(nrt))
    519 		return 0;
    520 	syslog(LOG_ERR, "%s: add_route: %m", nrt->iface->name);
    521 	return -1;
    522 }
    523 
    524 static int
    525 d_route(struct rt *rt)
    526 {
    527 	int retval;
    528 
    529 	desc_route("deleting", rt);
    530 	retval = del_route(rt);
    531 	if (retval != 0 && errno != ENOENT && errno != ESRCH)
    532 		syslog(LOG_ERR,"%s: del_route: %m", rt->iface->name);
    533 	return retval;
    534 }
    535 
    536 static struct rt *
    537 get_subnet_route(struct dhcp_message *dhcp)
    538 {
    539 	in_addr_t addr;
    540 	struct in_addr net;
    541 	struct rt *rt;
    542 
    543 	addr = dhcp->yiaddr;
    544 	if (addr == 0)
    545 		addr = dhcp->ciaddr;
    546 	/* Ensure we have all the needed values */
    547 	if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
    548 		net.s_addr = get_netmask(addr);
    549 	if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
    550 		return NULL;
    551 	rt = malloc(sizeof(*rt));
    552 	rt->dest.s_addr = addr & net.s_addr;
    553 	rt->net.s_addr = net.s_addr;
    554 	rt->gate.s_addr = 0;
    555 	return rt;
    556 }
    557 
    558 static struct rt *
    559 add_subnet_route(struct rt *rt, const struct interface *iface)
    560 {
    561 	struct rt *r;
    562 
    563 	if (iface->net.s_addr == INADDR_BROADCAST ||
    564 	    iface->net.s_addr == INADDR_ANY ||
    565 	    (iface->state->options->options &
    566 	     (DHCPCD_INFORM | DHCPCD_STATIC) &&
    567 	     iface->state->options->req_addr.s_addr == INADDR_ANY))
    568 		return rt;
    569 
    570 	r = xmalloc(sizeof(*r));
    571 	r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
    572 	r->net.s_addr = iface->net.s_addr;
    573 	r->gate.s_addr = 0;
    574 	r->next = rt;
    575 	return r;
    576 }
    577 
    578 static struct rt *
    579 get_routes(const struct interface *iface)
    580 {
    581 	struct rt *rt, *nrt = NULL, *r = NULL;
    582 
    583 	if (iface->state->options->routes != NULL) {
    584 		for (rt = iface->state->options->routes;
    585 		     rt != NULL;
    586 		     rt = rt->next)
    587 		{
    588 			if (rt->gate.s_addr == 0)
    589 				break;
    590 			if (r == NULL)
    591 				r = nrt = xmalloc(sizeof(*r));
    592 			else {
    593 				r->next = xmalloc(sizeof(*r));
    594 				r = r->next;
    595 			}
    596 			memcpy(r, rt, sizeof(*r));
    597 			r->next = NULL;
    598 		}
    599 		return nrt;
    600 	}
    601 
    602 	return get_option_routes(iface->state->new,
    603 	    iface->name, &iface->state->options->options);
    604 }
    605 
    606 /* Some DHCP servers add set host routes by setting the gateway
    607  * to the assinged IP address. This differs from our notion of a host route
    608  * where the gateway is the destination address, so we fix it. */
    609 static struct rt *
    610 massage_host_routes(struct rt *rt, const struct interface *iface)
    611 {
    612 	struct rt *r;
    613 
    614 	for (r = rt; r; r = r->next)
    615 		if (r->gate.s_addr == iface->addr.s_addr &&
    616 		    r->net.s_addr == INADDR_BROADCAST)
    617 			r->gate.s_addr = r->dest.s_addr;
    618 	return rt;
    619 }
    620 
    621 static struct rt *
    622 add_destination_route(struct rt *rt, const struct interface *iface)
    623 {
    624 	struct rt *r;
    625 
    626 	if (!(iface->flags & IFF_POINTOPOINT) ||
    627 	    !has_option_mask(iface->state->options->dstmask, DHO_ROUTER))
    628 		return rt;
    629 	r = xmalloc(sizeof(*r));
    630 	r->dest.s_addr = INADDR_ANY;
    631 	r->net.s_addr = INADDR_ANY;
    632 	r->gate.s_addr = iface->dst.s_addr;
    633 	r->next = rt;
    634 	return r;
    635 }
    636 
    637 /* We should check to ensure the routers are on the same subnet
    638  * OR supply a host route. If not, warn and add a host route. */
    639 static struct rt *
    640 add_router_host_route(struct rt *rt, const struct interface *ifp)
    641 {
    642 	struct rt *rtp, *rtl, *rtn;
    643 	const char *cp, *cp2, *cp3, *cplim;
    644 
    645 	for (rtp = rt, rtl = NULL; rtp; rtl = rtp, rtp = rtp->next) {
    646 		if (rtp->dest.s_addr != INADDR_ANY)
    647 			continue;
    648 		/* Scan for a route to match */
    649 		for (rtn = rt; rtn != rtp; rtn = rtn->next) {
    650 			/* match host */
    651 			if (rtn->dest.s_addr == rtp->gate.s_addr)
    652 				break;
    653 			/* match subnet */
    654 			cp = (const char *)&rtp->gate.s_addr;
    655 			cp2 = (const char *)&rtn->dest.s_addr;
    656 			cp3 = (const char *)&rtn->net.s_addr;
    657 			cplim = cp3 + sizeof(rtn->net.s_addr);
    658 			while (cp3 < cplim) {
    659 				if ((*cp++ ^ *cp2++) & *cp3++)
    660 					break;
    661 			}
    662 			if (cp3 == cplim)
    663 				break;
    664 		}
    665 		if (rtn != rtp)
    666 			continue;
    667 		if (ifp->flags & IFF_NOARP) {
    668 			syslog(LOG_WARNING,
    669 			    "%s: forcing router %s through interface",
    670 			    ifp->name, inet_ntoa(rtp->gate));
    671 			rtp->gate.s_addr = 0;
    672 			continue;
    673 		}
    674 		syslog(LOG_WARNING, "%s: router %s requires a host route",
    675 		    ifp->name, inet_ntoa(rtp->gate));
    676 		rtn = xmalloc(sizeof(*rtn));
    677 		rtn->dest.s_addr = rtp->gate.s_addr;
    678 		rtn->net.s_addr = INADDR_BROADCAST;
    679 		rtn->gate.s_addr = rtp->gate.s_addr;
    680 		rtn->next = rtp;
    681 		if (rtl == NULL)
    682 			rt = rtn;
    683 		else
    684 			rtl->next = rtn;
    685 	}
    686 	return rt;
    687 }
    688 
    689 void
    690 build_routes(void)
    691 {
    692 	struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
    693 	const struct interface *ifp;
    694 
    695 	if (avoid_routes) return;
    696 
    697 	for (ifp = ifaces; ifp; ifp = ifp->next) {
    698 		if (ifp->state->new == NULL)
    699 			continue;
    700 		dnr = get_routes(ifp);
    701 		dnr = massage_host_routes(dnr, ifp);
    702 		dnr = add_subnet_route(dnr, ifp);
    703 		dnr = add_router_host_route(dnr, ifp);
    704 		dnr = add_destination_route(dnr, ifp);
    705 		for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
    706 			rt->iface = ifp;
    707 			rt->metric = ifp->metric;
    708 			/* Is this route already in our table? */
    709 			if ((find_route(nrs, rt, NULL, NULL)) != NULL)
    710 				continue;
    711 			rt->src.s_addr = ifp->addr.s_addr;
    712 			/* Do we already manage it? */
    713 			if ((or = find_route(routes, rt, &rtl, NULL))) {
    714 				if (or->iface != ifp ||
    715 				    or->src.s_addr != ifp->addr.s_addr ||
    716 				    rt->gate.s_addr != or->gate.s_addr ||
    717 				    rt->metric != or->metric)
    718 				{
    719 					if (c_route(or, rt) != 0)
    720 						continue;
    721 				}
    722 				if (rtl != NULL)
    723 					rtl->next = or->next;
    724 				else
    725 					routes = or->next;
    726 				free(or);
    727 			} else {
    728 				if (n_route(rt) != 0)
    729 					continue;
    730 			}
    731 			if (dnr == rt)
    732 				dnr = rtn;
    733 			else if (lrt)
    734 				lrt->next = rtn;
    735 			rt->next = nrs;
    736 			nrs = rt;
    737 			rt = lrt; /* When we loop this makes lrt correct */
    738 		}
    739 		free_routes(dnr);
    740 	}
    741 
    742 	/* Remove old routes we used to manage */
    743 	for (rt = routes; rt; rt = rt->next) {
    744 		if (find_route(nrs, rt, NULL, NULL) == NULL)
    745 			d_route(rt);
    746 	}
    747 
    748 	free_routes(routes);
    749 	routes = nrs;
    750 }
    751 
    752 static int
    753 delete_address(struct interface *iface)
    754 {
    755 	int retval;
    756 	struct if_options *ifo;
    757 
    758 	ifo = iface->state->options;
    759 	if (ifo->options & DHCPCD_INFORM ||
    760 	    (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
    761 		return 0;
    762 	syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
    763 	    iface->name,
    764 	    inet_ntoa(iface->addr),
    765 	    inet_ntocidr(iface->net));
    766 	retval = del_address(iface, &iface->addr, &iface->net);
    767 	if (retval == -1 && errno != EADDRNOTAVAIL)
    768 		syslog(LOG_ERR, "del_address: %m");
    769 	iface->addr.s_addr = 0;
    770 	iface->net.s_addr = 0;
    771 	return retval;
    772 }
    773 
    774 int
    775 configure(struct interface *iface)
    776 {
    777 	struct dhcp_message *dhcp = iface->state->new;
    778 	struct dhcp_lease *lease = &iface->state->lease;
    779 	struct if_options *ifo = iface->state->options;
    780 	struct rt *rt;
    781 
    782 	/* As we are now adjusting an interface, we need to ensure
    783 	 * we have them in the right order for routing and configuration. */
    784 	sort_interfaces();
    785 
    786 	if (dhcp == NULL) {
    787 		if (!(ifo->options & DHCPCD_PERSISTENT)) {
    788 			build_routes();
    789 			if (iface->addr.s_addr != 0)
    790 				delete_address(iface);
    791 			run_script(iface);
    792 		}
    793 		return 0;
    794 	}
    795 
    796 	/* This also changes netmask */
    797 	if (!(ifo->options & DHCPCD_INFORM) ||
    798 	    !has_address(iface->name, &lease->addr, &lease->net))
    799 	{
    800 		syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
    801 		    iface->name, inet_ntoa(lease->addr),
    802 		    inet_ntocidr(lease->net));
    803 		if (add_address(iface,
    804 			&lease->addr, &lease->net, &lease->brd) == -1 &&
    805 		    errno != EEXIST)
    806 		{
    807 			syslog(LOG_ERR, "add_address: %m");
    808 			return -1;
    809 		}
    810 	}
    811 
    812 	/* Now delete the old address if different */
    813 	if (iface->addr.s_addr != lease->addr.s_addr &&
    814 	    iface->addr.s_addr != 0)
    815 		delete_address(iface);
    816 
    817 	iface->addr.s_addr = lease->addr.s_addr;
    818 	iface->net.s_addr = lease->net.s_addr;
    819 
    820 	if (!avoid_routes) {
    821 		/* We need to delete the subnet route to have our metric or
    822 		 * prefer the interface. */
    823 		rt = get_subnet_route(dhcp);
    824 		if (rt != NULL) {
    825 			rt->iface = iface;
    826 			rt->metric = 0;
    827 			if (!find_route(routes, rt, NULL, NULL))
    828 				del_route(rt);
    829 			free(rt);
    830 		}
    831 
    832 		build_routes();
    833 	}
    834 
    835 	if (!iface->state->lease.frominfo &&
    836 	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
    837 		if (write_lease(iface, dhcp) == -1)
    838 			syslog(LOG_ERR, "write_lease: %m");
    839 	run_script(iface);
    840 	return 0;
    841 }
    842