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
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
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,const char * reason,char *** argv)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
send_interface1(int fd,const struct interface * iface,const char * reason)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
send_interface(int fd,const struct interface * iface)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
run_script_reason(const struct interface * iface,const char * reason)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 *
find_route(struct rt * rts,const struct rt * r,struct rt ** lrt,const struct rt * srt)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
desc_route(const char * cmd,const struct rt * rt)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
route_deleted(const struct rt * rt)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
n_route(struct rt * rt)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
c_route(struct rt * ort,struct rt * nrt)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
d_route(struct rt * rt)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 *
get_subnet_route(struct dhcp_message * dhcp)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 *
add_subnet_route(struct rt * rt,const struct interface * iface)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 *
get_routes(const struct interface * iface)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 *
massage_host_routes(struct rt * rt,const struct interface * iface)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 *
add_destination_route(struct rt * rt,const struct interface * iface)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 *
add_router_host_route(struct rt * rt,const struct interface * ifp)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
build_routes(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
delete_address(struct interface * iface)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
configure(struct interface * iface)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