1 /** 2 * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License v2 as published by 6 * the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15 #include <time.h> 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <stdio.h> 19 #include <resolv.h> 20 #include <getopt.h> 21 #include <stddef.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <signal.h> 26 #include <stdbool.h> 27 #include <alloca.h> 28 #include <inttypes.h> 29 30 #include <arpa/inet.h> 31 #include <net/if.h> 32 #include <netinet/ip6.h> 33 #include <netpacket/packet.h> 34 #include <linux/netlink.h> 35 36 #include <sys/socket.h> 37 #include <sys/ioctl.h> 38 #include <sys/epoll.h> 39 #include <sys/types.h> 40 #include <sys/wait.h> 41 #include <sys/syscall.h> 42 #include <sys/random.h> 43 44 #include <libubox/uloop.h> 45 46 #include "odhcpd.h" 47 #include "dhcpv6-ia.h" 48 49 static int ioctl_sock = -1; 50 51 void __iflog(int lvl, const char *fmt, ...) 52 { 53 va_list ap; 54 55 if (lvl > config.log_level) 56 return; 57 58 va_start(ap, fmt); 59 60 if (config.log_syslog) { 61 vsyslog(lvl, fmt, ap); 62 } else { 63 vfprintf(stderr, fmt, ap); 64 fprintf(stderr, "\n"); 65 } 66 67 va_end(ap); 68 } 69 70 _o_noreturn static void print_usage(const char *app, int exit_status) 71 { 72 printf("== %s Usage ==\n" 73 "Features: ra ndp dhcpv6" 74 #ifdef DHCPV4_SUPPORT 75 " dhcpv4" 76 #else 77 " no-dhcpv4" 78 #endif /* DHCPV4_SUPPORT */ 79 #ifdef WITH_UBUS 80 " ubus" 81 #else 82 " no-ubus" 83 #endif /* WITH_UBUS */ 84 "\n" 85 "\n" 86 " -c <dir> Read UCI configuration files from <dir>\n" 87 " -l <int> Specify log level 0..7 (default %d)\n" 88 " -f Log to stderr instead of syslog\n" 89 #ifdef WITH_UBUS 90 " -u Disable ubus support\n" 91 #endif /* WITH_UBUS */ 92 " -h Print this help text and exit\n", 93 app, config.log_level); 94 95 exit(exit_status); 96 } 97 98 static bool ipv6_enabled(void) 99 { 100 int fd = socket(AF_INET6, SOCK_DGRAM, 0); 101 102 if (fd < 0) 103 return false; 104 105 close(fd); 106 107 return true; 108 } 109 110 int main(int argc, char **argv) 111 { 112 int opt; 113 114 while ((opt = getopt(argc, argv, "c:l:fuh")) != -1) { 115 switch (opt) { 116 case 'c': 117 struct stat sb; 118 char *path; 119 120 free(config.uci_cfgdir); 121 config.uci_cfgdir = NULL; 122 123 path = realpath(optarg, NULL); 124 if (!path || stat(path, &sb) || !S_ISDIR(sb.st_mode)) { 125 fprintf(stderr, "%s is not a directory, ignoring\n", optarg); 126 free(path); 127 break; 128 } 129 130 fprintf(stderr, "Configuration will be read from %s\n", path); 131 config.uci_cfgdir = path; 132 break; 133 134 case 'l': 135 config.log_level = (atoi(optarg) & LOG_PRIMASK); 136 config.log_level_cmdline = true; 137 fprintf(stderr, "Log level set to %d\n", config.log_level); 138 break; 139 case 'f': 140 config.log_syslog = false; 141 fprintf(stderr, "Logging to stderr\n"); 142 break; 143 case 'u': 144 config.use_ubus = false; 145 fprintf(stderr, "Ubus support disabled\n"); 146 break; 147 case 'h': 148 print_usage(argv[0], EXIT_SUCCESS); 149 case '?': 150 default: 151 print_usage(argv[0], EXIT_FAILURE); 152 } 153 } 154 155 if (getuid() != 0) { 156 error("Must be run as root!"); 157 return 2; 158 } 159 160 if (config.log_syslog) { 161 openlog("odhcpd", LOG_PERROR | LOG_PID, LOG_DAEMON); 162 setlogmask(LOG_UPTO(config.log_level)); 163 } 164 165 uloop_init(); 166 167 ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); 168 if (ioctl_sock < 0) 169 return 4; 170 171 if (netlink_init()) 172 return 4; 173 174 if (ipv6_enabled()) { 175 if (router_init()) 176 return 4; 177 178 if (dhcpv6_init()) 179 return 4; 180 181 if (ndp_init()) 182 return 4; 183 } 184 #ifndef DHCPV4_SUPPORT 185 else 186 return 4; 187 #else 188 if (dhcpv4_init()) 189 return 4; 190 #endif 191 192 return odhcpd_run(); 193 } 194 195 196 /* Read IPv6 MTU for interface */ 197 int odhcpd_get_interface_config(const char *ifname, const char *what) 198 { 199 char buf[64]; 200 201 snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/%s", ifname, what); 202 203 int fd = open(buf, O_RDONLY); 204 if (fd < 0) 205 return -1; 206 207 ssize_t len = read(fd, buf, sizeof(buf) - 1); 208 close(fd); 209 210 if (len < 0) 211 return -1; 212 213 buf[len] = 0; 214 return atoi(buf); 215 } 216 217 218 /* Read IPv6 MAC for interface */ 219 int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]) 220 { 221 struct ifreq ifr; 222 223 memset(&ifr, 0, sizeof(ifr)); 224 strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); 225 if (ioctl(ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) 226 return -1; 227 228 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 229 return 0; 230 } 231 232 int odhcpd_get_flags(const struct interface *iface) 233 { 234 struct ifreq ifr; 235 236 memset(&ifr, 0, sizeof(ifr)); 237 strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); 238 if (ioctl(ioctl_sock, SIOCGIFFLAGS, &ifr) < 0) 239 return -1; 240 241 return ifr.ifr_flags; 242 } 243 244 245 /* Forwards a packet on a specific interface with optional source address */ 246 ssize_t odhcpd_send_with_src(int socket, struct sockaddr_in6 *dest, 247 struct iovec *iov, size_t iov_len, 248 const struct interface *iface, const struct in6_addr *src_addr) 249 { 250 /* Construct headers */ 251 uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {0}; 252 struct msghdr msg = { 253 .msg_name = (void *) dest, 254 .msg_namelen = sizeof(*dest), 255 .msg_iov = iov, 256 .msg_iovlen = iov_len, 257 .msg_control = cmsg_buf, 258 .msg_controllen = sizeof(cmsg_buf), 259 .msg_flags = 0 260 }; 261 262 /* Set control data (define destination interface) */ 263 struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg); 264 chdr->cmsg_level = IPPROTO_IPV6; 265 chdr->cmsg_type = IPV6_PKTINFO; 266 chdr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 267 struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(chdr); 268 pktinfo->ipi6_ifindex = iface->ifindex; 269 270 /* Set source address if provided */ 271 if (src_addr) 272 pktinfo->ipi6_addr = *src_addr; 273 274 /* Also set scope ID if link-local */ 275 if (IN6_IS_ADDR_LINKLOCAL(&dest->sin6_addr) 276 || IN6_IS_ADDR_MC_LINKLOCAL(&dest->sin6_addr)) 277 dest->sin6_scope_id = iface->ifindex; 278 279 char ipbuf[INET6_ADDRSTRLEN]; 280 inet_ntop(AF_INET6, &dest->sin6_addr, ipbuf, sizeof(ipbuf)); 281 282 ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT); 283 if (sent < 0) 284 error("Failed to send to %s%%%s@%s (%m)", 285 ipbuf, iface->name, iface->ifname); 286 else 287 debug("Sent %zd bytes to %s%%%s@%s", 288 sent, ipbuf, iface->name, iface->ifname); 289 return sent; 290 } 291 292 /* Forwards a packet on a specific interface */ 293 ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest, 294 struct iovec *iov, size_t iov_len, 295 const struct interface *iface) 296 { 297 return odhcpd_send_with_src(socket, dest, iov, iov_len, iface, NULL); 298 } 299 300 301 int odhcpd_get_interface_linklocal_addr(struct interface *iface, struct in6_addr *addr) 302 { 303 /* Return cached address if valid */ 304 if (iface->cached_linklocal_valid) { 305 *addr = iface->cached_linklocal_addr; 306 return 0; 307 } 308 309 /* First try to get link-local address from interface addresses */ 310 for (size_t i = 0; i < iface->addr6_len; ++i) { 311 if (IN6_IS_ADDR_LINKLOCAL(&iface->addr6[i].addr.in6)) { 312 *addr = iface->addr6[i].addr.in6; 313 /* Cache the result for future use */ 314 iface->cached_linklocal_addr = *addr; 315 iface->cached_linklocal_valid = true; 316 return 0; 317 } 318 } 319 320 /* Fallback to socket-based method */ 321 struct sockaddr_in6 sockaddr; 322 socklen_t alen = sizeof(sockaddr); 323 int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 324 325 if (sock >= 0) { 326 memset(&sockaddr, 0, sizeof(sockaddr)); 327 sockaddr.sin6_family = AF_INET6; 328 inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &sockaddr.sin6_addr); 329 sockaddr.sin6_scope_id = iface->ifindex; 330 331 if (!connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) && 332 !getsockname(sock, (struct sockaddr*)&sockaddr, &alen)) { 333 *addr = sockaddr.sin6_addr; 334 /* Cache the result for future use */ 335 iface->cached_linklocal_addr = *addr; 336 iface->cached_linklocal_valid = true; 337 close(sock); 338 return 0; 339 } 340 close(sock); 341 } 342 343 return -1; 344 } 345 346 /* Try to send with link-local source address for RFC 4861 compliance and macOS compatibility. 347 * RFC 4861, ยง4.2 mandates that Neighbor Advertisement source address MUST be 348 * the link-local address assigned to the interface from which this message is sent. */ 349 ssize_t odhcpd_try_send_with_src(int socket, struct sockaddr_in6 *dest, 350 struct iovec *iov, size_t iov_len, 351 struct interface *iface) 352 { 353 struct in6_addr src_addr; 354 355 if (iface->ndp_from_link_local && odhcpd_get_interface_linklocal_addr(iface, &src_addr) == 0) { 356 return odhcpd_send_with_src(socket, dest, iov, iov_len, iface, &src_addr); 357 } else { 358 /* Fall back to default behavior if no link-local address is available or flag is disabled */ 359 return odhcpd_send(socket, dest, iov, iov_len, iface); 360 } 361 } 362 363 /* 364 * DNS address selection criteria order : 365 * - use IPv6 address with valid lifetime if none is yet selected 366 * - use IPv6 address with a preferred lifetime if the already selected IPv6 address is deprecated 367 * - use an IPv6 ULA address if the already selected IPv6 address is not an ULA address 368 * - use the IPv6 address with the longest preferred lifetime 369 */ 370 int odhcpd_get_interface_dns_addr6(struct interface *iface, struct in6_addr *dns_addr6) 371 { 372 time_t now = odhcpd_time(); 373 ssize_t m = -1; 374 375 if (!iface->dns_service) 376 return -1; 377 378 for (size_t i = 0; i < iface->addr6_len; ++i) { 379 if (iface->addr6[i].valid_lt <= (uint32_t)now) 380 continue; 381 382 if (m < 0) { 383 m = i; 384 continue; 385 } 386 387 if (iface->addr6[m].preferred_lt >= (uint32_t)now && 388 iface->addr6[i].preferred_lt < (uint32_t)now) 389 continue; 390 391 if (IN6_IS_ADDR_ULA(&iface->addr6[i].addr.in6)) { 392 if (!IN6_IS_ADDR_ULA(&iface->addr6[m].addr.in6)) { 393 m = i; 394 continue; 395 } 396 } else if (IN6_IS_ADDR_ULA(&iface->addr6[m].addr.in6)) 397 continue; 398 399 if (iface->addr6[i].preferred_lt > iface->addr6[m].preferred_lt) 400 m = i; 401 } 402 403 if (m >= 0) { 404 *dns_addr6 = iface->addr6[m].addr.in6; 405 return 0; 406 } 407 408 return odhcpd_get_interface_linklocal_addr(iface, dns_addr6); 409 } 410 411 struct interface* odhcpd_get_interface_by_index(int ifindex) 412 { 413 struct interface *iface; 414 415 avl_for_each_element(&interfaces, iface, avl) { 416 if (iface->ifindex == ifindex) 417 return iface; 418 } 419 420 return NULL; 421 } 422 423 /* Convenience function to receive and do basic validation of packets */ 424 static void odhcpd_receive_packets(struct uloop_fd *u, _o_unused unsigned int events) 425 { 426 struct odhcpd_event *e = container_of(u, struct odhcpd_event, uloop); 427 428 uint8_t data_buf[8192], cmsg_buf[128]; 429 union { 430 struct sockaddr_in6 in6; 431 struct sockaddr_in in; 432 struct sockaddr_ll ll; 433 struct sockaddr_nl nl; 434 } addr; 435 436 if (u->error) { 437 int ret = -1; 438 socklen_t ret_len = sizeof(ret); 439 440 u->error = false; 441 if (e->handle_error && getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len) == 0) 442 e->handle_error(e, ret); 443 } 444 445 if (e->recv_msgs) { 446 e->recv_msgs(e); 447 return; 448 } 449 450 while (true) { 451 struct iovec iov = {data_buf, sizeof(data_buf)}; 452 struct msghdr msg = { 453 .msg_name = (void *) &addr, 454 .msg_namelen = sizeof(addr), 455 .msg_iov = &iov, 456 .msg_iovlen = 1, 457 .msg_control = cmsg_buf, 458 .msg_controllen = sizeof(cmsg_buf), 459 .msg_flags = 0 460 }; 461 462 ssize_t len = recvmsg(u->fd, &msg, MSG_DONTWAIT); 463 if (len < 0) { 464 if (errno == EAGAIN) 465 break; 466 else 467 continue; 468 } 469 470 471 /* Extract destination interface */ 472 int destiface = 0; 473 int *hlim = NULL; 474 void *dest = NULL; 475 struct in6_pktinfo *pktinfo; 476 struct in_pktinfo *pkt4info; 477 for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL; ch = CMSG_NXTHDR(&msg, ch)) { 478 if (ch->cmsg_level == IPPROTO_IPV6 && 479 ch->cmsg_type == IPV6_PKTINFO) { 480 pktinfo = (struct in6_pktinfo*)CMSG_DATA(ch); 481 destiface = pktinfo->ipi6_ifindex; 482 dest = &pktinfo->ipi6_addr; 483 } else if (ch->cmsg_level == IPPROTO_IP && 484 ch->cmsg_type == IP_PKTINFO) { 485 pkt4info = (struct in_pktinfo*)CMSG_DATA(ch); 486 destiface = pkt4info->ipi_ifindex; 487 dest = &pkt4info->ipi_addr; 488 } else if (ch->cmsg_level == IPPROTO_IPV6 && 489 ch->cmsg_type == IPV6_HOPLIMIT) { 490 hlim = (int*)CMSG_DATA(ch); 491 } 492 } 493 494 /* Check hoplimit if received */ 495 if (hlim && *hlim != 255) 496 continue; 497 498 /* Detect interface for packet sockets */ 499 if (addr.ll.sll_family == AF_PACKET) 500 destiface = addr.ll.sll_ifindex; 501 502 char ipbuf[INET6_ADDRSTRLEN] = "kernel"; 503 if (addr.ll.sll_family == AF_PACKET && 504 len >= (ssize_t)sizeof(struct ip6_hdr)) 505 inet_ntop(AF_INET6, &data_buf[8], ipbuf, sizeof(ipbuf)); 506 else if (addr.in6.sin6_family == AF_INET6) 507 inet_ntop(AF_INET6, &addr.in6.sin6_addr, ipbuf, sizeof(ipbuf)); 508 else if (addr.in.sin_family == AF_INET) 509 inet_ntop(AF_INET, &addr.in.sin_addr, ipbuf, sizeof(ipbuf)); 510 511 /* From netlink */ 512 if (addr.nl.nl_family == AF_NETLINK) { 513 debug("Received %zd Bytes from %s%%netlink", len, ipbuf); 514 e->handle_dgram(&addr, data_buf, len, NULL, dest); 515 return; 516 } else if (destiface != 0) { 517 struct interface *iface; 518 519 avl_for_each_element(&interfaces, iface, avl) { 520 if (iface->ifindex != destiface) 521 continue; 522 523 debug("Received %zd Bytes from %s%%%s@%s", len, 524 ipbuf, iface->name, iface->ifname); 525 526 e->handle_dgram(&addr, data_buf, len, iface, dest); 527 } 528 } 529 530 531 } 532 } 533 534 /* Register events for the multiplexer */ 535 int odhcpd_register(struct odhcpd_event *event) 536 { 537 event->uloop.cb = odhcpd_receive_packets; 538 return uloop_fd_add(&event->uloop, ULOOP_READ | 539 ((event->handle_error) ? ULOOP_ERROR_CB : 0)); 540 } 541 542 int odhcpd_deregister(struct odhcpd_event *event) 543 { 544 event->uloop.cb = NULL; 545 return uloop_fd_delete(&event->uloop); 546 } 547 548 void odhcpd_process(struct odhcpd_event *event) 549 { 550 odhcpd_receive_packets(&event->uloop, 0); 551 } 552 553 void odhcpd_urandom(void *data, size_t len) 554 { 555 static bool warned_once = false; 556 557 while (true) { 558 ssize_t r; 559 560 if (len == 0) 561 return; 562 563 r = getrandom(data, len, GRND_INSECURE); 564 if (r < 0) { 565 if (errno == EINTR) 566 continue; 567 568 if (!warned_once) { 569 error("getrandom(): %m"); 570 warned_once = true; 571 } 572 573 return; 574 } 575 576 len -= r; 577 data = (uint8_t *)data + r; 578 } 579 } 580 581 time_t odhcpd_time(void) 582 { 583 struct timespec ts; 584 clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); 585 return ts.tv_sec; 586 } 587 588 589 static const char hexdigits[] = "0123456789abcdef"; 590 static const int8_t hexvals[] = { 591 -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, 592 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 593 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 594 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 595 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 596 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 597 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 598 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 599 }; 600 601 ssize_t odhcpd_unhexlify(uint8_t *dst, size_t len, const char *src) 602 { 603 size_t c; 604 for (c = 0; c < len && src[0] && src[1]; ++c) { 605 int8_t x = (int8_t)*src++; 606 int8_t y = (int8_t)*src++; 607 if (x < 0 || (x = hexvals[x]) < 0 608 || y < 0 || (y = hexvals[y]) < 0) 609 return -1; 610 dst[c] = x << 4 | y; 611 while (((int8_t)*src) < 0 || 612 (*src && hexvals[(uint8_t)*src] < 0)) 613 src++; 614 } 615 616 return c; 617 } 618 619 620 void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len) 621 { 622 for (size_t i = 0; i < len; ++i) { 623 *dst++ = hexdigits[src[i] >> 4]; 624 *dst++ = hexdigits[src[i] & 0x0f]; 625 } 626 *dst = 0; 627 } 628 629 const char *odhcpd_print_mac(const uint8_t *mac, const size_t len) 630 { 631 static char buf[32]; 632 633 snprintf(buf, sizeof(buf), "%02x", mac[0]); 634 for (size_t i = 1, j = 2; i < len && j < sizeof(buf); i++, j += 3) 635 snprintf(buf + j, sizeof(buf) - j, ":%02x", mac[i]); 636 637 return buf; 638 } 639 640 int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits) 641 { 642 const uint8_t *a = av, *b = bv; 643 size_t bytes = bits / 8; 644 bits %= 8; 645 646 int res = memcmp(a, b, bytes); 647 if (res == 0 && bits > 0) 648 res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits)); 649 650 return res; 651 } 652 653 654 void odhcpd_bmemcpy(void *av, const void *bv, size_t bits) 655 { 656 uint8_t *a = av; 657 const uint8_t *b = bv; 658 659 size_t bytes = bits / 8; 660 bits %= 8; 661 memcpy(a, b, bytes); 662 663 if (bits > 0) { 664 uint8_t mask = (1 << (8 - bits)) - 1; 665 a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]); 666 } 667 } 668 669 void odhcpd_enum_addr6(struct interface *iface, struct dhcpv6_lease *lease, 670 time_t now, odhcpd_enum_addr6_cb_t func, void *arg) 671 { 672 struct odhcpd_ipaddr *addrs = iface->addr6; 673 size_t m = get_preferred_addr(addrs, iface->addr6_len); 674 675 for (size_t i = 0; i < iface->addr6_len; ++i) { 676 struct in6_addr addr; 677 uint32_t preferred_lt, valid_lt; 678 int prefix = lease->length; 679 680 if (!valid_addr(&addrs[i], now)) 681 continue; 682 683 /* Filter Out Prefixes */ 684 if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) { 685 char addrbuf[INET6_ADDRSTRLEN]; 686 info("Address %s filtered out on %s", 687 inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)), 688 iface->name); 689 continue; 690 } 691 692 if (lease->flags & OAF_DHCPV6_NA) { 693 if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs)) 694 continue; 695 696 addr = in6_from_prefix_and_iid(&addrs[i], lease->assigned_host_id); 697 } else { 698 if (!valid_prefix_length(lease, addrs[i].prefix_len)) 699 continue; 700 701 addr = addrs[i].addr.in6; 702 addr.s6_addr32[1] |= htonl(lease->assigned_subnet_id); 703 addr.s6_addr32[2] = addr.s6_addr32[3] = 0; 704 } 705 706 preferred_lt = addrs[i].preferred_lt; 707 if (preferred_lt > (uint32_t)lease->preferred_until) 708 preferred_lt = lease->preferred_until; 709 710 if (preferred_lt > (uint32_t)lease->valid_until) 711 preferred_lt = lease->valid_until; 712 713 if (preferred_lt != UINT32_MAX) 714 preferred_lt -= now; 715 716 valid_lt = addrs[i].valid_lt; 717 if (valid_lt > (uint32_t)lease->valid_until) 718 valid_lt = lease->valid_until; 719 720 if (valid_lt != UINT32_MAX) 721 valid_lt -= now; 722 723 func(lease, &addr, prefix, preferred_lt, valid_lt, arg); 724 } 725 } 726 727 int odhcpd_parse_addr6_prefix(const char *str, struct in6_addr *addr, uint8_t *prefix) 728 { 729 size_t len; 730 char *delim; 731 732 *prefix = 0; 733 if (!str) 734 return -1; 735 736 len = strlen(str); 737 738 char buf[len + 1]; 739 memcpy(buf, str, len); 740 buf[len] = '\0'; 741 742 delim = memchr(buf, '/', len); 743 if (!delim) 744 return -1; 745 746 *(delim++) = '\0'; 747 748 if (inet_pton(AF_INET6, buf, addr) != 1) 749 return -1; 750 751 if (sscanf(delim, "%" SCNu8, prefix) != 1 || *prefix > 128) { 752 *prefix = 0; 753 return -1; 754 } 755 756 return 0; 757 } 758 759 bool odhcpd_valid_hostname(const char *name) 760 { 761 #define MAX_LABEL 63 762 const char *c, *label, *label_end; 763 int label_sz = 0; 764 765 for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1; 766 *c && label_sz <= MAX_LABEL; c++) { 767 if ((*c >= '' && *c <= '9') || 768 (*c >= 'A' && *c <= 'Z') || 769 (*c >= 'a' && *c <= 'z')) { 770 label_sz++; 771 continue; 772 } 773 774 if ((*c == '_' || *c == '-') && c != label && c != label_end) { 775 label_sz++; 776 continue; 777 } 778 779 if (*c == '.') { 780 if (*(c + 1)) { 781 label = c + 1; 782 label_end = label + strcspn(label, ".") - 1; 783 label_sz = 0; 784 } 785 continue; 786 } 787 788 return false; 789 } 790 791 return (label_sz && label_sz <= MAX_LABEL ? true : false); 792 } 793
This page was automatically generated by LXR 0.3.1. • OpenWrt