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