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 65static struct rt *routes; 66 67static int 68exec_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 97static char * 98make_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 110static void 111append_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 143static size_t 144arraytostr(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 165static ssize_t 166make_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 264dumplease: 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 302static int 303send_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 326int 327send_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 339int 340run_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 414static struct rt * 415find_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 437static void 438desc_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. */ 461int 462route_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 478static int 479n_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 504static int 505c_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 524static int 525d_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 536static struct rt * 537get_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 558static struct rt * 559add_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 578static struct rt * 579get_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. */ 609static struct rt * 610massage_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 621static struct rt * 622add_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. */ 639static struct rt * 640add_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 689void 690build_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 752static int 753delete_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 774int 775configure(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