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 <syslog.h> 28 #include <alloca.h> 29 #include <inttypes.h> 30 31 #include <arpa/inet.h> 32 #include <net/if.h> 33 #include <netinet/ip6.h> 34 #include <netpacket/packet.h> 35 #include <linux/netlink.h> 36 37 #include <sys/socket.h> 38 #include <sys/ioctl.h> 39 #include <sys/epoll.h> 40 #include <sys/types.h> 41 #include <sys/wait.h> 42 #include <sys/syscall.h> 43 44 #include <libubox/uloop.h> 45 #include "odhcpd.h" 46 47 static int ioctl_sock = -1; 48 static int urandom_fd = -1; 49 50 static void sighandler(_unused int signal) 51 { 52 uloop_end(); 53 } 54 55 static void print_usage(const char *app) 56 { 57 printf( 58 "== %s Usage ==\n\n" 59 " -h, --help Print this help\n" 60 " -l level Specify log level 0..7 (default %d)\n", 61 app, config.log_level 62 ); 63 } 64 65 static bool ipv6_enabled(void) 66 { 67 int fd = socket(AF_INET6, SOCK_DGRAM, 0); 68 69 if (fd < 0) 70 return false; 71 72 close(fd); 73 74 return true; 75 } 76 77 int main(int argc, char **argv) 78 { 79 openlog("odhcpd", LOG_PERROR | LOG_PID, LOG_DAEMON); 80 int opt; 81 82 while ((opt = getopt(argc, argv, "hl:")) != -1) { 83 switch (opt) { 84 case 'h': 85 print_usage(argv[0]); 86 return 0; 87 case 'l': 88 config.log_level = (atoi(optarg) & LOG_PRIMASK); 89 fprintf(stderr, "Log level set to %d\n", config.log_level); 90 break; 91 } 92 } 93 setlogmask(LOG_UPTO(config.log_level)); 94 uloop_init(); 95 96 if (getuid() != 0) { 97 syslog(LOG_ERR, "Must be run as root!"); 98 return 2; 99 } 100 101 ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); 102 103 if (ioctl_sock < 0) 104 return 4; 105 106 if ((urandom_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) < 0) 107 return 4; 108 109 signal(SIGUSR1, SIG_IGN); 110 signal(SIGINT, sighandler); 111 signal(SIGTERM, sighandler); 112 113 if (netlink_init()) 114 return 4; 115 116 if (ipv6_enabled()) { 117 if (router_init()) 118 return 4; 119 120 if (dhcpv6_init()) 121 return 4; 122 123 if (ndp_init()) 124 return 4; 125 } 126 #ifndef DHCPV4_SUPPORT 127 else 128 return 4; 129 #else 130 if (dhcpv4_init()) 131 return 4; 132 #endif 133 134 odhcpd_run(); 135 return 0; 136 } 137 138 139 /* Read IPv6 MTU for interface */ 140 int odhcpd_get_interface_config(const char *ifname, const char *what) 141 { 142 char buf[64]; 143 144 snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/%s", ifname, what); 145 146 int fd = open(buf, O_RDONLY); 147 if (fd < 0) 148 return -1; 149 150 ssize_t len = read(fd, buf, sizeof(buf) - 1); 151 close(fd); 152 153 if (len < 0) 154 return -1; 155 156 buf[len] = 0; 157 return atoi(buf); 158 } 159 160 161 /* Read IPv6 MAC for interface */ 162 int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6]) 163 { 164 struct ifreq ifr; 165 166 memset(&ifr, 0, sizeof(ifr)); 167 strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); 168 if (ioctl(ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) 169 return -1; 170 171 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 172 return 0; 173 } 174 175 int odhcpd_get_flags(const struct interface *iface) 176 { 177 struct ifreq ifr; 178 179 memset(&ifr, 0, sizeof(ifr)); 180 strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); 181 if (ioctl(ioctl_sock, SIOCGIFFLAGS, &ifr) < 0) 182 return -1; 183 184 return ifr.ifr_flags; 185 } 186 187 188 /* Forwards a packet on a specific interface */ 189 ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest, 190 struct iovec *iov, size_t iov_len, 191 const struct interface *iface) 192 { 193 /* Construct headers */ 194 uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {0}; 195 struct msghdr msg = { 196 .msg_name = (void *) dest, 197 .msg_namelen = sizeof(*dest), 198 .msg_iov = iov, 199 .msg_iovlen = iov_len, 200 .msg_control = cmsg_buf, 201 .msg_controllen = sizeof(cmsg_buf), 202 .msg_flags = 0 203 }; 204 205 /* Set control data (define destination interface) */ 206 struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg); 207 chdr->cmsg_level = IPPROTO_IPV6; 208 chdr->cmsg_type = IPV6_PKTINFO; 209 chdr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 210 struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(chdr); 211 pktinfo->ipi6_ifindex = iface->ifindex; 212 213 /* Also set scope ID if link-local */ 214 if (IN6_IS_ADDR_LINKLOCAL(&dest->sin6_addr) 215 || IN6_IS_ADDR_MC_LINKLOCAL(&dest->sin6_addr)) 216 dest->sin6_scope_id = iface->ifindex; 217 218 char ipbuf[INET6_ADDRSTRLEN]; 219 inet_ntop(AF_INET6, &dest->sin6_addr, ipbuf, sizeof(ipbuf)); 220 221 ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT); 222 if (sent < 0) 223 syslog(LOG_ERR, "Failed to send to %s%%%s@%s (%m)", 224 ipbuf, iface->name, iface->ifname); 225 else 226 syslog(LOG_DEBUG, "Sent %zd bytes to %s%%%s@%s", 227 sent, ipbuf, iface->name, iface->ifname); 228 return sent; 229 } 230 231 232 static int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr) 233 { 234 int ret = -1; 235 struct sockaddr_in6 addr; 236 socklen_t alen = sizeof(addr); 237 int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 238 239 if (sock < 0) 240 return -1; 241 242 memset(&addr, 0, sizeof(addr)); 243 addr.sin6_family = AF_INET6; 244 inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &addr.sin6_addr); 245 addr.sin6_scope_id = ifindex; 246 247 if (!connect(sock, (struct sockaddr*)&addr, sizeof(addr)) && 248 !getsockname(sock, (struct sockaddr*)&addr, &alen)) { 249 *lladdr = addr.sin6_addr; 250 ret = 0; 251 } 252 253 close(sock); 254 return ret; 255 } 256 257 /* 258 * DNS address selection criteria order : 259 * - use IPv6 address with valid lifetime if none is yet selected 260 * - use IPv6 address with a preferred lifetime if the already selected IPv6 address is deprecated 261 * - use an IPv6 ULA address if the already selected IPv6 address is not an ULA address 262 * - use the IPv6 address with the longest preferred lifetime 263 */ 264 int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr *addr) 265 { 266 time_t now = odhcpd_time(); 267 ssize_t m = -1; 268 269 if (!iface->dns_service) 270 return -1; 271 272 for (size_t i = 0; i < iface->addr6_len; ++i) { 273 if (iface->addr6[i].valid_lt <= (uint32_t)now) 274 continue; 275 276 if (m < 0) { 277 m = i; 278 continue; 279 } 280 281 if (iface->addr6[m].preferred_lt >= (uint32_t)now && 282 iface->addr6[i].preferred_lt < (uint32_t)now) 283 continue; 284 285 if (IN6_IS_ADDR_ULA(&iface->addr6[i].addr.in6)) { 286 if (!IN6_IS_ADDR_ULA(&iface->addr6[m].addr.in6)) { 287 m = i; 288 continue; 289 } 290 } else if (IN6_IS_ADDR_ULA(&iface->addr6[m].addr.in6)) 291 continue; 292 293 if (iface->addr6[i].preferred_lt > iface->addr6[m].preferred_lt) 294 m = i; 295 } 296 297 if (m >= 0) { 298 *addr = iface->addr6[m].addr.in6; 299 return 0; 300 } 301 302 return odhcpd_get_linklocal_interface_address(iface->ifindex, addr); 303 } 304 305 struct interface* odhcpd_get_interface_by_index(int ifindex) 306 { 307 struct interface *iface; 308 309 avl_for_each_element(&interfaces, iface, avl) { 310 if (iface->ifindex == ifindex) 311 return iface; 312 } 313 314 return NULL; 315 } 316 317 /* Convenience function to receive and do basic validation of packets */ 318 static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int events) 319 { 320 struct odhcpd_event *e = container_of(u, struct odhcpd_event, uloop); 321 322 uint8_t data_buf[8192], cmsg_buf[128]; 323 union { 324 struct sockaddr_in6 in6; 325 struct sockaddr_in in; 326 struct sockaddr_ll ll; 327 struct sockaddr_nl nl; 328 } addr; 329 330 if (u->error) { 331 int ret = -1; 332 socklen_t ret_len = sizeof(ret); 333 334 u->error = false; 335 if (e->handle_error && getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len) == 0) 336 e->handle_error(e, ret); 337 } 338 339 if (e->recv_msgs) { 340 e->recv_msgs(e); 341 return; 342 } 343 344 while (true) { 345 struct iovec iov = {data_buf, sizeof(data_buf)}; 346 struct msghdr msg = { 347 .msg_name = (void *) &addr, 348 .msg_namelen = sizeof(addr), 349 .msg_iov = &iov, 350 .msg_iovlen = 1, 351 .msg_control = cmsg_buf, 352 .msg_controllen = sizeof(cmsg_buf), 353 .msg_flags = 0 354 }; 355 356 ssize_t len = recvmsg(u->fd, &msg, MSG_DONTWAIT); 357 if (len < 0) { 358 if (errno == EAGAIN) 359 break; 360 else 361 continue; 362 } 363 364 365 /* Extract destination interface */ 366 int destiface = 0; 367 int *hlim = NULL; 368 void *dest = NULL; 369 struct in6_pktinfo *pktinfo; 370 struct in_pktinfo *pkt4info; 371 for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL; ch = CMSG_NXTHDR(&msg, ch)) { 372 if (ch->cmsg_level == IPPROTO_IPV6 && 373 ch->cmsg_type == IPV6_PKTINFO) { 374 pktinfo = (struct in6_pktinfo*)CMSG_DATA(ch); 375 destiface = pktinfo->ipi6_ifindex; 376 dest = &pktinfo->ipi6_addr; 377 } else if (ch->cmsg_level == IPPROTO_IP && 378 ch->cmsg_type == IP_PKTINFO) { 379 pkt4info = (struct in_pktinfo*)CMSG_DATA(ch); 380 destiface = pkt4info->ipi_ifindex; 381 dest = &pkt4info->ipi_addr; 382 } else if (ch->cmsg_level == IPPROTO_IPV6 && 383 ch->cmsg_type == IPV6_HOPLIMIT) { 384 hlim = (int*)CMSG_DATA(ch); 385 } 386 } 387 388 /* Check hoplimit if received */ 389 if (hlim && *hlim != 255) 390 continue; 391 392 /* Detect interface for packet sockets */ 393 if (addr.ll.sll_family == AF_PACKET) 394 destiface = addr.ll.sll_ifindex; 395 396 char ipbuf[INET6_ADDRSTRLEN] = "kernel"; 397 if (addr.ll.sll_family == AF_PACKET && 398 len >= (ssize_t)sizeof(struct ip6_hdr)) 399 inet_ntop(AF_INET6, &data_buf[8], ipbuf, sizeof(ipbuf)); 400 else if (addr.in6.sin6_family == AF_INET6) 401 inet_ntop(AF_INET6, &addr.in6.sin6_addr, ipbuf, sizeof(ipbuf)); 402 else if (addr.in.sin_family == AF_INET) 403 inet_ntop(AF_INET, &addr.in.sin_addr, ipbuf, sizeof(ipbuf)); 404 405 /* From netlink */ 406 if (addr.nl.nl_family == AF_NETLINK) { 407 syslog(LOG_DEBUG, "Received %zd Bytes from %s%%netlink", len, 408 ipbuf); 409 e->handle_dgram(&addr, data_buf, len, NULL, dest); 410 return; 411 } else if (destiface != 0) { 412 struct interface *iface; 413 414 avl_for_each_element(&interfaces, iface, avl) { 415 if (iface->ifindex != destiface) 416 continue; 417 418 syslog(LOG_DEBUG, "Received %zd Bytes from %s%%%s@%s", len, 419 ipbuf, iface->name, iface->ifname); 420 421 e->handle_dgram(&addr, data_buf, len, iface, dest); 422 } 423 } 424 425 426 } 427 } 428 429 /* Register events for the multiplexer */ 430 int odhcpd_register(struct odhcpd_event *event) 431 { 432 event->uloop.cb = odhcpd_receive_packets; 433 return uloop_fd_add(&event->uloop, ULOOP_READ | 434 ((event->handle_error) ? ULOOP_ERROR_CB : 0)); 435 } 436 437 int odhcpd_deregister(struct odhcpd_event *event) 438 { 439 event->uloop.cb = NULL; 440 return uloop_fd_delete(&event->uloop); 441 } 442 443 void odhcpd_process(struct odhcpd_event *event) 444 { 445 odhcpd_receive_packets(&event->uloop, 0); 446 } 447 448 int odhcpd_urandom(void *data, size_t len) 449 { 450 return read(urandom_fd, data, len); 451 } 452 453 454 time_t odhcpd_time(void) 455 { 456 struct timespec ts; 457 clock_gettime(CLOCK_MONOTONIC, &ts); 458 return ts.tv_sec; 459 } 460 461 462 static const char hexdigits[] = "0123456789abcdef"; 463 static const int8_t hexvals[] = { 464 -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, 465 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 466 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 467 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 468 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 469 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 470 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 472 }; 473 474 ssize_t odhcpd_unhexlify(uint8_t *dst, size_t len, const char *src) 475 { 476 size_t c; 477 for (c = 0; c < len && src[0] && src[1]; ++c) { 478 int8_t x = (int8_t)*src++; 479 int8_t y = (int8_t)*src++; 480 if (x < 0 || (x = hexvals[x]) < 0 481 || y < 0 || (y = hexvals[y]) < 0) 482 return -1; 483 dst[c] = x << 4 | y; 484 while (((int8_t)*src) < 0 || 485 (*src && hexvals[(uint8_t)*src] < 0)) 486 src++; 487 } 488 489 return c; 490 } 491 492 493 void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len) 494 { 495 for (size_t i = 0; i < len; ++i) { 496 *dst++ = hexdigits[src[i] >> 4]; 497 *dst++ = hexdigits[src[i] & 0x0f]; 498 } 499 *dst = 0; 500 } 501 502 const char *odhcpd_print_mac(const uint8_t *mac, const size_t len) 503 { 504 static char buf[32]; 505 506 snprintf(buf, sizeof(buf), "%02x", mac[0]); 507 for (size_t i = 1, j = 2; i < len && j < sizeof(buf); i++, j += 3) 508 snprintf(buf + j, sizeof(buf) - j, ":%02x", mac[i]); 509 510 return buf; 511 } 512 513 int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits) 514 { 515 const uint8_t *a = av, *b = bv; 516 size_t bytes = bits / 8; 517 bits %= 8; 518 519 int res = memcmp(a, b, bytes); 520 if (res == 0 && bits > 0) 521 res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits)); 522 523 return res; 524 } 525 526 527 void odhcpd_bmemcpy(void *av, const void *bv, size_t bits) 528 { 529 uint8_t *a = av; 530 const uint8_t *b = bv; 531 532 size_t bytes = bits / 8; 533 bits %= 8; 534 memcpy(a, b, bytes); 535 536 if (bits > 0) { 537 uint8_t mask = (1 << (8 - bits)) - 1; 538 a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]); 539 } 540 } 541 542 543 int odhcpd_parse_addr6_prefix(const char *str, struct in6_addr *addr, uint8_t *prefix) 544 { 545 size_t len; 546 char *delim; 547 548 *prefix = 0; 549 if (!str) 550 return -1; 551 552 len = strlen(str); 553 554 char buf[len + 1]; 555 memcpy(buf, str, len); 556 buf[len] = '\0'; 557 558 delim = memchr(buf, '/', len); 559 if (!delim) 560 return -1; 561 562 *(delim++) = '\0'; 563 564 if (inet_pton(AF_INET6, buf, addr) != 1) 565 return -1; 566 567 if (sscanf(delim, "%" SCNu8, prefix) != 1 || *prefix > 128) { 568 *prefix = 0; 569 return -1; 570 } 571 572 return 0; 573 } 574 575 576 int odhcpd_netmask2bitlen(bool inet6, void *mask) 577 { 578 int bits; 579 struct in_addr *v4; 580 struct in6_addr *v6; 581 582 if (inet6) 583 for (bits = 0, v6 = mask; 584 bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128; 585 bits++); 586 else 587 for (bits = 0, v4 = mask; 588 bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000; 589 bits++); 590 591 return bits; 592 } 593 594 bool odhcpd_bitlen2netmask(bool inet6, unsigned int bits, void *mask) 595 { 596 uint8_t b; 597 struct in_addr *v4; 598 struct in6_addr *v6; 599 600 if (inet6) 601 { 602 if (bits > 128) 603 return false; 604 605 v6 = mask; 606 607 for (unsigned int i = 0; i < sizeof(v6->s6_addr); i++) 608 { 609 b = (bits > 8) ? 8 : bits; 610 v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b)); 611 bits -= b; 612 } 613 } 614 else 615 { 616 if (bits > 32) 617 return false; 618 619 v4 = mask; 620 v4->s_addr = bits ? htonl(~((1 << (32 - bits)) - 1)) : 0; 621 } 622 623 return true; 624 } 625 626 bool odhcpd_valid_hostname(const char *name) 627 { 628 #define MAX_LABEL 63 629 const char *c, *label, *label_end; 630 int label_sz = 0; 631 632 for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1; 633 *c && label_sz <= MAX_LABEL; c++) { 634 if ((*c >= '' && *c <= '9') || 635 (*c >= 'A' && *c <= 'Z') || 636 (*c >= 'a' && *c <= 'z')) { 637 label_sz++; 638 continue; 639 } 640 641 if ((*c == '_' || *c == '-') && c != label && c != label_end) { 642 label_sz++; 643 continue; 644 } 645 646 if (*c == '.') { 647 if (*(c + 1)) { 648 label = c + 1; 649 label_end = label + strcspn(label, ".") - 1; 650 label_sz = 0; 651 } 652 continue; 653 } 654 655 return false; 656 } 657 658 return (label_sz && label_sz <= MAX_LABEL ? true : false); 659 } 660
This page was automatically generated by LXR 0.3.1. • OpenWrt