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 static void sighandler(_unused int signal) 71 { 72 uloop_end(); 73 } 74 75 static void print_usage(const char *app) 76 { 77 printf("== %s Usage ==\n" 78 "Features: ra ndp dhcpv6" 79 #ifdef DHCPV4_SUPPORT 80 " dhcpv4" 81 #else 82 " no-dhcpv4" 83 #endif /* DHCPV4_SUPPORT */ 84 #ifdef WITH_UBUS 85 " ubus" 86 #else 87 " no-ubus" 88 #endif /* WITH_UBUS */ 89 "\n" 90 "\n" 91 " -c <dir> Read UCI configuration files from <dir>\n" 92 " -l <int> Specify log level 0..7 (default %d)\n" 93 " -f Log to stderr instead of syslog\n" 94 " -h Print this help text and exit\n", 95 app, config.log_level); 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:fh")) != -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 'h': 144 print_usage(argv[0]); 145 return 0; 146 } 147 } 148 149 if (config.log_syslog) { 150 openlog("odhcpd", LOG_PERROR | LOG_PID, LOG_DAEMON); 151 setlogmask(LOG_UPTO(config.log_level)); 152 } 153 154 uloop_init(); 155 156 if (getuid() != 0) { 157 error("Must be run as root!"); 158 return 2; 159 } 160 161 ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); 162 if (ioctl_sock < 0) 163 return 4; 164 165 signal(SIGUSR1, SIG_IGN); 166 signal(SIGINT, sighandler); 167 signal(SIGTERM, sighandler); 168 169 if (netlink_init()) 170 return 4; 171 172 if (ipv6_enabled()) { 173 if (router_init()) 174 return 4; 175 176 if (dhcpv6_init()) 177 return 4; 178 179 if (ndp_init()) 180 return 4; 181 } 182 #ifndef DHCPV4_SUPPORT 183 else 184 return 4; 185 #else 186 if (dhcpv4_init()) 187 return 4; 188 #endif 189 190 odhcpd_run(); 191 return 0; 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_addr(struct interface *iface, struct in6_addr *addr) 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 *addr = iface->addr6[m].addr.in6; 404 return 0; 405 } 406 407 return odhcpd_get_interface_linklocal_addr(iface, addr); 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, _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)) 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 759 int odhcpd_netmask2bitlen(bool inet6, void *mask) 760 { 761 int bits; 762 struct in_addr *v4; 763 struct in6_addr *v6; 764 765 if (inet6) 766 for (bits = 0, v6 = mask; 767 bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128; 768 bits++); 769 else 770 for (bits = 0, v4 = mask; 771 bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000; 772 bits++); 773 774 return bits; 775 } 776 777 bool odhcpd_bitlen2netmask(bool inet6, unsigned int bits, void *mask) 778 { 779 uint8_t b; 780 struct in_addr *v4; 781 struct in6_addr *v6; 782 783 if (inet6) 784 { 785 if (bits > 128) 786 return false; 787 788 v6 = mask; 789 790 for (unsigned int i = 0; i < sizeof(v6->s6_addr); i++) 791 { 792 b = (bits > 8) ? 8 : bits; 793 v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b)); 794 bits -= b; 795 } 796 } 797 else 798 { 799 if (bits > 32) 800 return false; 801 802 v4 = mask; 803 v4->s_addr = bits ? htonl(~((1 << (32 - bits)) - 1)) : 0; 804 } 805 806 return true; 807 } 808 809 bool odhcpd_valid_hostname(const char *name) 810 { 811 #define MAX_LABEL 63 812 const char *c, *label, *label_end; 813 int label_sz = 0; 814 815 for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1; 816 *c && label_sz <= MAX_LABEL; c++) { 817 if ((*c >= '' && *c <= '9') || 818 (*c >= 'A' && *c <= 'Z') || 819 (*c >= 'a' && *c <= 'z')) { 820 label_sz++; 821 continue; 822 } 823 824 if ((*c == '_' || *c == '-') && c != label && c != label_end) { 825 label_sz++; 826 continue; 827 } 828 829 if (*c == '.') { 830 if (*(c + 1)) { 831 label = c + 1; 832 label_end = label + strcspn(label, ".") - 1; 833 label_sz = 0; 834 } 835 continue; 836 } 837 838 return false; 839 } 840 841 return (label_sz && label_sz <= MAX_LABEL ? true : false); 842 } 843
This page was automatically generated by LXR 0.3.1. • OpenWrt