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