1/* $OpenBSD: kroute.c,v 1.197 2021/03/28 17:25:21 krw Exp $ */ 2 3/* 4 * Copyright 2012 Kenneth R Westerback <krw@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/ioctl.h> 20#include <sys/queue.h> 21#include <sys/socket.h> 22#include <sys/stat.h> 23#include <sys/sysctl.h> 24 25#include <arpa/inet.h> 26 27#include <net/if.h> 28#include <net/if_types.h> 29#include <net/route.h> 30 31#include <netinet/in.h> 32#include <netinet/if_ether.h> 33 34#include <errno.h> 35#include <fcntl.h> 36#include <ifaddrs.h> 37#include <imsg.h> 38#include <limits.h> 39#include <poll.h> 40#include <resolv.h> 41#include <signal.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <unistd.h> 46 47#include "dhcp.h" 48#include "dhcpd.h" 49#include "log.h" 50#include "privsep.h" 51 52#define ROUNDUP(a) \ 53 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 54 55#define CIDR_MAX_BITS 32 56 57int delete_addresses(char *, int, struct in_addr, struct in_addr); 58void set_address(char *, int, struct in_addr, struct in_addr); 59void delete_address(char *, int, struct in_addr); 60 61char *get_routes(int, size_t *); 62void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 63unsigned int route_pos(struct rt_msghdr *, uint8_t *, unsigned int, 64 struct in_addr); 65void flush_routes(int, int, int, uint8_t *, unsigned int, 66 struct in_addr); 67void discard_route(uint8_t *, unsigned int); 68void add_route(char *, int, int, struct in_addr, struct in_addr, 69 struct in_addr, struct in_addr, int); 70void set_routes(char *, int, int, int, struct in_addr, 71 struct in_addr, uint8_t *, unsigned int); 72 73int default_route_index(int, int); 74char *resolv_conf_tail(void); 75char *set_resolv_conf(char *, char *, struct unwind_info *); 76 77void set_mtu(char *, int, uint16_t); 78 79/* 80 * delete_addresses() removes all inet addresses on the named interface, except 81 * for newaddr/newnetmask. 82 * 83 * If newaddr/newmask is already present, return 1, else 0. 84 */ 85int 86delete_addresses(char *name, int ioctlfd, struct in_addr newaddr, 87 struct in_addr newnetmask) 88{ 89 struct in_addr addr, netmask; 90 struct ifaddrs *ifap, *ifa; 91 int found; 92 93 if (getifaddrs(&ifap) == -1) 94 fatal("getifaddrs"); 95 96 found = 0; 97 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 98 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0 || 99 (ifa->ifa_flags & IFF_POINTOPOINT) != 0 || 100 ((ifa->ifa_flags & IFF_UP) == 0) || 101 (ifa->ifa_addr->sa_family != AF_INET) || 102 (strcmp(name, ifa->ifa_name) != 0)) 103 continue; 104 105 memcpy(&addr, 106 &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, 107 sizeof(addr)); 108 memcpy(&netmask, 109 &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr, 110 sizeof(netmask)); 111 112 if (addr.s_addr == newaddr.s_addr && 113 netmask.s_addr == newnetmask.s_addr) { 114 found = 1; 115 } else { 116 delete_address(name, ioctlfd, addr); 117 } 118 } 119 120 freeifaddrs(ifap); 121 return found; 122} 123 124/* 125 * set_address() is the equivalent of 126 * 127 * ifconfig <if> inet <addr> netmask <mask> broadcast <addr> 128 */ 129void 130set_address(char *name, int ioctlfd, struct in_addr addr, 131 struct in_addr netmask) 132{ 133 struct ifaliasreq ifaliasreq; 134 struct sockaddr_in *in; 135 136 if (delete_addresses(name, ioctlfd, addr, netmask) == 1) 137 return; 138 139 memset(&ifaliasreq, 0, sizeof(ifaliasreq)); 140 strncpy(ifaliasreq.ifra_name, name, sizeof(ifaliasreq.ifra_name)); 141 142 /* The actual address in ifra_addr. */ 143 in = (struct sockaddr_in *)&ifaliasreq.ifra_addr; 144 in->sin_family = AF_INET; 145 in->sin_len = sizeof(ifaliasreq.ifra_addr); 146 in->sin_addr.s_addr = addr.s_addr; 147 148 /* And the netmask in ifra_mask. */ 149 in = (struct sockaddr_in *)&ifaliasreq.ifra_mask; 150 in->sin_family = AF_INET; 151 in->sin_len = sizeof(ifaliasreq.ifra_mask); 152 in->sin_addr.s_addr = netmask.s_addr; 153 154 /* No need to set broadcast address. Kernel can figure it out. */ 155 156 if (ioctl(ioctlfd, SIOCAIFADDR, &ifaliasreq) == -1) 157 log_warn("%s: SIOCAIFADDR %s", log_procname, 158 inet_ntoa(addr)); 159} 160 161void 162delete_address(char *name, int ioctlfd, struct in_addr addr) 163{ 164 struct ifaliasreq ifaliasreq; 165 struct sockaddr_in *in; 166 167 /* 168 * Delete specified address on specified interface. 169 * 170 * Deleting the address also clears out arp entries. 171 */ 172 173 memset(&ifaliasreq, 0, sizeof(ifaliasreq)); 174 strncpy(ifaliasreq.ifra_name, name, sizeof(ifaliasreq.ifra_name)); 175 176 in = (struct sockaddr_in *)&ifaliasreq.ifra_addr; 177 in->sin_family = AF_INET; 178 in->sin_len = sizeof(ifaliasreq.ifra_addr); 179 in->sin_addr.s_addr = addr.s_addr; 180 181 /* SIOCDIFADDR will result in a RTM_DELADDR message we must catch! */ 182 if (ioctl(ioctlfd, SIOCDIFADDR, &ifaliasreq) == -1) { 183 if (errno != EADDRNOTAVAIL) 184 log_warn("%s: SIOCDIFADDR %s", log_procname, 185 inet_ntoa(addr)); 186 } 187} 188 189/* 190 * get_routes() returns all relevant routes currently configured, and the 191 * length of the buffer being returned. 192 */ 193char * 194get_routes(int rdomain, size_t *len) 195{ 196 int mib[7]; 197 char *buf, *bufp, *errmsg = NULL; 198 size_t needed; 199 200 mib[0] = CTL_NET; 201 mib[1] = PF_ROUTE; /* PF_ROUTE (not AF_ROUTE) for sysctl(2)! */ 202 mib[2] = 0; 203 mib[3] = AF_INET; 204 mib[4] = NET_RT_FLAGS; 205 mib[5] = RTF_STATIC; 206 mib[6] = rdomain; 207 208 buf = NULL; 209 errmsg = NULL; 210 for (;;) { 211 if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) { 212 errmsg = "sysctl size of routes:"; 213 break; 214 } 215 if (needed == 0) { 216 free(buf); 217 return NULL; 218 } 219 if ((bufp = realloc(buf, needed)) == NULL) { 220 errmsg = "routes buf realloc:"; 221 break; 222 } 223 buf = bufp; 224 if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) { 225 if (errno == ENOMEM) 226 continue; 227 errmsg = "sysctl retrieval of routes:"; 228 break; 229 } 230 break; 231 } 232 233 if (errmsg != NULL) { 234 log_warn("%s: get_routes - %s (msize=%zu)", log_procname, 235 errmsg, needed); 236 free(buf); 237 buf = NULL; 238 } 239 240 *len = needed; 241 return buf; 242} 243 244/* 245 * get_rtaddrs() populates rti_info with pointers to the 246 * sockaddr's contained in a rtm message. 247 */ 248void 249get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 250{ 251 int i; 252 253 for (i = 0; i < RTAX_MAX; i++) { 254 if (addrs & (1 << i)) { 255 rti_info[i] = sa; 256 sa = (struct sockaddr *)((char *)(sa) + 257 ROUNDUP(sa->sa_len)); 258 } else 259 rti_info[i] = NULL; 260 } 261} 262/* 263 * route_pos() finds the position of the *rtm route within 264 * routes. 265 * 266 * If the *rtm route is not in routes, return routes_len. 267 */ 268unsigned int 269route_pos(struct rt_msghdr *rtm, uint8_t *routes, unsigned int routes_len, 270 struct in_addr address) 271{ 272 struct sockaddr *rti_info[RTAX_MAX]; 273 struct sockaddr *dst, *netmask, *gateway; 274 in_addr_t dstaddr, netmaskaddr, gatewayaddr; 275 in_addr_t routesdstaddr, routesnetmaskaddr; 276 in_addr_t routesgatewayaddr; 277 unsigned int i, len; 278 279 get_rtaddrs(rtm->rtm_addrs, 280 (struct sockaddr *)((char *)(rtm) + rtm->rtm_hdrlen), 281 rti_info); 282 283 dst = rti_info[RTAX_DST]; 284 netmask = rti_info[RTAX_NETMASK]; 285 gateway = rti_info[RTAX_GATEWAY]; 286 287 if (dst == NULL || netmask == NULL || gateway == NULL) 288 return routes_len; 289 290 if (dst->sa_family != AF_INET || netmask->sa_family != AF_INET || 291 gateway->sa_family != AF_INET) 292 return routes_len; 293 294 dstaddr = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 295 netmaskaddr = ((struct sockaddr_in *)netmask)->sin_addr.s_addr; 296 gatewayaddr = ((struct sockaddr_in *)gateway)->sin_addr.s_addr; 297 298 dstaddr &= netmaskaddr; 299 i = 0; 300 while (i < routes_len) { 301 len = extract_route(&routes[i], routes_len - i, &routesdstaddr, 302 &routesnetmaskaddr, &routesgatewayaddr); 303 if (len == 0) 304 break; 305 306 /* Direct route in routes: 307 * 308 * dst=1.2.3.4 netmask=255.255.255.255 gateway=0.0.0.0 309 * 310 * direct route in rtm: 311 * 312 * dst=1.2.3.4 netmask=255.255.255.255 gateway = address 313 * 314 * So replace 0.0.0.0 with address for comparison. 315 */ 316 if (routesgatewayaddr == INADDR_ANY) 317 routesgatewayaddr = address.s_addr; 318 routesdstaddr &= routesnetmaskaddr; 319 320 if (dstaddr == routesdstaddr && 321 netmaskaddr == routesnetmaskaddr && 322 gatewayaddr == routesgatewayaddr) 323 return i; 324 325 i += len; 326 } 327 328 return routes_len; 329} 330 331void 332flush_routes(int index, int routefd, int rdomain, uint8_t *routes, 333 unsigned int routes_len, struct in_addr address) 334{ 335 static int seqno; 336 char *lim, *buf, *next; 337 struct rt_msghdr *rtm; 338 size_t len; 339 ssize_t rlen; 340 unsigned int pos; 341 342 buf = get_routes(rdomain, &len); 343 if (buf == NULL) 344 return; 345 346 lim = buf + len; 347 for (next = buf; next < lim; next += rtm->rtm_msglen) { 348 rtm = (struct rt_msghdr *)next; 349 if (rtm->rtm_version != RTM_VERSION) 350 continue; 351 if (rtm->rtm_index != index) 352 continue; 353 if (rtm->rtm_tableid != rdomain) 354 continue; 355 if ((rtm->rtm_flags & RTF_STATIC) == 0) 356 continue; 357 if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0) 358 continue; 359 360 pos = route_pos(rtm, routes, routes_len, address); 361 if (pos < routes_len) { 362 discard_route(routes + pos, routes_len - pos); 363 continue; 364 } 365 366 rtm->rtm_type = RTM_DELETE; 367 rtm->rtm_seq = seqno++; 368 369 rlen = write(routefd, (char *)rtm, rtm->rtm_msglen); 370 if (rlen == -1) { 371 if (errno != ESRCH) 372 log_warn("%s: write(RTM_DELETE)", log_procname); 373 } else if (rlen < (int)rtm->rtm_msglen) 374 log_warnx("%s: write(RTM_DELETE): %zd of %u bytes", 375 log_procname, rlen, rtm->rtm_msglen); 376 } 377 378 free(buf); 379} 380 381void 382discard_route(uint8_t *routes, unsigned int routes_len) 383{ 384 unsigned int len; 385 386 len = 1 + sizeof(struct in_addr) + (routes[0] + 7) / 8; 387 memmove(routes, routes + len, routes_len - len); 388 routes[routes_len - len] = CIDR_MAX_BITS + 1; 389} 390 391/* 392 * add_route() adds a single route to the routing table. 393 */ 394void 395add_route(char *name, int rdomain, int routefd, struct in_addr dest, 396 struct in_addr netmask, struct in_addr gateway, struct in_addr address, 397 int flags) 398{ 399 char destbuf[INET_ADDRSTRLEN]; 400 char maskbuf[INET_ADDRSTRLEN]; 401 struct iovec iov[5]; 402 struct sockaddr_in sockaddr_in[4]; 403 struct rt_msghdr rtm; 404 int i, iovcnt = 0; 405 406 memset(&rtm, 0, sizeof(rtm)); 407 rtm.rtm_index = if_nametoindex(name); 408 if (rtm.rtm_index == 0) 409 return; 410 411 rtm.rtm_version = RTM_VERSION; 412 rtm.rtm_type = RTM_ADD; 413 rtm.rtm_tableid = rdomain; 414 rtm.rtm_priority = RTP_NONE; 415 rtm.rtm_flags = flags; 416 417 iov[0].iov_base = &rtm; 418 iov[0].iov_len = sizeof(rtm); 419 420 memset(sockaddr_in, 0, sizeof(sockaddr_in)); 421 for (i = 0; i < 4; i++) { 422 sockaddr_in[i].sin_len = sizeof(sockaddr_in[i]); 423 sockaddr_in[i].sin_family = AF_INET; 424 iov[i+1].iov_base = &sockaddr_in[i]; 425 iov[i+1].iov_len = sizeof(sockaddr_in[i]); 426 } 427 428 /* Order of sockaddr_in's is mandatory! */ 429 sockaddr_in[0].sin_addr = dest; 430 sockaddr_in[1].sin_addr = gateway; 431 sockaddr_in[2].sin_addr = netmask; 432 sockaddr_in[3].sin_addr = address; 433 if (address.s_addr == INADDR_ANY) { 434 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 435 iovcnt = 4; 436 } else { 437 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFA; 438 iovcnt = 5; 439 } 440 441 for (i = 0; i < iovcnt; i++) 442 rtm.rtm_msglen += iov[i].iov_len; 443 444 if (writev(routefd, iov, iovcnt) == -1) { 445 if (errno != EEXIST || log_getverbose() != 0) { 446 strlcpy(destbuf, inet_ntoa(dest), sizeof(destbuf)); 447 strlcpy(maskbuf, inet_ntoa(netmask),sizeof(maskbuf)); 448 log_warn("%s: add route %s/%s via %s", log_procname, 449 destbuf, maskbuf, inet_ntoa(gateway)); 450 } 451 } 452} 453 454/* 455 * set_routes() adds the routes contained in 'routes' to the routing table. 456 */ 457void 458set_routes(char *name, int index, int rdomain, int routefd, struct in_addr addr, 459 struct in_addr addrmask, uint8_t *routes, unsigned int routes_len) 460{ 461 const struct in_addr any = { INADDR_ANY }; 462 const struct in_addr broadcast = { INADDR_BROADCAST }; 463 struct in_addr dest, gateway, netmask; 464 in_addr_t addrnet, gatewaynet; 465 unsigned int i, len; 466 467 flush_routes(index, routefd, rdomain, routes, routes_len, addr); 468 469 addrnet = addr.s_addr & addrmask.s_addr; 470 471 /* Add classless static routes. */ 472 i = 0; 473 while (i < routes_len) { 474 len = extract_route(&routes[i], routes_len - i, 475 &dest.s_addr, &netmask.s_addr, &gateway.s_addr); 476 if (len == 0) 477 return; 478 i += len; 479 480 if (gateway.s_addr == INADDR_ANY) { 481 /* 482 * DIRECT ROUTE 483 * 484 * route add -net $dest -netmask $netmask -cloning 485 * -iface $addr 486 */ 487 add_route(name, rdomain, routefd, dest, netmask, 488 addr, any, RTF_STATIC | RTF_CLONING); 489 } else if (netmask.s_addr == INADDR_ANY) { 490 /* 491 * DEFAULT ROUTE 492 */ 493 gatewaynet = gateway.s_addr & addrmask.s_addr; 494 if (gatewaynet != addrnet) { 495 /* 496 * DIRECT ROUTE TO DEFAULT GATEWAY 497 * 498 * route add -net $gateway 499 * -netmask 255.255.255.255 500 * -cloning -iface $addr 501 * 502 * If the default route gateway is not reachable 503 * via the IP assignment then add a cloning 504 * direct route for the gateway. Deals with 505 * weird configs seen in the wild. 506 * 507 * e.g. add the route if we were given a /32 IP 508 * assignment. a.k.a. "make Google Cloud DHCP 509 * work". 510 * 511 */ 512 add_route(name, rdomain, routefd, gateway, 513 broadcast, addr, any, 514 RTF_STATIC | RTF_CLONING); 515 } 516 517 if (memcmp(&gateway, &addr, sizeof(addr)) == 0) { 518 /* 519 * DEFAULT ROUTE IS A DIRECT ROUTE 520 * 521 * route add default -iface $addr 522 */ 523 add_route(name, rdomain, routefd, any, any, 524 gateway, any, RTF_STATIC); 525 } else { 526 /* 527 * DEFAULT ROUTE IS VIA GATEWAY 528 * 529 * route add default $gateway -ifa $addr 530 * 531 */ 532 add_route(name, rdomain, routefd, any, any, 533 gateway, addr, RTF_STATIC | RTF_GATEWAY); 534 } 535 } else { 536 /* 537 * NON-DIRECT, NON-DEFAULT ROUTE 538 * 539 * route add -net $dest -netmask $netmask $gateway 540 */ 541 add_route(name, rdomain, routefd, dest, netmask, 542 gateway, any, RTF_STATIC | RTF_GATEWAY); 543 } 544 } 545} 546 547/* 548 * default_route_index() returns the interface index of the current 549 * default route (a.k.a. 0.0.0.0/0). 550 */ 551int 552default_route_index(int rdomain, int routefd) 553{ 554 struct pollfd fds[1]; 555 struct timespec now, stop, timeout; 556 int nfds; 557 struct iovec iov[3]; 558 struct sockaddr_in sin; 559 struct { 560 struct rt_msghdr m_rtm; 561 char m_space[512]; 562 } m_rtmsg; 563 pid_t pid; 564 ssize_t len; 565 int seq; 566 567 memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 568 m_rtmsg.m_rtm.rtm_version = RTM_VERSION; 569 m_rtmsg.m_rtm.rtm_type = RTM_GET; 570 m_rtmsg.m_rtm.rtm_tableid = rdomain; 571 m_rtmsg.m_rtm.rtm_seq = seq = arc4random(); 572 m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 573 m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) + 574 2 * sizeof(struct sockaddr_in); 575 576 memset(&sin, 0, sizeof(sin)); 577 sin.sin_len = sizeof(sin); 578 sin.sin_family = AF_INET; 579 580 iov[0].iov_base = &m_rtmsg.m_rtm; 581 iov[0].iov_len = sizeof(m_rtmsg.m_rtm); 582 iov[1].iov_base = &sin; 583 iov[1].iov_len = sizeof(sin); 584 iov[2].iov_base = &sin; 585 iov[2].iov_len = sizeof(sin); 586 587 pid = getpid(); 588 clock_gettime(CLOCK_MONOTONIC, &now); 589 timespecclear(&timeout); 590 timeout.tv_sec = 3; 591 timespecadd(&now, &timeout, &stop); 592 593 if (writev(routefd, iov, 3) == -1) { 594 if (errno == ESRCH) 595 log_debug("%s: writev(RTM_GET) - no default route", 596 log_procname); 597 else 598 log_warn("%s: writev(RTM_GET)", log_procname); 599 return 0; 600 } 601 602 for (;;) { 603 clock_gettime(CLOCK_MONOTONIC, &now); 604 if (timespeccmp(&stop, &now, <=)) 605 break; 606 timespecsub(&stop, &now, &timeout); 607 608 fds[0].fd = routefd; 609 fds[0].events = POLLIN; 610 nfds = ppoll(fds, 1, &timeout, NULL); 611 if (nfds == -1) { 612 if (errno == EINTR) 613 continue; 614 log_warn("%s: ppoll(routefd)", log_procname); 615 break; 616 } 617 if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) { 618 log_warnx("%s: routefd: ERR|HUP|NVAL", log_procname); 619 break; 620 } 621 if (nfds == 0 || (fds[0].revents & POLLIN) == 0) 622 continue; 623 624 len = read(routefd, &m_rtmsg, sizeof(m_rtmsg)); 625 if (len == -1) { 626 log_warn("%s: read(RTM_GET)", log_procname); 627 break; 628 } else if (len == 0) { 629 log_warnx("%s: read(RTM_GET): 0 bytes", log_procname); 630 break; 631 } 632 633 if (m_rtmsg.m_rtm.rtm_version == RTM_VERSION && 634 m_rtmsg.m_rtm.rtm_type == RTM_GET && 635 m_rtmsg.m_rtm.rtm_pid == pid && 636 m_rtmsg.m_rtm.rtm_seq == seq && 637 (m_rtmsg.m_rtm.rtm_flags & RTF_UP) == RTF_UP) { 638 if (m_rtmsg.m_rtm.rtm_errno != 0) { 639 log_warnx("%s: read(RTM_GET): %s", log_procname, 640 strerror(m_rtmsg.m_rtm.rtm_errno)); 641 break; 642 } 643 return m_rtmsg.m_rtm.rtm_index; 644 } 645 } 646 647 return 0; 648} 649 650/* 651 * resolv_conf_tail() returns the contents of /etc/resolv.conf.tail, if 652 * any. NULL is returned if there is no such file, the file is emtpy 653 * or any errors are encounted in reading the file. 654 */ 655char * 656resolv_conf_tail(void) 657{ 658 struct stat sb; 659 const char *tail_path = "/etc/resolv.conf.tail"; 660 char *tailcontents = NULL; 661 ssize_t tailn; 662 int tailfd; 663 664 tailfd = open(tail_path, O_RDONLY); 665 if (tailfd == -1) { 666 if (errno != ENOENT) 667 log_warn("%s: open(%s)", log_procname, tail_path); 668 } else if (fstat(tailfd, &sb) == -1) { 669 log_warn("%s: fstat(%s)", log_procname, tail_path); 670 } else if (sb.st_size > 0 && sb.st_size < LLONG_MAX) { 671 tailcontents = calloc(1, sb.st_size + 1); 672 if (tailcontents == NULL) 673 fatal("%s contents", tail_path); 674 tailn = read(tailfd, tailcontents, sb.st_size); 675 if (tailn == -1) 676 log_warn("%s: read(%s)", log_procname, 677 tail_path); 678 else if (tailn == 0) 679 log_warnx("%s: got no data from %s", 680 log_procname,tail_path); 681 else if (tailn != sb.st_size) 682 log_warnx("%s: short read of %s", 683 log_procname, tail_path); 684 else { 685 close(tailfd); 686 return tailcontents; 687 } 688 689 close(tailfd); 690 free(tailcontents); 691 } 692 693 return NULL; 694} 695 696/* 697 * set_resolv_conf() creates a string that are the resolv.conf contents 698 * that should be used when IMSG_WRITE_RESOLV_CONF messages are received. 699 */ 700char * 701set_resolv_conf(char *name, char *search, struct unwind_info *ns_info) 702{ 703 char *ns, *p, *tail; 704 struct in_addr addr; 705 unsigned int i; 706 int rslt; 707 708 ns = NULL; 709 for (i = 0; i < ns_info->count; i++) { 710 addr.s_addr = ns_info->ns[i]; 711 rslt = asprintf(&p, "%snameserver %s\n", 712 (ns == NULL) ? "" : ns, inet_ntoa(addr)); 713 if (rslt == -1) 714 fatal("nameserver"); 715 free(ns); 716 ns = p; 717 } 718 719 if (search == NULL && ns == NULL) 720 return NULL; 721 722 tail = resolv_conf_tail(); 723 724 rslt = asprintf(&p, "# Generated by %s dhclient\n%s%s%s", name, 725 (search == NULL) ? "" : search, 726 (ns == NULL) ? "" : ns, 727 (tail == NULL) ? "" : tail); 728 if (rslt == -1) 729 fatal("resolv.conf"); 730 731 free(tail); 732 free(ns); 733 734 return p; 735} 736 737/* 738 * set_mtu() is the equivalent of 739 * 740 * ifconfig <if> mtu <mtu> 741 */ 742void 743set_mtu(char *name, int ioctlfd, uint16_t mtu) 744{ 745 struct ifreq ifr; 746 747 memset(&ifr, 0, sizeof(ifr)); 748 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 749 750 if (ioctl(ioctlfd, SIOCGIFMTU, &ifr) == -1) { 751 log_warn("%s: SIOCGIFMTU", log_procname); 752 return; 753 } 754 if (ifr.ifr_mtu == mtu) 755 return; /* Avoid unnecessary RTM_IFINFO! */ 756 757 ifr.ifr_mtu = mtu; 758 if (ioctl(ioctlfd, SIOCSIFMTU, &ifr) == -1) 759 log_warn("%s: SIOCSIFMTU %u", log_procname, mtu); 760} 761 762/* 763 * extract_route() decodes the route pointed to by routes into its 764 * {destination, netmask, gateway} and returns the number of bytes consumed 765 * from routes. 766 */ 767unsigned int 768extract_route(uint8_t *routes, unsigned int routes_len, in_addr_t *dest, 769 in_addr_t *netmask, in_addr_t *gateway) 770{ 771 unsigned int bits, bytes, len; 772 773 if (routes[0] > CIDR_MAX_BITS) 774 return 0; 775 776 bits = routes[0]; 777 bytes = (bits + 7) / 8; 778 len = 1 + bytes + sizeof(*gateway); 779 if (len > routes_len) 780 return 0; 781 782 if (dest != NULL) 783 memcpy(dest, &routes[1], bytes); 784 785 if (netmask != NULL) { 786 if (bits == 0) 787 *netmask = INADDR_ANY; 788 else 789 *netmask = htonl(0xffffffff << (CIDR_MAX_BITS - bits)); 790 if (dest != NULL) 791 *dest &= *netmask; 792 } 793 794 if (gateway != NULL) 795 memcpy(gateway, &routes[1 + bytes], sizeof(*gateway)); 796 797 return len; 798} 799 800/* 801 * [priv_]write_resolv_conf write out a new resolv.conf. 802 */ 803void 804write_resolv_conf(void) 805{ 806 int rslt; 807 808 rslt = imsg_compose(unpriv_ibuf, IMSG_WRITE_RESOLV_CONF, 809 0, 0, -1, NULL, 0); 810 if (rslt == -1) 811 log_warn("%s: imsg_compose(IMSG_WRITE_RESOLV_CONF)", 812 log_procname); 813} 814 815void 816priv_write_resolv_conf(int index, int routefd, int rdomain, char *contents, 817 int *lastidx) 818{ 819 char ifname[IF_NAMESIZE]; 820 const char *path = "/etc/resolv.conf"; 821 ssize_t n; 822 size_t sz; 823 int fd, retries, newidx; 824 825 if (contents == NULL) 826 return; 827 828 retries = 0; 829 do { 830 newidx = default_route_index(rdomain, routefd); 831 retries++; 832 } while (newidx == 0 && retries < 3); 833 834 if (newidx == 0) { 835 log_debug("%s: %s not updated, no default route is UP", 836 log_procname, path); 837 return; 838 } else if (newidx != index) { 839 *lastidx = newidx; 840 if (if_indextoname(newidx, ifname) == NULL) { 841 memset(ifname, 0, sizeof(ifname)); 842 strlcat(ifname, "<unknown>", sizeof(ifname)); 843 } 844 log_debug("%s: %s not updated, default route on %s", 845 log_procname, path, ifname); 846 return; 847 } else if (newidx == *lastidx) { 848 log_debug("%s: %s not updated, same as last write", 849 log_procname, path); 850 return; 851 } 852 853 *lastidx = newidx; 854 log_debug("%s: %s updated", log_procname, path); 855 856 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 857 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 858 859 if (fd == -1) { 860 log_warn("%s: open(%s)", log_procname, path); 861 return; 862 } 863 864 sz = strlen(contents); 865 n = write(fd, contents, sz); 866 if (n == -1) 867 log_warn("%s: write(%s)", log_procname, path); 868 else if ((size_t)n < sz) 869 log_warnx("%s: write(%s): %zd of %zu bytes", log_procname, 870 path, n, sz); 871 872 close(fd); 873} 874 875/* 876 * [priv_]propose implements a proposal. 877 */ 878void 879propose(struct proposal *proposal) 880{ 881 struct option_data opt; 882 int rslt; 883 884 log_debug("%s: proposing address %s netmask 0x%08x", log_procname, 885 inet_ntoa(proposal->address), ntohl(proposal->netmask.s_addr)); 886 887 opt.data = (u_int8_t *)proposal + sizeof(struct proposal); 888 opt.len = proposal->routes_len; 889 if (opt.len > 0) 890 log_debug("%s: proposing static route(s) %s", log_procname, 891 pretty_print_option(DHO_CLASSLESS_STATIC_ROUTES, &opt, 0)); 892 893 opt.data += opt.len; 894 opt.len = proposal->domains_len; 895 if (opt.len > 0) 896 log_debug("%s: proposing search domain(s) %s", log_procname, 897 pretty_print_option(DHO_DOMAIN_SEARCH, &opt, 0)); 898 899 opt.data += opt.len; 900 opt.len = proposal->ns_len; 901 if (opt.len > 0) 902 log_debug("%s: proposing DNS server(s) %s", log_procname, 903 pretty_print_option(DHO_DOMAIN_NAME_SERVERS, &opt, 0)); 904 905 if (proposal->mtu != 0) 906 log_debug("%s: proposing mtu %u", log_procname, proposal->mtu); 907 908 rslt = imsg_compose(unpriv_ibuf, IMSG_PROPOSE, 0, 0, -1, proposal, 909 sizeof(*proposal) + proposal->routes_len + 910 proposal->domains_len + proposal->ns_len); 911 if (rslt == -1) 912 log_warn("%s: imsg_compose(IMSG_PROPOSE)", log_procname); 913} 914 915void 916priv_propose(char *name, int ioctlfd, struct proposal *proposal, 917 size_t sz, char **resolv_conf, int routefd, int rdomain, int index, 918 int *lastidx) 919{ 920 struct unwind_info unwind_info; 921 uint8_t *dns, *domains, *routes; 922 char *search = NULL; 923 int rslt; 924 925 if (sz != proposal->routes_len + proposal->domains_len + 926 proposal->ns_len) { 927 log_warnx("%s: bad IMSG_PROPOSE data", log_procname); 928 return; 929 } 930 931 routes = (uint8_t *)proposal + sizeof(struct proposal); 932 domains = routes + proposal->routes_len; 933 dns = domains + proposal->domains_len; 934 935 memset(&unwind_info, 0, sizeof(unwind_info)); 936 if (proposal->ns_len >= sizeof(in_addr_t)) { 937 if (proposal->ns_len > sizeof(unwind_info.ns)) { 938 memcpy(unwind_info.ns, dns, sizeof(unwind_info.ns)); 939 unwind_info.count = sizeof(unwind_info.ns) / 940 sizeof(in_addr_t); 941 } else { 942 memcpy(unwind_info.ns, dns, proposal->ns_len); 943 unwind_info.count = proposal->ns_len / 944 sizeof(in_addr_t); 945 } 946 } 947 948 if (proposal->domains_len > 0) { 949 rslt = asprintf(&search, "search %.*s\n", 950 proposal->domains_len, domains); 951 if (rslt == -1) 952 search = NULL; 953 } 954 955 free(*resolv_conf); 956 *resolv_conf = set_resolv_conf(name, search, &unwind_info); 957 free(search); 958 959 if (proposal->mtu != 0) { 960 if (proposal->mtu < 68) 961 log_warnx("%s: mtu size %d < 68: ignored", log_procname, 962 proposal->mtu); 963 else 964 set_mtu(name, ioctlfd, proposal->mtu); 965 } 966 967 set_address(name, ioctlfd, proposal->address, proposal->netmask); 968 969 set_routes(name, index, rdomain, routefd, proposal->address, 970 proposal->netmask, routes, proposal->routes_len); 971 972 *lastidx = 0; 973 priv_write_resolv_conf(index, routefd, rdomain, *resolv_conf, lastidx); 974} 975 976/* 977 * [priv_]revoke_proposal de-configures a proposal. 978 */ 979void 980revoke_proposal(struct proposal *proposal) 981{ 982 int rslt; 983 984 if (proposal == NULL) 985 return; 986 987 rslt = imsg_compose(unpriv_ibuf, IMSG_REVOKE, 0, 0, -1, proposal, 988 sizeof(*proposal)); 989 if (rslt == -1) 990 log_warn("%s: imsg_compose(IMSG_REVOKE)", log_procname); 991} 992 993void 994priv_revoke_proposal(char *name, int ioctlfd, struct proposal *proposal, 995 char **resolv_conf) 996{ 997 free(*resolv_conf); 998 *resolv_conf = NULL; 999 1000 delete_address(name, ioctlfd, proposal->address); 1001} 1002 1003/* 1004 * [priv_]tell_unwind sends out inforation unwind may be intereted in. 1005 */ 1006void 1007tell_unwind(struct unwind_info *unwind_info, int ifi_flags) 1008{ 1009 struct unwind_info noinfo; 1010 int rslt; 1011 1012 if ((ifi_flags & IFI_IN_CHARGE) == 0) 1013 return; 1014 1015 if (unwind_info != NULL) 1016 rslt = imsg_compose(unpriv_ibuf, IMSG_TELL_UNWIND, 0, 0, -1, 1017 unwind_info, sizeof(*unwind_info)); 1018 else { 1019 memset(&noinfo, 0, sizeof(noinfo)); 1020 rslt = imsg_compose(unpriv_ibuf, IMSG_TELL_UNWIND, 0, 0, -1, 1021 &noinfo, sizeof(noinfo)); 1022 } 1023 1024 if (rslt == -1) 1025 log_warn("%s: imsg_compose(IMSG_TELL_UNWIND)", log_procname); 1026} 1027 1028void 1029priv_tell_unwind(int index, int routefd, int rdomain, 1030 struct unwind_info *unwind_info) 1031{ 1032 struct rt_msghdr rtm; 1033 struct sockaddr_rtdns rtdns; 1034 struct iovec iov[3]; 1035 long pad = 0; 1036 int iovcnt = 0, padlen; 1037 1038 memset(&rtm, 0, sizeof(rtm)); 1039 1040 rtm.rtm_version = RTM_VERSION; 1041 rtm.rtm_type = RTM_PROPOSAL; 1042 rtm.rtm_msglen = sizeof(rtm); 1043 rtm.rtm_tableid = rdomain; 1044 rtm.rtm_index = index; 1045 rtm.rtm_seq = arc4random(); 1046 rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT; 1047 rtm.rtm_addrs = RTA_DNS; 1048 rtm.rtm_flags = RTF_UP; 1049 1050 iov[iovcnt].iov_base = &rtm; 1051 iov[iovcnt++].iov_len = sizeof(rtm); 1052 1053 memset(&rtdns, 0, sizeof(rtdns)); 1054 rtdns.sr_family = AF_INET; 1055 1056 rtdns.sr_len = 2 + unwind_info->count * sizeof(in_addr_t); 1057 memcpy(rtdns.sr_dns, unwind_info->ns, 1058 unwind_info->count * sizeof(in_addr_t)); 1059 1060 iov[iovcnt].iov_base = &rtdns; 1061 iov[iovcnt++].iov_len = sizeof(rtdns); 1062 rtm.rtm_msglen += sizeof(rtdns); 1063 padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); 1064 if (padlen > 0) { 1065 iov[iovcnt].iov_base = &pad; 1066 iov[iovcnt++].iov_len = padlen; 1067 rtm.rtm_msglen += padlen; 1068 } 1069 1070 if (writev(routefd, iov, iovcnt) == -1) 1071 log_warn("failed to tell unwind"); 1072} 1073