• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2006-2010 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 "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
exec_script(char * const * argv,char * const * env)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 *
make_var(const char * prefix,const char * var)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
append_config(char *** env,ssize_t * len,const char * prefix,const char * const * config)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
arraytostr(const char * const * argv,char ** s)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
make_env(const struct interface * iface,char *** argv)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
send_interface(int fd,const struct interface * iface)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
run_script(const struct interface * iface)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 *
find_route(struct rt * rts,const struct rt * r,struct rt ** lrt,const struct rt * srt)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
desc_route(const char * cmd,const struct rt * rt,const char * ifname)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
route_deleted(const struct rt * rt)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
n_route(struct rt * rt,const struct interface * iface)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
c_route(struct rt * ort,struct rt * nrt,const struct interface * iface)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
d_route(struct rt * rt,const struct interface * iface,int metric)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 *
get_subnet_route(struct dhcp_message * dhcp)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 *
add_subnet_route(struct rt * rt,const struct interface * iface)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 *
get_routes(const struct interface * iface)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 *
massage_host_routes(struct rt * rt,const struct interface * iface)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 *
add_destination_route(struct rt * rt,const struct interface * iface)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 *
add_router_host_route(struct rt * rt,const struct interface * ifp)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
build_routes(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
delete_address(struct interface * iface)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
configure(struct interface * iface)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