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