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