1 /** 2 * Copyright (C) 2012-2014 Steven Barth <steven@midlink.org> 3 * Copyright (C) 2017-2018 Hans Dedecker <dedeckeh@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License v2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 16 #include <alloca.h> 17 #include <arpa/inet.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <linux/rtnetlink.h> 21 #include <net/if.h> 22 #include <netinet/in.h> 23 #include <netinet/icmp6.h> 24 #include <resolv.h> 25 #include <signal.h> 26 #include <stdbool.h> 27 #include <stddef.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <sys/ioctl.h> 32 #include <sys/socket.h> 33 #include <sys/types.h> 34 #include <unistd.h> 35 36 #include "odhcp6c.h" 37 #include "ra.h" 38 39 #ifndef SOL_NETLINK 40 #define SOL_NETLINK 270 41 #endif 42 43 #ifndef NETLINK_ADD_MEMBERSHIP 44 #define NETLINK_ADD_MEMBERSHIP 1 45 #endif 46 47 #ifndef IFF_LOWER_UP 48 #define IFF_LOWER_UP 0x10000 49 #endif 50 51 static bool nocarrier = false; 52 static bool ptp_link = false; 53 54 static int sock = -1, rtnl = -1; 55 static int if_index = 0; 56 static char if_name[IF_NAMESIZE] = {0}; 57 static volatile int rs_attempt = 0; 58 static struct in6_addr ra_addr = IN6ADDR_ANY_INIT; 59 static unsigned int ra_options = 0; 60 static unsigned int ra_holdoff_interval = 0; 61 static ra_ifid_mode_t ra_ifid_mode = RA_IFID_LLA; 62 static int ra_hoplimit = 0; 63 static int ra_mtu = 0; 64 static int ra_reachable = 0; 65 static int ra_retransmit = 0; 66 67 struct { 68 struct icmp6_hdr hdr; 69 struct icmpv6_opt lladdr; 70 } rs = { 71 .hdr = {ND_ROUTER_SOLICIT, 0, 0, {{0}}}, 72 .lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {0}}, 73 }; 74 75 static void ra_send_rs(_o_unused int signal); 76 77 int ra_init(const char *ifname, const struct in6_addr *ifid, 78 ra_ifid_mode_t ifid_mode, unsigned int options, 79 unsigned int holdoff_interval) 80 { 81 struct ifreq ifr; 82 83 ra_options = options; 84 ra_holdoff_interval = holdoff_interval; 85 ra_ifid_mode = ifid_mode; 86 87 const pid_t ourpid = getpid(); 88 sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6); 89 if (sock < 0) 90 goto failure; 91 92 memset(&ifr, 0, sizeof(ifr)); 93 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); 94 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) 95 goto failure; 96 97 ptp_link = !!(ifr.ifr_flags & IFF_POINTOPOINT); 98 99 memset(&ifr, 0, sizeof(ifr)); 100 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); 101 if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) 102 goto failure; 103 104 strncpy(if_name, ifname, sizeof(if_name) - 1); 105 if_index = ifr.ifr_ifindex; 106 ra_addr = *ifid; 107 108 rtnl = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE); 109 if (rtnl < 0) 110 goto failure; 111 112 struct sockaddr_nl rtnl_kernel = { .nl_family = AF_NETLINK }; 113 if (connect(rtnl, (const struct sockaddr*)&rtnl_kernel, sizeof(rtnl_kernel)) < 0) 114 goto failure; 115 116 int val = RTNLGRP_LINK; 117 if (setsockopt(rtnl, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &val, sizeof(val)) < 0) 118 goto failure; 119 120 if (fcntl(rtnl, F_SETOWN, ourpid) < 0) 121 goto failure; 122 123 if (fcntl(rtnl, F_SETFL, fcntl(sock, F_GETFL) | O_ASYNC) < 0) 124 goto failure; 125 126 struct { 127 struct nlmsghdr hdr; 128 struct ifinfomsg ifi; 129 } req = { 130 .hdr = {sizeof(req), RTM_GETLINK, NLM_F_REQUEST, 1, 0}, 131 .ifi = {.ifi_index = if_index} 132 }; 133 if (send(rtnl, &req, sizeof(req), 0) < 0) 134 goto failure; 135 136 ra_link_up(); 137 138 // Filter ICMPv6 package types 139 struct icmp6_filter filt; 140 ICMP6_FILTER_SETBLOCKALL(&filt); 141 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 142 if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) 143 goto failure; 144 145 // Bind to all-nodes 146 struct ipv6_mreq an = {ALL_IPV6_NODES, if_index}; 147 if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &an, sizeof(an)) < 0) 148 goto failure; 149 150 // Let the kernel compute our checksums 151 val = 2; 152 if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val)) < 0) 153 goto failure; 154 155 // This is required by RFC 4861 156 val = 255; 157 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) < 0) 158 goto failure; 159 160 // Receive multicast hops 161 val = 1; 162 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)) < 0) 163 goto failure; 164 165 // Bind to one device 166 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) 167 goto failure; 168 169 // Add async-mode 170 if (fcntl(sock, F_SETOWN, ourpid) < 0) 171 goto failure; 172 173 val = fcntl(sock, F_GETFL); 174 if (val < 0) 175 goto failure; 176 177 if (fcntl(sock, F_SETFL, val | O_ASYNC) < 0) 178 goto failure; 179 180 // flush any received messages that may not have had all the options (particularly the bind) applied to them 181 uint8_t buf[1500] _o_aligned(4); 182 union { 183 struct cmsghdr hdr; 184 uint8_t buf[CMSG_SPACE(sizeof(int))]; 185 } cmsg_buf; 186 187 while (true) { 188 struct sockaddr_in6 from; 189 struct iovec iov = {buf, sizeof(buf)}; 190 struct msghdr msg = { 191 .msg_name = (void *) &from, 192 .msg_namelen = sizeof(from), 193 .msg_iov = &iov, 194 .msg_iovlen = 1, 195 .msg_control = cmsg_buf.buf, 196 .msg_controllen = sizeof(cmsg_buf), 197 .msg_flags = 0 198 }; 199 200 ssize_t len = recvmsg(sock, &msg, MSG_DONTWAIT); 201 if (len <= 0) 202 break; 203 } 204 205 // Send RS 206 signal(SIGALRM, ra_send_rs); 207 ra_send_rs(SIGALRM); 208 209 return 0; 210 211 failure: 212 if (sock >= 0) 213 close(sock); 214 215 if (rtnl >= 0) 216 close(rtnl); 217 218 return -1; 219 } 220 221 static void ra_send_rs(_o_unused int signal) 222 { 223 const struct sockaddr_in6 dest = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, if_index}; 224 const struct icmpv6_opt llnull = {ND_OPT_SOURCE_LINKADDR, 1, {0}}; 225 size_t len; 226 227 if ((rs_attempt % 2 == 0) && memcmp(&rs.lladdr, &llnull, sizeof(llnull))) 228 len = sizeof(rs); 229 else 230 len = sizeof(struct icmp6_hdr); 231 232 if (sendto(sock, &rs, len, MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)) < 0) 233 error("Failed to send RS (%s)", strerror(errno)); 234 235 if (++rs_attempt <= 3) 236 alarm(4); 237 } 238 239 static int16_t pref_to_priority(uint8_t flags) 240 { 241 flags = (flags >> 3) & 0x03; 242 243 return (flags == 0x0) ? 512 : (flags == 0x1) ? 384 : 244 (flags == 0x3) ? 640 : -1; 245 } 246 247 bool ra_link_up(void) 248 { 249 static bool firstcall = true; 250 struct { 251 struct nlmsghdr hdr; 252 struct ifinfomsg msg; 253 uint8_t pad[4000]; 254 } resp; 255 bool ret = false; 256 ssize_t read; 257 258 do { 259 read = recv(rtnl, &resp, sizeof(resp), MSG_DONTWAIT); 260 261 if (read < 0 || !NLMSG_OK(&resp.hdr, (size_t)read) || 262 resp.hdr.nlmsg_type != RTM_NEWLINK || 263 resp.msg.ifi_index != if_index) 264 continue; 265 266 ssize_t alen = NLMSG_PAYLOAD(&resp.hdr, sizeof(resp.msg)); 267 for (struct rtattr *rta = (struct rtattr*)(resp.pad); 268 RTA_OK(rta, alen); rta = RTA_NEXT(rta, alen)) { 269 if (rta->rta_type == IFLA_ADDRESS && 270 RTA_PAYLOAD(rta) >= sizeof(rs.lladdr.data)) 271 memcpy(rs.lladdr.data, RTA_DATA(rta), sizeof(rs.lladdr.data)); 272 } 273 274 bool hascarrier = resp.msg.ifi_flags & IFF_LOWER_UP; 275 if (!firstcall && nocarrier != !hascarrier) 276 ret = true; 277 278 nocarrier = !hascarrier; 279 firstcall = false; 280 } while (read > 0); 281 282 if (ret) { 283 notice("carrier => %i event on %s", (int)!nocarrier, if_name); 284 285 rs_attempt = 0; 286 ra_send_rs(SIGALRM); 287 } 288 289 return ret; 290 } 291 292 static bool ra_icmpv6_valid(struct sockaddr_in6 *source, int hlim, uint8_t *data, size_t len) 293 { 294 struct icmp6_hdr *hdr = (struct icmp6_hdr*)data; 295 struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len]; 296 297 if (hlim != 255 || len < sizeof(*hdr) || hdr->icmp6_code) 298 return false; 299 300 switch (hdr->icmp6_type) { 301 case ND_ROUTER_ADVERT: 302 if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr)) 303 return false; 304 305 opt = (struct icmpv6_opt*)((struct nd_router_advert*)data + 1); 306 break; 307 308 default: 309 return false; 310 } 311 312 icmpv6_for_each_option(opt, opt, end) 313 ; 314 315 return opt == end; 316 } 317 318 static bool ra_set_hoplimit(int val) 319 { 320 if (val > 0 && val != ra_hoplimit) { 321 ra_hoplimit = val; 322 return true; 323 } 324 325 return false; 326 } 327 328 static bool ra_set_mtu(int val) 329 { 330 if (val >= 1280 && val <= 65535 && ra_mtu != val) { 331 ra_mtu = val; 332 return true; 333 } 334 335 return false; 336 } 337 338 static bool ra_set_reachable(int val) 339 { 340 if (val > 0 && val <= 3600000 && ra_reachable != val) { 341 ra_reachable = val; 342 return true; 343 } 344 345 return false; 346 } 347 348 static bool ra_set_retransmit(int val) 349 { 350 if (val > 0 && val <= 60000 && ra_retransmit != val) { 351 ra_retransmit = val; 352 return true; 353 } 354 355 return false; 356 } 357 358 static bool ra_generate_addr_eui64(void) 359 { 360 struct ifreq ifr; 361 int sock; 362 363 sock = socket(AF_INET6, SOCK_DGRAM, 0); 364 if (sock < 0) { 365 error( 366 "%s: error creating EUI64 socket", 367 if_name); 368 return false; 369 } 370 371 memset(&ifr, 0, sizeof(ifr)); 372 strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1); 373 374 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) { 375 error( 376 "%s: error getting EUI64 HW address", 377 if_name); 378 close(sock); 379 return false; 380 } 381 382 close(sock); 383 384 if (!odhcp6c_is_valid_ether_addr((uint8_t *) ifr.ifr_hwaddr.sa_data)) { 385 error( 386 "%s: invalid EUI64 HW address", 387 if_name); 388 return false; 389 } 390 391 ra_addr.s6_addr[0] = 0xfe; 392 ra_addr.s6_addr[1] = 0x80; 393 ra_addr.s6_addr[8] = ifr.ifr_hwaddr.sa_data[0] ^ 0x2; 394 ra_addr.s6_addr[9] = ifr.ifr_hwaddr.sa_data[1]; 395 ra_addr.s6_addr[10] = ifr.ifr_hwaddr.sa_data[2]; 396 ra_addr.s6_addr[11] = 0xff; 397 ra_addr.s6_addr[12] = 0xfe; 398 ra_addr.s6_addr[13] = ifr.ifr_hwaddr.sa_data[3]; 399 ra_addr.s6_addr[14] = ifr.ifr_hwaddr.sa_data[4]; 400 ra_addr.s6_addr[15] = ifr.ifr_hwaddr.sa_data[5]; 401 402 return true; 403 } 404 405 static bool ra_generate_addr_ll(void) 406 { 407 struct sockaddr_in6 addr = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, if_index}; 408 socklen_t alen = sizeof(addr); 409 int sock; 410 411 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 412 if (sock < 0) { 413 error( 414 "%s: error creating LLA socket", 415 if_name); 416 return false; 417 } 418 419 if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) { 420 error( 421 "%s: error connecting LLA socket", 422 if_name); 423 close(sock); 424 return false; 425 } 426 427 if (getsockname(sock, (struct sockaddr*) &addr, &alen) != 0) { 428 error( 429 "%s: error getting address from LLA socket", 430 if_name); 431 close(sock); 432 return false; 433 } 434 435 close(sock); 436 437 ra_addr = addr.sin6_addr; 438 439 return true; 440 } 441 442 static bool ra_generate_addr_rand(void) 443 { 444 if (odhcp6c_random(&ra_addr.s6_addr[8], 8) != 8) { 445 ra_addr.s6_addr32[2] = 0; 446 ra_addr.s6_addr32[3] = 0; 447 error( 448 "%s: error generating random interface address", 449 if_name); 450 return false; 451 } 452 453 ra_addr.s6_addr[0] = 0xfe; 454 ra_addr.s6_addr[1] = 0x80; 455 456 return true; 457 } 458 459 static void ra_generate_addr(void) 460 { 461 bool addr_lla = false; 462 463 switch (ra_ifid_mode) { 464 case RA_IFID_EUI64: 465 addr_lla |= !ra_generate_addr_eui64(); 466 break; 467 case RA_IFID_FIXED: 468 /* nothing to do */ 469 break; 470 case RA_IFID_LLA: 471 addr_lla = true; 472 break; 473 case RA_IFID_RANDOM: 474 addr_lla |= !ra_generate_addr_rand(); 475 break; 476 } 477 478 if (addr_lla) 479 ra_generate_addr_ll(); 480 } 481 482 int ra_get_hoplimit(void) 483 { 484 return ra_hoplimit; 485 } 486 487 int ra_get_mtu(void) 488 { 489 return ra_mtu; 490 } 491 492 int ra_get_reachable(void) 493 { 494 return ra_reachable; 495 } 496 497 int ra_get_retransmit(void) 498 { 499 return ra_retransmit; 500 } 501 502 bool ra_process(void) 503 { 504 bool found = false; 505 bool changed = false; 506 uint8_t buf[1500] _o_aligned(4); 507 union { 508 struct cmsghdr hdr; 509 uint8_t buf[CMSG_SPACE(sizeof(int))]; 510 } cmsg_buf; 511 struct nd_router_advert *adv = (struct nd_router_advert*)buf; 512 struct odhcp6c_entry *entry = alloca(sizeof(*entry) + 256); 513 const struct in6_addr any = IN6ADDR_ANY_INIT; 514 515 memset(entry, 0, sizeof(*entry)); 516 517 if (IN6_IS_ADDR_UNSPECIFIED(&ra_addr)) 518 ra_generate_addr(); 519 520 while (true) { 521 struct sockaddr_in6 from; 522 struct iovec iov = {buf, sizeof(buf)}; 523 struct msghdr msg = { 524 .msg_name = (void *) &from, 525 .msg_namelen = sizeof(from), 526 .msg_iov = &iov, 527 .msg_iovlen = 1, 528 .msg_control = cmsg_buf.buf, 529 .msg_controllen = sizeof(cmsg_buf), 530 .msg_flags = 0 531 }; 532 struct icmpv6_opt *opt; 533 uint32_t router_valid; 534 int hlim = 0; 535 536 ssize_t len = recvmsg(sock, &msg, MSG_DONTWAIT); 537 if (len <= 0) 538 break; 539 540 if (IN6_IS_ADDR_UNSPECIFIED(&ra_addr)) 541 continue; 542 543 for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL; 544 ch = CMSG_NXTHDR(&msg, ch)) 545 if (ch->cmsg_level == IPPROTO_IPV6 && 546 ch->cmsg_type == IPV6_HOPLIMIT) 547 memcpy(&hlim, CMSG_DATA(ch), sizeof(hlim)); 548 549 if (!ra_icmpv6_valid(&from, hlim, buf, len)) 550 continue; 551 552 if (!found) { 553 odhcp6c_expire(false); 554 found = true; 555 } 556 557 router_valid = ntohs(adv->nd_ra_router_lifetime); 558 559 /* RFC4861 §6.3.7 560 * Once the host sends a Router Solicitation, and receives a valid 561 * Router Advertisement with a non-zero Router Lifetime, the host MUST 562 * desist from sending additional solicitations on that interface 563 * Moreover, a host SHOULD send at least one solicitation in the case 564 * where an advertisement is received prior to having sent a solicitation. 565 */ 566 if (rs_attempt > 0 && router_valid > 0) { 567 alarm(0); 568 rs_attempt = 0; 569 } 570 571 // Parse default route 572 entry->target = any; 573 entry->length = 0; 574 entry->router = from.sin6_addr; 575 entry->ra_flags = adv->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); 576 entry->priority = pref_to_priority(adv->nd_ra_flags_reserved); 577 if (entry->priority < 0) 578 entry->priority = pref_to_priority(0); 579 580 entry->valid = router_valid; 581 entry->preferred = entry->valid; 582 changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, 583 ra_holdoff_interval); 584 entry->ra_flags = 0; // other STATE_RA_* entries don't have flags 585 586 // Parse hop limit 587 changed |= ra_set_hoplimit(adv->nd_ra_curhoplimit); 588 589 // Parse ND parameters 590 changed |= ra_set_reachable(ntohl(adv->nd_ra_reachable)); 591 changed |= ra_set_retransmit(ntohl(adv->nd_ra_retransmit)); 592 593 // Evaluate options 594 icmpv6_for_each_option(opt, &adv[1], &buf[len]) { 595 if (opt->type == ND_OPT_MTU) { 596 uint32_t *mtu = (uint32_t*)&opt->data[2]; 597 changed |= ra_set_mtu(ntohl(*mtu)); 598 } else if (opt->type == ND_OPT_ROUTE_INFORMATION && opt->len <= 3) { 599 struct icmpv6_opt_route_info *ri = (struct icmpv6_opt_route_info *)opt; 600 601 if (ri->prefix_len > 128) { 602 continue; 603 } else if (ri->prefix_len > 64) { 604 if (ri->len < 2) 605 continue; 606 } else if (ri->prefix_len > 0) { 607 if (ri->len < 1) 608 continue; 609 } 610 611 entry->router = from.sin6_addr; 612 entry->target = any; 613 entry->priority = pref_to_priority(ri->flags); 614 entry->length = ri->prefix_len; 615 entry->valid = ntohl(ri->lifetime); 616 memcpy(&entry->target, ri->prefix, (ri->len - 1) * 8); 617 618 if (IN6_IS_ADDR_LINKLOCAL(&entry->target) 619 || IN6_IS_ADDR_LOOPBACK(&entry->target) 620 || IN6_IS_ADDR_MULTICAST(&entry->target)) 621 continue; 622 623 if (entry->priority > 0) 624 changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, 625 ra_holdoff_interval); 626 } else if (opt->type == ND_OPT_PREFIX_INFORMATION && opt->len == 4) { 627 /* 628 * We implement draft-ietf-6man-slaac-renum-11 here: 629 * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-11#section-5.4 630 * 631 * This removes the two hour magic and instead just uses the new 632 * data. If the lifetime is zero, then the prefix is removed. 633 * 634 * An entry with lifetime zero is added. odhcp6c_expire will remove 635 * it again. odhcp6c_expire is called at the end of this function. 636 */ 637 struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info*)opt; 638 entry->router = any; 639 entry->target = pinfo->nd_opt_pi_prefix; 640 entry->priority = 256; 641 entry->length = pinfo->nd_opt_pi_prefix_len; 642 entry->valid = ntohl(pinfo->nd_opt_pi_valid_time); 643 entry->preferred = ntohl(pinfo->nd_opt_pi_preferred_time); 644 645 if (entry->length > 128 || IN6_IS_ADDR_LINKLOCAL(&entry->target) 646 || IN6_IS_ADDR_LOOPBACK(&entry->target) 647 || IN6_IS_ADDR_MULTICAST(&entry->target) 648 || entry->valid < entry->preferred) 649 continue; 650 651 if ((pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && 652 !ptp_link) 653 changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, 654 ra_holdoff_interval); 655 656 if (!(pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) || 657 pinfo->nd_opt_pi_prefix_len != 64) 658 continue; 659 660 entry->target.s6_addr32[2] = ra_addr.s6_addr32[2]; 661 entry->target.s6_addr32[3] = ra_addr.s6_addr32[3]; 662 663 changed |= odhcp6c_update_entry(STATE_RA_PREFIX, entry, 664 ra_holdoff_interval); 665 } else if (opt->type == ND_OPT_RECURSIVE_DNS && opt->len > 2) { 666 entry->router = from.sin6_addr; 667 entry->priority = 0; 668 entry->length = 128; 669 uint32_t *valid = (uint32_t*)&opt->data[2]; 670 entry->valid = ntohl(*valid); 671 entry->preferred = 0; 672 673 for (ssize_t i = 0; i < (opt->len - 1) / 2; ++i) { 674 memcpy(&entry->target, &opt->data[6 + i * sizeof(entry->target)], 675 sizeof(entry->target)); 676 changed |= odhcp6c_update_entry(STATE_RA_DNS, entry, 677 ra_holdoff_interval); 678 } 679 } else if (opt->type == ND_OPT_DNSSL && opt->len > 1) { 680 uint32_t *valid = (uint32_t*)&opt->data[2]; 681 uint8_t *ds_buf = &opt->data[6]; 682 uint8_t *end = &ds_buf[(opt->len - 1) * 8]; 683 684 entry->router = from.sin6_addr; 685 entry->valid = ntohl(*valid); 686 687 while (ds_buf < end) { 688 int ds_len = dn_expand(ds_buf, end, ds_buf, (char*)entry->auxtarget, 256); 689 if (ds_len < 1) 690 break; 691 692 ds_buf = &ds_buf[ds_len]; 693 entry->auxlen = strlen((char*)entry->auxtarget); 694 695 if (entry->auxlen == 0) 696 continue; 697 698 changed |= odhcp6c_update_entry(STATE_RA_SEARCH, entry, 699 ra_holdoff_interval); 700 entry->auxlen = 0; 701 } 702 } else if (opt->type == ND_OPT_CAPTIVE_PORTAL) { 703 /* RFC8910 Captive-Portal §2.3 */ 704 if (opt->len <= 1) 705 continue; 706 707 struct icmpv6_opt_captive_portal *capt_port = (struct icmpv6_opt_captive_portal*)opt; 708 uint8_t *cp_buf = &capt_port->data[0]; 709 size_t ref_len = sizeof(URN_IETF_CAPT_PORT_UNRESTR) - 1; 710 711 /* RFC8910 §2: 712 * Networks with no captive portals may explicitly indicate this 713 * condition by using this option with the IANA-assigned URI for 714 * this purpose. Clients observing the URI value ... may forego 715 * time-consuming forms of captive portal detection. */ 716 if (memcmp(cp_buf, URN_IETF_CAPT_PORT_UNRESTR, ref_len)) { 717 /* URI are not guaranteed to be \0 terminated if data is unpadded */ 718 size_t uri_len = (capt_port->len * 8) - 2; 719 /* Allocate new buffer including room for '\0' */ 720 uint8_t *copy = malloc(uri_len + 1); 721 if (!copy) 722 continue; 723 724 memcpy(copy, cp_buf, uri_len); 725 copy[uri_len] = '\0'; 726 odhcp6c_clear_state(STATE_CAPT_PORT_RA); 727 odhcp6c_add_state(STATE_CAPT_PORT_RA, copy, uri_len); 728 free(copy); 729 } 730 } 731 } 732 733 if (ra_options & RA_RDNSS_DEFAULT_LIFETIME) { 734 int states[2] = {STATE_RA_DNS, STATE_RA_SEARCH}; 735 736 for (size_t i = 0; i < 2; ++i) { 737 size_t ra_dns_len; 738 uint8_t *start = odhcp6c_get_state(states[i], &ra_dns_len); 739 740 for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; 741 (uint8_t*)c < &start[ra_dns_len] && 742 (uint8_t*)odhcp6c_next_entry(c) <= &start[ra_dns_len]; 743 c = odhcp6c_next_entry(c)) { 744 if (IN6_ARE_ADDR_EQUAL(&c->router, &from.sin6_addr) && 745 c->valid > router_valid) 746 c->valid = router_valid; 747 } 748 } 749 } 750 } 751 752 if (found) 753 odhcp6c_expire(false); 754 755 return found && changed; 756 } 757
This page was automatically generated by LXR 0.3.1. • OpenWrt