18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd - DHCP client daemon 46e63cc1fSRoy Marples * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> 57827cba2SAaron LI * All rights reserved 67827cba2SAaron LI 77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without 87827cba2SAaron LI * modification, are permitted provided that the following conditions 97827cba2SAaron LI * are met: 107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright 117827cba2SAaron LI * notice, this list of conditions and the following disclaimer. 127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright 137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the 147827cba2SAaron LI * documentation and/or other materials provided with the distribution. 157827cba2SAaron LI * 167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 267827cba2SAaron LI * SUCH DAMAGE. 277827cba2SAaron LI */ 287827cba2SAaron LI 297827cba2SAaron LI #include <sys/param.h> 307827cba2SAaron LI #include <sys/types.h> 317827cba2SAaron LI #include <sys/socket.h> 327827cba2SAaron LI #include <sys/stat.h> 337827cba2SAaron LI 348d36e1dfSRoy Marples #include <arpa/inet.h> 357827cba2SAaron LI #include <net/if.h> 367827cba2SAaron LI #include <net/route.h> 377827cba2SAaron LI #include <netinet/in.h> 387827cba2SAaron LI #include <netinet/if_ether.h> 397827cba2SAaron LI 407827cba2SAaron LI #include "config.h" 417827cba2SAaron LI 427827cba2SAaron LI #ifdef HAVE_SYS_BITOPS_H 437827cba2SAaron LI #include <sys/bitops.h> 447827cba2SAaron LI #else 457827cba2SAaron LI #include "compat/bitops.h" 467827cba2SAaron LI #endif 477827cba2SAaron LI 487827cba2SAaron LI #ifdef BSD 497827cba2SAaron LI /* Purely for the ND6_IFF_AUTO_LINKLOCAL #define which is solely used 507827cba2SAaron LI * to generate our CAN_ADD_LLADDR #define. */ 517827cba2SAaron LI # include <netinet6/in6_var.h> 527827cba2SAaron LI # include <netinet6/nd6.h> 537827cba2SAaron LI #endif 547827cba2SAaron LI 557827cba2SAaron LI #include <errno.h> 567827cba2SAaron LI #include <ifaddrs.h> 577827cba2SAaron LI #include <inttypes.h> 587827cba2SAaron LI #include <stdlib.h> 597827cba2SAaron LI #include <string.h> 606e63cc1fSRoy Marples #include <syslog.h> 617827cba2SAaron LI #include <unistd.h> 627827cba2SAaron LI 636e63cc1fSRoy Marples #define ELOOP_QUEUE ELOOP_IPV6 647827cba2SAaron LI #include "common.h" 657827cba2SAaron LI #include "if.h" 667827cba2SAaron LI #include "dhcpcd.h" 677827cba2SAaron LI #include "dhcp6.h" 687827cba2SAaron LI #include "eloop.h" 697827cba2SAaron LI #include "ipv6.h" 707827cba2SAaron LI #include "ipv6nd.h" 717827cba2SAaron LI #include "logerr.h" 72d4fb1e02SRoy Marples #include "privsep.h" 737827cba2SAaron LI #include "sa.h" 747827cba2SAaron LI #include "script.h" 757827cba2SAaron LI 767827cba2SAaron LI #ifdef HAVE_MD5_H 777827cba2SAaron LI # ifndef DEPGEN 787827cba2SAaron LI # include <md5.h> 797827cba2SAaron LI # endif 807827cba2SAaron LI #endif 817827cba2SAaron LI 827827cba2SAaron LI #ifdef SHA2_H 837827cba2SAaron LI # include SHA2_H 847827cba2SAaron LI #endif 857827cba2SAaron LI 867827cba2SAaron LI #ifndef SHA256_DIGEST_LENGTH 877827cba2SAaron LI # define SHA256_DIGEST_LENGTH 32 887827cba2SAaron LI #endif 897827cba2SAaron LI 907827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 917827cba2SAaron LI # warning kernel does not report IPv6 address flag changes 927827cba2SAaron LI # warning polling tentative address flags periodically 937827cba2SAaron LI #endif 947827cba2SAaron LI 957827cba2SAaron LI /* Hackery at it's finest. */ 967827cba2SAaron LI #ifndef s6_addr32 977827cba2SAaron LI # ifdef __sun 987827cba2SAaron LI # define s6_addr32 _S6_un._S6_u32 997827cba2SAaron LI # else 1007827cba2SAaron LI # define s6_addr32 __u6_addr.__u6_addr32 1017827cba2SAaron LI # endif 1027827cba2SAaron LI #endif 1037827cba2SAaron LI 1047827cba2SAaron LI #if defined(HAVE_IN6_ADDR_GEN_MODE_NONE) || defined(ND6_IFF_AUTO_LINKLOCAL) || \ 1057827cba2SAaron LI defined(IFF_NOLINKLOCAL) 1067827cba2SAaron LI /* Only add the LL address if we have a carrier, so DaD works. */ 1077827cba2SAaron LI #define CAN_ADD_LLADDR(ifp) \ 10893ddca5eSRoy Marples (!((ifp)->options->options & DHCPCD_LINK) || if_is_link_up((ifp))) 1097827cba2SAaron LI #ifdef __sun 1107827cba2SAaron LI /* Although we can add our own LL address, we cannot drop it 1117827cba2SAaron LI * without unplumbing the if which is a lot of code. 1127827cba2SAaron LI * So just keep it for the time being. */ 1137827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (0) 1147827cba2SAaron LI #else 1157827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (1) 1167827cba2SAaron LI #endif 1177827cba2SAaron LI #else 1187827cba2SAaron LI /* We have no control over the OS adding the LLADDR, so just let it do it 1197827cba2SAaron LI * as we cannot force our own view on it. */ 1207827cba2SAaron LI #define CAN_ADD_LLADDR(ifp) (0) 1217827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (0) 1227827cba2SAaron LI #endif 1237827cba2SAaron LI 1247827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 1257827cba2SAaron LI static void ipv6_regentempaddr(void *); 1267827cba2SAaron LI #endif 1277827cba2SAaron LI 1287827cba2SAaron LI int 1297827cba2SAaron LI ipv6_init(struct dhcpcd_ctx *ctx) 1307827cba2SAaron LI { 1317827cba2SAaron LI 1328d36e1dfSRoy Marples if (ctx->ra_routers != NULL) 1337827cba2SAaron LI return 0; 1347827cba2SAaron LI 1357827cba2SAaron LI ctx->ra_routers = malloc(sizeof(*ctx->ra_routers)); 1367827cba2SAaron LI if (ctx->ra_routers == NULL) 1377827cba2SAaron LI return -1; 1387827cba2SAaron LI TAILQ_INIT(ctx->ra_routers); 1397827cba2SAaron LI 1408d36e1dfSRoy Marples #ifndef __sun 1417827cba2SAaron LI ctx->nd_fd = -1; 1428d36e1dfSRoy Marples #endif 143d4fb1e02SRoy Marples #ifdef DHCP6 144d4fb1e02SRoy Marples ctx->dhcp6_rfd = -1; 145d4fb1e02SRoy Marples ctx->dhcp6_wfd = -1; 146d4fb1e02SRoy Marples #endif 1477827cba2SAaron LI return 0; 1487827cba2SAaron LI } 1497827cba2SAaron LI 1507827cba2SAaron LI static ssize_t 1517827cba2SAaron LI ipv6_readsecret(struct dhcpcd_ctx *ctx) 1527827cba2SAaron LI { 1537827cba2SAaron LI char line[1024]; 1547827cba2SAaron LI unsigned char *p; 1557827cba2SAaron LI size_t len; 1567827cba2SAaron LI uint32_t r; 1577827cba2SAaron LI 158d4fb1e02SRoy Marples ctx->secret_len = dhcp_read_hwaddr_aton(ctx, &ctx->secret, SECRET); 159d4fb1e02SRoy Marples if (ctx->secret_len != 0) 1607827cba2SAaron LI return (ssize_t)ctx->secret_len; 1617827cba2SAaron LI 1627827cba2SAaron LI if (errno != ENOENT) 163d4fb1e02SRoy Marples logerr("%s: cannot read secret", __func__); 1647827cba2SAaron LI 1657827cba2SAaron LI /* Chaining arc4random should be good enough. 1667827cba2SAaron LI * RFC7217 section 5.1 states the key SHOULD be at least 128 bits. 1677827cba2SAaron LI * To attempt and future proof ourselves, we'll generate a key of 1687827cba2SAaron LI * 512 bits (64 bytes). */ 1697827cba2SAaron LI if (ctx->secret_len < 64) { 1707827cba2SAaron LI if ((ctx->secret = malloc(64)) == NULL) { 1717827cba2SAaron LI logerr(__func__); 1727827cba2SAaron LI return -1; 1737827cba2SAaron LI } 1747827cba2SAaron LI ctx->secret_len = 64; 1757827cba2SAaron LI } 1767827cba2SAaron LI p = ctx->secret; 1777827cba2SAaron LI for (len = 0; len < 512 / NBBY; len += sizeof(r)) { 1787827cba2SAaron LI r = arc4random(); 1797827cba2SAaron LI memcpy(p, &r, sizeof(r)); 1807827cba2SAaron LI p += sizeof(r); 1817827cba2SAaron LI } 1827827cba2SAaron LI 183d4fb1e02SRoy Marples hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line)); 184d4fb1e02SRoy Marples len = strlen(line); 185d4fb1e02SRoy Marples if (len < sizeof(line) - 2) { 186d4fb1e02SRoy Marples line[len++] = '\n'; 187d4fb1e02SRoy Marples line[len] = '\0'; 188d4fb1e02SRoy Marples } 189d4fb1e02SRoy Marples if (dhcp_writefile(ctx, SECRET, S_IRUSR, line, len) == -1) { 190d4fb1e02SRoy Marples logerr("%s: cannot write secret", __func__); 1917827cba2SAaron LI ctx->secret_len = 0; 1927827cba2SAaron LI return -1; 1937827cba2SAaron LI } 194d4fb1e02SRoy Marples return (ssize_t)ctx->secret_len; 195d4fb1e02SRoy Marples } 1967827cba2SAaron LI 1977827cba2SAaron LI /* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml 1987827cba2SAaron LI * RFC5453 */ 1997827cba2SAaron LI static const struct reslowhigh { 2007827cba2SAaron LI const uint8_t high[8]; 2017827cba2SAaron LI const uint8_t low[8]; 2027827cba2SAaron LI } reslowhigh[] = { 2037827cba2SAaron LI /* RFC4291 + RFC6543 */ 2047827cba2SAaron LI { { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 }, 2057827cba2SAaron LI { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } }, 2067827cba2SAaron LI /* RFC2526 */ 2077827cba2SAaron LI { { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }, 2087827cba2SAaron LI { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } 2097827cba2SAaron LI }; 2107827cba2SAaron LI 211280986e4SRoy Marples static bool 2127827cba2SAaron LI ipv6_reserved(const struct in6_addr *addr) 2137827cba2SAaron LI { 2147827cba2SAaron LI uint64_t id, low, high; 2157827cba2SAaron LI size_t i; 2167827cba2SAaron LI const struct reslowhigh *r; 2177827cba2SAaron LI 2187827cba2SAaron LI id = be64dec(addr->s6_addr + sizeof(id)); 2197827cba2SAaron LI if (id == 0) /* RFC4291 */ 2207827cba2SAaron LI return 1; 221280986e4SRoy Marples for (i = 0; i < __arraycount(reslowhigh); i++) { 2227827cba2SAaron LI r = &reslowhigh[i]; 2237827cba2SAaron LI low = be64dec(r->low); 2247827cba2SAaron LI high = be64dec(r->high); 2257827cba2SAaron LI if (id >= low && id <= high) 226280986e4SRoy Marples return true; 2277827cba2SAaron LI } 228280986e4SRoy Marples return false; 2297827cba2SAaron LI } 2307827cba2SAaron LI 2317827cba2SAaron LI /* RFC7217 */ 2327827cba2SAaron LI static int 233280986e4SRoy Marples ipv6_makestableprivate1(struct dhcpcd_ctx *ctx, 234280986e4SRoy Marples struct in6_addr *addr, const struct in6_addr *prefix, int prefix_len, 2357827cba2SAaron LI const unsigned char *netiface, size_t netiface_len, 2367827cba2SAaron LI const unsigned char *netid, size_t netid_len, 2377827cba2SAaron LI unsigned short vlanid, 238280986e4SRoy Marples uint32_t *dad_counter) 2397827cba2SAaron LI { 2407827cba2SAaron LI unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH]; 2417827cba2SAaron LI size_t len, l; 242280986e4SRoy Marples SHA256_CTX sha_ctx; 2437827cba2SAaron LI 2447827cba2SAaron LI if (prefix_len < 0 || prefix_len > 120) { 2457827cba2SAaron LI errno = EINVAL; 2467827cba2SAaron LI return -1; 2477827cba2SAaron LI } 2487827cba2SAaron LI 249280986e4SRoy Marples if (ctx->secret_len == 0) { 250280986e4SRoy Marples if (ipv6_readsecret(ctx) == -1) 251280986e4SRoy Marples return -1; 252280986e4SRoy Marples } 253280986e4SRoy Marples 2547827cba2SAaron LI l = (size_t)(ROUNDUP8(prefix_len) / NBBY); 255280986e4SRoy Marples len = l + netiface_len + netid_len + sizeof(*dad_counter) + 256280986e4SRoy Marples ctx->secret_len; 2577827cba2SAaron LI if (vlanid != 0) 2587827cba2SAaron LI len += sizeof(vlanid); 2597827cba2SAaron LI if (len > sizeof(buf)) { 2607827cba2SAaron LI errno = ENOBUFS; 2617827cba2SAaron LI return -1; 2627827cba2SAaron LI } 2637827cba2SAaron LI 2647827cba2SAaron LI for (;; (*dad_counter)++) { 2657827cba2SAaron LI /* Combine all parameters into one buffer */ 2667827cba2SAaron LI p = buf; 2677827cba2SAaron LI memcpy(p, prefix, l); 2687827cba2SAaron LI p += l; 2697827cba2SAaron LI memcpy(p, netiface, netiface_len); 2707827cba2SAaron LI p += netiface_len; 2717827cba2SAaron LI memcpy(p, netid, netid_len); 2727827cba2SAaron LI p += netid_len; 2737827cba2SAaron LI /* Don't use a vlanid if not set. 2747827cba2SAaron LI * This ensures prior versions have the same unique address. */ 2757827cba2SAaron LI if (vlanid != 0) { 2767827cba2SAaron LI memcpy(p, &vlanid, sizeof(vlanid)); 2777827cba2SAaron LI p += sizeof(vlanid); 2787827cba2SAaron LI } 2797827cba2SAaron LI memcpy(p, dad_counter, sizeof(*dad_counter)); 2807827cba2SAaron LI p += sizeof(*dad_counter); 281280986e4SRoy Marples memcpy(p, ctx->secret, ctx->secret_len); 2827827cba2SAaron LI 2837827cba2SAaron LI /* Make an address using the digest of the above. 2847827cba2SAaron LI * RFC7217 Section 5.1 states that we shouldn't use MD5. 2857827cba2SAaron LI * Pity as we use that for HMAC-MD5 which is still deemed OK. 2867827cba2SAaron LI * SHA-256 is recommended */ 287280986e4SRoy Marples SHA256_Init(&sha_ctx); 288280986e4SRoy Marples SHA256_Update(&sha_ctx, buf, len); 289280986e4SRoy Marples SHA256_Final(digest, &sha_ctx); 2907827cba2SAaron LI 2917827cba2SAaron LI p = addr->s6_addr; 2927827cba2SAaron LI memcpy(p, prefix, l); 2937827cba2SAaron LI /* RFC7217 section 5.2 says we need to start taking the id from 2947827cba2SAaron LI * the least significant bit */ 2957827cba2SAaron LI len = sizeof(addr->s6_addr) - l; 2967827cba2SAaron LI memcpy(p + l, digest + (sizeof(digest) - len), len); 2977827cba2SAaron LI 2987827cba2SAaron LI /* Ensure that the Interface ID does not match a reserved one, 2997827cba2SAaron LI * if it does then treat it as a DAD failure. 3007827cba2SAaron LI * RFC7217 section 5.2 */ 3017827cba2SAaron LI if (prefix_len != 64) 3027827cba2SAaron LI break; 3037827cba2SAaron LI if (!ipv6_reserved(addr)) 3047827cba2SAaron LI break; 3057827cba2SAaron LI } 3067827cba2SAaron LI 3077827cba2SAaron LI return 0; 3087827cba2SAaron LI } 3097827cba2SAaron LI 3107827cba2SAaron LI int 3117827cba2SAaron LI ipv6_makestableprivate(struct in6_addr *addr, 3127827cba2SAaron LI const struct in6_addr *prefix, int prefix_len, 3137827cba2SAaron LI const struct interface *ifp, 3147827cba2SAaron LI int *dad_counter) 3157827cba2SAaron LI { 3167827cba2SAaron LI uint32_t dad; 3177827cba2SAaron LI int r; 3187827cba2SAaron LI 3197827cba2SAaron LI dad = (uint32_t)*dad_counter; 3207827cba2SAaron LI 3217827cba2SAaron LI /* For our implementation, we shall set the hardware address 3227827cba2SAaron LI * as the interface identifier */ 323280986e4SRoy Marples r = ipv6_makestableprivate1(ifp->ctx, addr, prefix, prefix_len, 3247827cba2SAaron LI ifp->hwaddr, ifp->hwlen, 3257827cba2SAaron LI ifp->ssid, ifp->ssid_len, 326280986e4SRoy Marples ifp->vlanid, &dad); 3277827cba2SAaron LI 3287827cba2SAaron LI if (r == 0) 3297827cba2SAaron LI *dad_counter = (int)dad; 3307827cba2SAaron LI return r; 3317827cba2SAaron LI } 3327827cba2SAaron LI 333280986e4SRoy Marples #ifdef IPV6_AF_TEMPORARY 334280986e4SRoy Marples static int 335280986e4SRoy Marples ipv6_maketemporaryaddress(struct in6_addr *addr, 336280986e4SRoy Marples const struct in6_addr *prefix, int prefix_len, 337280986e4SRoy Marples const struct interface *ifp) 338280986e4SRoy Marples { 339280986e4SRoy Marples struct in6_addr mask; 340280986e4SRoy Marples struct interface *ifpn; 341280986e4SRoy Marples 342280986e4SRoy Marples if (ipv6_mask(&mask, prefix_len) == -1) 343280986e4SRoy Marples return -1; 344280986e4SRoy Marples *addr = *prefix; 345280986e4SRoy Marples 346280986e4SRoy Marples again: 347280986e4SRoy Marples addr->s6_addr32[2] |= (arc4random() & ~mask.s6_addr32[2]); 348280986e4SRoy Marples addr->s6_addr32[3] |= (arc4random() & ~mask.s6_addr32[3]); 349280986e4SRoy Marples 350280986e4SRoy Marples TAILQ_FOREACH(ifpn, ifp->ctx->ifaces, next) { 351280986e4SRoy Marples if (ipv6_iffindaddr(ifpn, addr, 0) != NULL) 352280986e4SRoy Marples break; 353280986e4SRoy Marples } 354280986e4SRoy Marples if (ifpn != NULL) 355280986e4SRoy Marples goto again; 356280986e4SRoy Marples if (ipv6_reserved(addr)) 357280986e4SRoy Marples goto again; 358280986e4SRoy Marples return 0; 359280986e4SRoy Marples } 360280986e4SRoy Marples #endif 361280986e4SRoy Marples 3627827cba2SAaron LI int 3637827cba2SAaron LI ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp, 364280986e4SRoy Marples const struct in6_addr *prefix, int prefix_len, unsigned int flags) 3657827cba2SAaron LI { 3667827cba2SAaron LI const struct ipv6_addr *ap; 3677827cba2SAaron LI int dad; 3687827cba2SAaron LI 3697827cba2SAaron LI if (prefix_len < 0 || prefix_len > 120) { 3707827cba2SAaron LI errno = EINVAL; 3717827cba2SAaron LI return -1; 3727827cba2SAaron LI } 3737827cba2SAaron LI 374280986e4SRoy Marples #ifdef IPV6_AF_TEMPORARY 375280986e4SRoy Marples if (flags & IPV6_AF_TEMPORARY) 376280986e4SRoy Marples return ipv6_maketemporaryaddress(addr, prefix, prefix_len, ifp); 377280986e4SRoy Marples #else 378280986e4SRoy Marples UNUSED(flags); 379280986e4SRoy Marples #endif 380280986e4SRoy Marples 3817827cba2SAaron LI if (ifp->options->options & DHCPCD_SLAACPRIVATE) { 3827827cba2SAaron LI dad = 0; 3837827cba2SAaron LI if (ipv6_makestableprivate(addr, 3847827cba2SAaron LI prefix, prefix_len, ifp, &dad) == -1) 3857827cba2SAaron LI return -1; 3867827cba2SAaron LI return dad; 3877827cba2SAaron LI } 3887827cba2SAaron LI 3897827cba2SAaron LI if (prefix_len > 64) { 3907827cba2SAaron LI errno = EINVAL; 3917827cba2SAaron LI return -1; 3927827cba2SAaron LI } 3937827cba2SAaron LI if ((ap = ipv6_linklocal(ifp)) == NULL) { 3947827cba2SAaron LI /* We delay a few functions until we get a local-link address 3957827cba2SAaron LI * so this should never be hit. */ 3967827cba2SAaron LI errno = ENOENT; 3977827cba2SAaron LI return -1; 3987827cba2SAaron LI } 3997827cba2SAaron LI 4007827cba2SAaron LI /* Make the address from the first local-link address */ 4017827cba2SAaron LI memcpy(addr, prefix, sizeof(*prefix)); 4027827cba2SAaron LI addr->s6_addr32[2] = ap->addr.s6_addr32[2]; 4037827cba2SAaron LI addr->s6_addr32[3] = ap->addr.s6_addr32[3]; 4047827cba2SAaron LI return 0; 4057827cba2SAaron LI } 4067827cba2SAaron LI 4077827cba2SAaron LI static int 4087827cba2SAaron LI ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len) 4097827cba2SAaron LI { 4106e63cc1fSRoy Marples struct in6_addr mask; 4116e63cc1fSRoy Marples size_t i; 4127827cba2SAaron LI 4136e63cc1fSRoy Marples if (ipv6_mask(&mask, len) == -1) 4147827cba2SAaron LI return -1; 4156e63cc1fSRoy Marples *prefix = *addr; 4166e63cc1fSRoy Marples for (i = 0; i < sizeof(prefix->s6_addr); i++) 4176e63cc1fSRoy Marples prefix->s6_addr[i] &= mask.s6_addr[i]; 4187827cba2SAaron LI return 0; 4197827cba2SAaron LI } 4207827cba2SAaron LI 4217827cba2SAaron LI int 4227827cba2SAaron LI ipv6_mask(struct in6_addr *mask, int len) 4237827cba2SAaron LI { 4247827cba2SAaron LI static const unsigned char masks[NBBY] = 4257827cba2SAaron LI { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 4267827cba2SAaron LI int bytes, bits, i; 4277827cba2SAaron LI 4287827cba2SAaron LI if (len < 0 || len > 128) { 4297827cba2SAaron LI errno = EINVAL; 4307827cba2SAaron LI return -1; 4317827cba2SAaron LI } 4327827cba2SAaron LI 4337827cba2SAaron LI memset(mask, 0, sizeof(*mask)); 4347827cba2SAaron LI bytes = len / NBBY; 4357827cba2SAaron LI bits = len % NBBY; 4367827cba2SAaron LI for (i = 0; i < bytes; i++) 4377827cba2SAaron LI mask->s6_addr[i] = 0xff; 4387827cba2SAaron LI if (bits != 0) { 4397827cba2SAaron LI /* Coverify false positive. 4407827cba2SAaron LI * bytelen cannot be 16 if bitlen is non zero */ 4417827cba2SAaron LI /* coverity[overrun-local] */ 4427827cba2SAaron LI mask->s6_addr[bytes] = masks[bits - 1]; 4437827cba2SAaron LI } 4447827cba2SAaron LI return 0; 4457827cba2SAaron LI } 4467827cba2SAaron LI 4477827cba2SAaron LI uint8_t 4487827cba2SAaron LI ipv6_prefixlen(const struct in6_addr *mask) 4497827cba2SAaron LI { 4507827cba2SAaron LI int x = 0, y; 4517827cba2SAaron LI const unsigned char *lim, *p; 4527827cba2SAaron LI 4537827cba2SAaron LI lim = (const unsigned char *)mask + sizeof(*mask); 4547827cba2SAaron LI for (p = (const unsigned char *)mask; p < lim; x++, p++) { 4557827cba2SAaron LI if (*p != 0xff) 4567827cba2SAaron LI break; 4577827cba2SAaron LI } 4587827cba2SAaron LI y = 0; 4597827cba2SAaron LI if (p < lim) { 4607827cba2SAaron LI for (y = 0; y < NBBY; y++) { 4617827cba2SAaron LI if ((*p & (0x80 >> y)) == 0) 4627827cba2SAaron LI break; 4637827cba2SAaron LI } 4647827cba2SAaron LI } 4657827cba2SAaron LI 4667827cba2SAaron LI /* 4677827cba2SAaron LI * when the limit pointer is given, do a stricter check on the 4687827cba2SAaron LI * remaining bits. 4697827cba2SAaron LI */ 4707827cba2SAaron LI if (p < lim) { 4717827cba2SAaron LI if (y != 0 && (*p & (0x00ff >> y)) != 0) 4727827cba2SAaron LI return 0; 4737827cba2SAaron LI for (p = p + 1; p < lim; p++) 4747827cba2SAaron LI if (*p != 0) 4757827cba2SAaron LI return 0; 4767827cba2SAaron LI } 4777827cba2SAaron LI 4787827cba2SAaron LI return (uint8_t)(x * NBBY + y); 4797827cba2SAaron LI } 4807827cba2SAaron LI 4817827cba2SAaron LI static void 4827827cba2SAaron LI in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr) 4837827cba2SAaron LI { 4847827cba2SAaron LI 4857827cba2SAaron LI *vhigh = be64dec(addr->s6_addr); 4867827cba2SAaron LI *vlow = be64dec(addr->s6_addr + 8); 4877827cba2SAaron LI } 4887827cba2SAaron LI 4897827cba2SAaron LI static void 4907827cba2SAaron LI h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow) 4917827cba2SAaron LI { 4927827cba2SAaron LI 4937827cba2SAaron LI be64enc(addr->s6_addr, vhigh); 4947827cba2SAaron LI be64enc(addr->s6_addr + 8, vlow); 4957827cba2SAaron LI } 4967827cba2SAaron LI 4977827cba2SAaron LI int 4987827cba2SAaron LI ipv6_userprefix( 4997827cba2SAaron LI const struct in6_addr *prefix, // prefix from router 5007827cba2SAaron LI short prefix_len, // length of prefix received 5017827cba2SAaron LI uint64_t user_number, // "random" number from user 5027827cba2SAaron LI struct in6_addr *result, // resultant prefix 5037827cba2SAaron LI short result_len) // desired prefix length 5047827cba2SAaron LI { 5057827cba2SAaron LI uint64_t vh, vl, user_low, user_high; 5067827cba2SAaron LI 5077827cba2SAaron LI if (prefix_len < 1 || prefix_len > 128 || 5087827cba2SAaron LI result_len < 1 || result_len > 128) 5097827cba2SAaron LI { 5107827cba2SAaron LI errno = EINVAL; 5117827cba2SAaron LI return -1; 5127827cba2SAaron LI } 5137827cba2SAaron LI 5147827cba2SAaron LI /* Check that the user_number fits inside result_len less prefix_len */ 5157827cba2SAaron LI if (result_len < prefix_len || 5167827cba2SAaron LI fls64(user_number) > result_len - prefix_len) 5177827cba2SAaron LI { 5187827cba2SAaron LI errno = ERANGE; 5197827cba2SAaron LI return -1; 5207827cba2SAaron LI } 5217827cba2SAaron LI 5227827cba2SAaron LI /* If user_number is zero, just copy the prefix into the result. */ 5237827cba2SAaron LI if (user_number == 0) { 5247827cba2SAaron LI *result = *prefix; 5257827cba2SAaron LI return 0; 5267827cba2SAaron LI } 5277827cba2SAaron LI 5287827cba2SAaron LI /* Shift user_number so it fit's just inside result_len. 5297827cba2SAaron LI * Shifting by 0 or sizeof(user_number) is undefined, 5307827cba2SAaron LI * so we cater for that. */ 5317827cba2SAaron LI if (result_len == 128) { 5327827cba2SAaron LI user_high = 0; 5337827cba2SAaron LI user_low = user_number; 5347827cba2SAaron LI } else if (result_len > 64) { 5357827cba2SAaron LI if (prefix_len >= 64) 5367827cba2SAaron LI user_high = 0; 5377827cba2SAaron LI else 5387827cba2SAaron LI user_high = user_number >> (result_len - prefix_len); 5397827cba2SAaron LI user_low = user_number << (128 - result_len); 5407827cba2SAaron LI } else if (result_len == 64) { 5417827cba2SAaron LI user_high = user_number; 5427827cba2SAaron LI user_low = 0; 5437827cba2SAaron LI } else { 5447827cba2SAaron LI user_high = user_number << (64 - result_len); 5457827cba2SAaron LI user_low = 0; 5467827cba2SAaron LI } 5477827cba2SAaron LI 5487827cba2SAaron LI /* convert to two 64bit host order values */ 5497827cba2SAaron LI in6_to_h64(&vh, &vl, prefix); 5507827cba2SAaron LI 5517827cba2SAaron LI vh |= user_high; 5527827cba2SAaron LI vl |= user_low; 5537827cba2SAaron LI 5547827cba2SAaron LI /* copy back result */ 5557827cba2SAaron LI h64_to_in6(result, vh, vl); 5567827cba2SAaron LI 5577827cba2SAaron LI return 0; 5587827cba2SAaron LI } 5597827cba2SAaron LI 5607827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 5617827cba2SAaron LI void 5627827cba2SAaron LI ipv6_checkaddrflags(void *arg) 5637827cba2SAaron LI { 5647827cba2SAaron LI struct ipv6_addr *ia; 5657827cba2SAaron LI int flags; 5667827cba2SAaron LI const char *alias; 5677827cba2SAaron LI 5687827cba2SAaron LI ia = arg; 5697827cba2SAaron LI #ifdef ALIAS_ADDR 5707827cba2SAaron LI alias = ia->alias; 5717827cba2SAaron LI #else 5727827cba2SAaron LI alias = NULL; 5737827cba2SAaron LI #endif 5747827cba2SAaron LI if ((flags = if_addrflags6(ia->iface, &ia->addr, alias)) == -1) { 5757827cba2SAaron LI if (errno != EEXIST && errno != EADDRNOTAVAIL) 5767827cba2SAaron LI logerr("%s: if_addrflags6", __func__); 5777827cba2SAaron LI return; 5787827cba2SAaron LI } 5797827cba2SAaron LI 5807827cba2SAaron LI if (!(flags & IN6_IFF_TENTATIVE)) { 5817827cba2SAaron LI /* Simulate the kernel announcing the new address. */ 5827827cba2SAaron LI ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR, 5837827cba2SAaron LI ia->iface->ctx->ifaces, ia->iface->name, 5847827cba2SAaron LI &ia->addr, ia->prefix_len, flags, 0); 5857827cba2SAaron LI } else { 5867827cba2SAaron LI /* Still tentative? Check again in a bit. */ 5876e63cc1fSRoy Marples eloop_timeout_add_msec(ia->iface->ctx->eloop, 5886e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia); 5897827cba2SAaron LI } 5907827cba2SAaron LI } 5917827cba2SAaron LI #endif 5927827cba2SAaron LI 5937827cba2SAaron LI static void 5947827cba2SAaron LI ipv6_deletedaddr(struct ipv6_addr *ia) 5957827cba2SAaron LI { 5967827cba2SAaron LI 597d4fb1e02SRoy Marples #ifdef DHCP6 5986e63cc1fSRoy Marples #ifdef PRIVSEP 5996e63cc1fSRoy Marples if (!(ia->iface->ctx->options & DHCPCD_MASTER)) 6006e63cc1fSRoy Marples ps_inet_closedhcp6(ia); 6016e63cc1fSRoy Marples #elif defined(SMALL) 6027827cba2SAaron LI UNUSED(ia); 6037827cba2SAaron LI #else 6047827cba2SAaron LI /* NOREJECT is set if we delegated exactly the prefix to another 6057827cba2SAaron LI * address. 6067827cba2SAaron LI * This can only be one address, so just clear the flag. 6077827cba2SAaron LI * This should ensure the reject route will be restored. */ 6087827cba2SAaron LI if (ia->delegating_prefix != NULL) 6097827cba2SAaron LI ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT; 6107827cba2SAaron LI #endif 611d4fb1e02SRoy Marples #else 612d4fb1e02SRoy Marples UNUSED(ia); 613d4fb1e02SRoy Marples #endif 6147827cba2SAaron LI } 6157827cba2SAaron LI 6167827cba2SAaron LI void 6177827cba2SAaron LI ipv6_deleteaddr(struct ipv6_addr *ia) 6187827cba2SAaron LI { 6197827cba2SAaron LI struct ipv6_state *state; 6207827cba2SAaron LI struct ipv6_addr *ap; 6217827cba2SAaron LI 6227827cba2SAaron LI loginfox("%s: deleting address %s", ia->iface->name, ia->saddr); 6237827cba2SAaron LI if (if_address6(RTM_DELADDR, ia) == -1 && 6247827cba2SAaron LI errno != EADDRNOTAVAIL && errno != ESRCH && 6257827cba2SAaron LI errno != ENXIO && errno != ENODEV) 6267827cba2SAaron LI logerr(__func__); 6277827cba2SAaron LI 6287827cba2SAaron LI ipv6_deletedaddr(ia); 6297827cba2SAaron LI 6307827cba2SAaron LI state = IPV6_STATE(ia->iface); 6317827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) { 6327827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) { 6337827cba2SAaron LI TAILQ_REMOVE(&state->addrs, ap, next); 6347827cba2SAaron LI ipv6_freeaddr(ap); 6357827cba2SAaron LI break; 6367827cba2SAaron LI } 6377827cba2SAaron LI } 6388d36e1dfSRoy Marples 6398d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 6408d36e1dfSRoy Marples /* Advertise the address if it exists on another interface. */ 6418d36e1dfSRoy Marples ipv6nd_advertise(ia); 6428d36e1dfSRoy Marples #endif 6437827cba2SAaron LI } 6447827cba2SAaron LI 6457827cba2SAaron LI static int 6467827cba2SAaron LI ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now) 6477827cba2SAaron LI { 6487827cba2SAaron LI struct interface *ifp; 6497827cba2SAaron LI uint32_t pltime, vltime; 6506e63cc1fSRoy Marples int loglevel; 6518d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 6528d36e1dfSRoy Marples bool vltime_was_zero = ia->prefix_vltime == 0; 6538d36e1dfSRoy Marples #endif 6548d36e1dfSRoy Marples #ifdef __sun 6558d36e1dfSRoy Marples struct ipv6_state *state; 6568d36e1dfSRoy Marples struct ipv6_addr *ia2; 6577827cba2SAaron LI 6588d36e1dfSRoy Marples /* If we re-add then address on Solaris then the prefix 6598d36e1dfSRoy Marples * route will be scrubbed and re-added. Something might 6608d36e1dfSRoy Marples * be using it, so let's avoid it. */ 6618d36e1dfSRoy Marples if (ia->flags & IPV6_AF_DADCOMPLETED) { 6628d36e1dfSRoy Marples logdebugx("%s: IP address %s already exists", 6638d36e1dfSRoy Marples ia->iface->name, ia->saddr); 6648d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 6658d36e1dfSRoy Marples goto advertise; 6668d36e1dfSRoy Marples #else 6678d36e1dfSRoy Marples return 0; 6688d36e1dfSRoy Marples #endif 6697827cba2SAaron LI } 6708d36e1dfSRoy Marples #endif 6717827cba2SAaron LI 6727827cba2SAaron LI /* Remember the interface of the address. */ 6737827cba2SAaron LI ifp = ia->iface; 6747827cba2SAaron LI 6757827cba2SAaron LI if (!(ia->flags & IPV6_AF_DADCOMPLETED) && 6767827cba2SAaron LI ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE)) 6777827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED; 6787827cba2SAaron LI 6797827cba2SAaron LI /* Adjust plftime and vltime based on acquired time */ 6807827cba2SAaron LI pltime = ia->prefix_pltime; 6817827cba2SAaron LI vltime = ia->prefix_vltime; 682b8b69544SRoy Marples 683b8b69544SRoy Marples if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { 684b8b69544SRoy Marples /* We don't want the kernel to expire the address. 685b8b69544SRoy Marples * The saved times will be re-applied to the ia 686b8b69544SRoy Marples * before exiting this function. */ 687b8b69544SRoy Marples ia->prefix_vltime = ia->prefix_pltime = ND6_INFINITE_LIFETIME; 688b8b69544SRoy Marples } 689b8b69544SRoy Marples 6907827cba2SAaron LI if (timespecisset(&ia->acquired) && 6917827cba2SAaron LI (ia->prefix_pltime != ND6_INFINITE_LIFETIME || 6927827cba2SAaron LI ia->prefix_vltime != ND6_INFINITE_LIFETIME)) 6937827cba2SAaron LI { 6946e63cc1fSRoy Marples uint32_t elapsed; 6957827cba2SAaron LI struct timespec n; 6967827cba2SAaron LI 6977827cba2SAaron LI if (now == NULL) { 6987827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &n); 6997827cba2SAaron LI now = &n; 7007827cba2SAaron LI } 7016e63cc1fSRoy Marples elapsed = (uint32_t)eloop_timespec_diff(now, &ia->acquired, 7026e63cc1fSRoy Marples NULL); 7037827cba2SAaron LI if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) { 7046e63cc1fSRoy Marples if (elapsed > ia->prefix_pltime) 7057827cba2SAaron LI ia->prefix_pltime = 0; 7066e63cc1fSRoy Marples else 7076e63cc1fSRoy Marples ia->prefix_pltime -= elapsed; 7087827cba2SAaron LI } 7097827cba2SAaron LI if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) { 7106e63cc1fSRoy Marples if (elapsed > ia->prefix_vltime) 7116e63cc1fSRoy Marples ia->prefix_vltime = 0; 7126e63cc1fSRoy Marples else 7136e63cc1fSRoy Marples ia->prefix_vltime -= elapsed; 7147827cba2SAaron LI } 7157827cba2SAaron LI } 7167827cba2SAaron LI 7176e63cc1fSRoy Marples loglevel = ia->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG; 7186e63cc1fSRoy Marples logmessage(loglevel, "%s: adding %saddress %s", ifp->name, 7197827cba2SAaron LI #ifdef IPV6_AF_TEMPORARY 7207827cba2SAaron LI ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "", 7217827cba2SAaron LI #else 7227827cba2SAaron LI "", 7237827cba2SAaron LI #endif 7247827cba2SAaron LI ia->saddr); 7257827cba2SAaron LI if (ia->prefix_pltime == ND6_INFINITE_LIFETIME && 7267827cba2SAaron LI ia->prefix_vltime == ND6_INFINITE_LIFETIME) 7277827cba2SAaron LI logdebugx("%s: pltime infinity, vltime infinity", 7287827cba2SAaron LI ifp->name); 7297827cba2SAaron LI else if (ia->prefix_pltime == ND6_INFINITE_LIFETIME) 7307827cba2SAaron LI logdebugx("%s: pltime infinity, vltime %"PRIu32" seconds", 7317827cba2SAaron LI ifp->name, ia->prefix_vltime); 7327827cba2SAaron LI else if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) 7337827cba2SAaron LI logdebugx("%s: pltime %"PRIu32"seconds, vltime infinity", 7347827cba2SAaron LI ifp->name, ia->prefix_pltime); 7357827cba2SAaron LI else 7367827cba2SAaron LI logdebugx("%s: pltime %"PRIu32" seconds, vltime %"PRIu32 7377827cba2SAaron LI " seconds", 7387827cba2SAaron LI ifp->name, ia->prefix_pltime, ia->prefix_vltime); 7397827cba2SAaron LI 7407827cba2SAaron LI if (if_address6(RTM_NEWADDR, ia) == -1) { 7417827cba2SAaron LI logerr(__func__); 7427827cba2SAaron LI /* Restore real pltime and vltime */ 7437827cba2SAaron LI ia->prefix_pltime = pltime; 7447827cba2SAaron LI ia->prefix_vltime = vltime; 7457827cba2SAaron LI return -1; 7467827cba2SAaron LI } 7477827cba2SAaron LI 7487827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 7497827cba2SAaron LI /* RFC4941 Section 3.4 */ 7507827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY && 7517827cba2SAaron LI ia->prefix_pltime && 7527827cba2SAaron LI ia->prefix_vltime && 7537a0236bfSRoy Marples ifp->options->options & DHCPCD_SLAACTEMP) 7547827cba2SAaron LI eloop_timeout_add_sec(ifp->ctx->eloop, 7556e63cc1fSRoy Marples ia->prefix_pltime - REGEN_ADVANCE, 7567827cba2SAaron LI ipv6_regentempaddr, ia); 7577827cba2SAaron LI #endif 7587827cba2SAaron LI 7597827cba2SAaron LI /* Restore real pltime and vltime */ 7607827cba2SAaron LI ia->prefix_pltime = pltime; 7617827cba2SAaron LI ia->prefix_vltime = vltime; 7627827cba2SAaron LI 7637827cba2SAaron LI ia->flags &= ~IPV6_AF_NEW; 7647827cba2SAaron LI ia->flags |= IPV6_AF_ADDED; 7657827cba2SAaron LI #ifndef SMALL 7667827cba2SAaron LI if (ia->delegating_prefix != NULL) 7677827cba2SAaron LI ia->flags |= IPV6_AF_DELEGATED; 7687827cba2SAaron LI #endif 7697827cba2SAaron LI 7707827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 7717827cba2SAaron LI eloop_timeout_delete(ifp->ctx->eloop, 7727827cba2SAaron LI ipv6_checkaddrflags, ia); 7737827cba2SAaron LI if (!(ia->flags & IPV6_AF_DADCOMPLETED)) { 7746e63cc1fSRoy Marples eloop_timeout_add_msec(ifp->ctx->eloop, 7756e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia); 7767827cba2SAaron LI } 7777827cba2SAaron LI #endif 7787827cba2SAaron LI 7797827cba2SAaron LI #ifdef __sun 7807827cba2SAaron LI /* Solaris does not announce new addresses which need DaD 7817827cba2SAaron LI * so we need to take a copy and add it to our list. 7827827cba2SAaron LI * Otherwise aliasing gets confused if we add another 7837827cba2SAaron LI * address during DaD. */ 7847827cba2SAaron LI 7857827cba2SAaron LI state = IPV6_STATE(ifp); 7867827cba2SAaron LI TAILQ_FOREACH(ia2, &state->addrs, next) { 7877827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr)) 7887827cba2SAaron LI break; 7897827cba2SAaron LI } 7907827cba2SAaron LI if (ia2 == NULL) { 7917827cba2SAaron LI if ((ia2 = malloc(sizeof(*ia2))) == NULL) { 7927827cba2SAaron LI logerr(__func__); 7937827cba2SAaron LI return 0; /* Well, we did add the address */ 7947827cba2SAaron LI } 7957827cba2SAaron LI memcpy(ia2, ia, sizeof(*ia2)); 7967827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia2, next); 7977827cba2SAaron LI } 7987827cba2SAaron LI #endif 7997827cba2SAaron LI 8008d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 8018d36e1dfSRoy Marples #ifdef __sun 8028d36e1dfSRoy Marples advertise: 8038d36e1dfSRoy Marples #endif 8048d36e1dfSRoy Marples /* Re-advertise the preferred address to be safe. */ 8058d36e1dfSRoy Marples if (!vltime_was_zero) 8068d36e1dfSRoy Marples ipv6nd_advertise(ia); 8078d36e1dfSRoy Marples #endif 8088d36e1dfSRoy Marples 8097827cba2SAaron LI return 0; 8107827cba2SAaron LI } 8117827cba2SAaron LI 8127827cba2SAaron LI #ifdef ALIAS_ADDR 8138d36e1dfSRoy Marples /* Find the next logical alias address we can use. */ 8147827cba2SAaron LI static int 8157827cba2SAaron LI ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl) 8167827cba2SAaron LI { 8177827cba2SAaron LI struct ipv6_state *state; 8187827cba2SAaron LI struct ipv6_addr *iap; 8198d36e1dfSRoy Marples unsigned int lun; 8207827cba2SAaron LI char alias[IF_NAMESIZE]; 8217827cba2SAaron LI 8227827cba2SAaron LI if (ia->alias[0] != '\0') 8237827cba2SAaron LI return 0; 8247827cba2SAaron LI state = IPV6_STATE(ia->iface); 8257827cba2SAaron LI 8267827cba2SAaron LI /* First find an existng address. 8277827cba2SAaron LI * This can happen when dhcpcd restarts as ND and DHCPv6 8287827cba2SAaron LI * maintain their own lists of addresses. */ 8297827cba2SAaron LI TAILQ_FOREACH(iap, &state->addrs, next) { 8307827cba2SAaron LI if (iap->alias[0] != '\0' && 8317827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr)) 8327827cba2SAaron LI { 8337827cba2SAaron LI strlcpy(ia->alias, iap->alias, sizeof(ia->alias)); 8347827cba2SAaron LI return 0; 8357827cba2SAaron LI } 8367827cba2SAaron LI } 8377827cba2SAaron LI 8388d36e1dfSRoy Marples lun = 0; 8397827cba2SAaron LI find_unit: 8408d36e1dfSRoy Marples if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >= 8418d36e1dfSRoy Marples IF_NAMESIZE) 8428d36e1dfSRoy Marples { 8438d36e1dfSRoy Marples errno = ENOMEM; 8448d36e1dfSRoy Marples return -1; 8458d36e1dfSRoy Marples } 8467827cba2SAaron LI TAILQ_FOREACH(iap, &state->addrs, next) { 8477827cba2SAaron LI if (iap->alias[0] == '\0') 8487827cba2SAaron LI continue; 8497827cba2SAaron LI if (IN6_IS_ADDR_UNSPECIFIED(&iap->addr)) { 8507827cba2SAaron LI /* No address assigned? Lets use it. */ 8517827cba2SAaron LI strlcpy(ia->alias, iap->alias, sizeof(ia->alias)); 8527827cba2SAaron LI if (repl) 8537827cba2SAaron LI *repl = iap; 8547827cba2SAaron LI return 1; 8557827cba2SAaron LI } 8567827cba2SAaron LI if (strcmp(iap->alias, alias) == 0) 8577827cba2SAaron LI break; 8587827cba2SAaron LI } 8597827cba2SAaron LI 8607827cba2SAaron LI if (iap != NULL) { 8618d36e1dfSRoy Marples if (lun == UINT_MAX) { 8627827cba2SAaron LI errno = ERANGE; 8637827cba2SAaron LI return -1; 8647827cba2SAaron LI } 8658d36e1dfSRoy Marples lun++; 8667827cba2SAaron LI goto find_unit; 8677827cba2SAaron LI } 8687827cba2SAaron LI 8697827cba2SAaron LI strlcpy(ia->alias, alias, sizeof(ia->alias)); 8707827cba2SAaron LI return 0; 8717827cba2SAaron LI } 8727827cba2SAaron LI #endif 8737827cba2SAaron LI 8747827cba2SAaron LI int 8757827cba2SAaron LI ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now) 8767827cba2SAaron LI { 8777827cba2SAaron LI int r; 8787827cba2SAaron LI #ifdef ALIAS_ADDR 8797827cba2SAaron LI int replaced, blank; 8807827cba2SAaron LI struct ipv6_addr *replaced_ia; 8817827cba2SAaron LI 8827827cba2SAaron LI blank = (ia->alias[0] == '\0'); 8837827cba2SAaron LI if ((replaced = ipv6_aliasaddr(ia, &replaced_ia)) == -1) 8847827cba2SAaron LI return -1; 8857827cba2SAaron LI if (blank) 8867827cba2SAaron LI logdebugx("%s: aliased %s", ia->alias, ia->saddr); 8877827cba2SAaron LI #endif 8887827cba2SAaron LI 8897827cba2SAaron LI if ((r = ipv6_addaddr1(ia, now)) == 0) { 8907827cba2SAaron LI #ifdef ALIAS_ADDR 8917827cba2SAaron LI if (replaced) { 8927827cba2SAaron LI struct ipv6_state *state; 8937827cba2SAaron LI 8947827cba2SAaron LI state = IPV6_STATE(ia->iface); 8957827cba2SAaron LI TAILQ_REMOVE(&state->addrs, replaced_ia, next); 8967827cba2SAaron LI ipv6_freeaddr(replaced_ia); 8977827cba2SAaron LI } 8987827cba2SAaron LI #endif 8997827cba2SAaron LI } 9007827cba2SAaron LI return r; 9017827cba2SAaron LI } 9027827cba2SAaron LI 9037827cba2SAaron LI int 9047827cba2SAaron LI ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match, 9057827cba2SAaron LI unsigned int flags) 9067827cba2SAaron LI { 9077827cba2SAaron LI 9087827cba2SAaron LI if (match == NULL) { 9097827cba2SAaron LI if ((addr->flags & 9107827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) == 9117827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) 9127827cba2SAaron LI return 1; 9137827cba2SAaron LI } else if (addr->prefix_vltime && 9147827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&addr->addr, match) && 9157827cba2SAaron LI (!flags || addr->flags & flags)) 9167827cba2SAaron LI return 1; 9177827cba2SAaron LI 9187827cba2SAaron LI return 0; 9197827cba2SAaron LI } 9207827cba2SAaron LI 9217827cba2SAaron LI struct ipv6_addr * 9227827cba2SAaron LI ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags) 9237827cba2SAaron LI { 9248d36e1dfSRoy Marples struct ipv6_addr *nap; 9258d36e1dfSRoy Marples #ifdef DHCP6 9268d36e1dfSRoy Marples struct ipv6_addr *dap; 9278d36e1dfSRoy Marples #endif 9287827cba2SAaron LI 9297827cba2SAaron LI nap = ipv6nd_findaddr(ctx, addr, flags); 9308d36e1dfSRoy Marples #ifdef DHCP6 9318d36e1dfSRoy Marples dap = dhcp6_findaddr(ctx, addr, flags); 9327827cba2SAaron LI if (!dap && !nap) 9337827cba2SAaron LI return NULL; 9347827cba2SAaron LI if (dap && !nap) 9357827cba2SAaron LI return dap; 9367827cba2SAaron LI if (nap && !dap) 9377827cba2SAaron LI return nap; 9387827cba2SAaron LI if (nap->iface->metric < dap->iface->metric) 9397827cba2SAaron LI return nap; 9407827cba2SAaron LI return dap; 9418d36e1dfSRoy Marples #else 9428d36e1dfSRoy Marples return nap; 9438d36e1dfSRoy Marples #endif 9447827cba2SAaron LI } 9457827cba2SAaron LI 946ce6cc02eSRoy Marples int 947ce6cc02eSRoy Marples ipv6_doaddr(struct ipv6_addr *ia, struct timespec *now) 9487827cba2SAaron LI { 949ce6cc02eSRoy Marples 950ce6cc02eSRoy Marples /* A delegated prefix is not an address. */ 951ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_DELEGATEDPFX) 952ce6cc02eSRoy Marples return 0; 953ce6cc02eSRoy Marples 954ce6cc02eSRoy Marples if (ia->prefix_vltime == 0) { 955ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_ADDED) 956ce6cc02eSRoy Marples ipv6_deleteaddr(ia); 957ce6cc02eSRoy Marples eloop_q_timeout_delete(ia->iface->ctx->eloop, 9586e63cc1fSRoy Marples ELOOP_QUEUE_ALL, NULL, ia); 959ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_REQUEST) { 960ce6cc02eSRoy Marples ia->flags &= ~IPV6_AF_ADDED; 961ce6cc02eSRoy Marples return 0; 962ce6cc02eSRoy Marples } 963ce6cc02eSRoy Marples return -1; 964ce6cc02eSRoy Marples } 965ce6cc02eSRoy Marples 966ce6cc02eSRoy Marples if (ia->flags & IPV6_AF_STALE || 967ce6cc02eSRoy Marples IN6_IS_ADDR_UNSPECIFIED(&ia->addr)) 968ce6cc02eSRoy Marples return 0; 969ce6cc02eSRoy Marples 970ce6cc02eSRoy Marples if (!timespecisset(now)) 971ce6cc02eSRoy Marples clock_gettime(CLOCK_MONOTONIC, now); 972ce6cc02eSRoy Marples ipv6_addaddr(ia, now); 973ce6cc02eSRoy Marples return ia->flags & IPV6_AF_NEW ? 1 : 0; 974ce6cc02eSRoy Marples } 975ce6cc02eSRoy Marples 976ce6cc02eSRoy Marples ssize_t 977ce6cc02eSRoy Marples ipv6_addaddrs(struct ipv6_addrhead *iaddrs) 978ce6cc02eSRoy Marples { 9797827cba2SAaron LI struct timespec now; 980ce6cc02eSRoy Marples struct ipv6_addr *ia, *ian; 981ce6cc02eSRoy Marples ssize_t i, r; 9827827cba2SAaron LI 9837827cba2SAaron LI i = 0; 9847827cba2SAaron LI timespecclear(&now); 985ce6cc02eSRoy Marples TAILQ_FOREACH_SAFE(ia, iaddrs, next, ian) { 986ce6cc02eSRoy Marples r = ipv6_doaddr(ia, &now); 987ce6cc02eSRoy Marples if (r != 0) 9887827cba2SAaron LI i++; 989ce6cc02eSRoy Marples if (r == -1) { 990ce6cc02eSRoy Marples TAILQ_REMOVE(iaddrs, ia, next); 991ce6cc02eSRoy Marples ipv6_freeaddr(ia); 9927827cba2SAaron LI } 9937827cba2SAaron LI } 9947827cba2SAaron LI return i; 9957827cba2SAaron LI } 9967827cba2SAaron LI 9977827cba2SAaron LI void 9987827cba2SAaron LI ipv6_freeaddr(struct ipv6_addr *ia) 9997827cba2SAaron LI { 10006e63cc1fSRoy Marples struct eloop *eloop = ia->iface->ctx->eloop; 10017827cba2SAaron LI #ifndef SMALL 10027827cba2SAaron LI struct ipv6_addr *iad; 10037827cba2SAaron LI 10047827cba2SAaron LI /* Forget the reference */ 10057827cba2SAaron LI if (ia->flags & IPV6_AF_DELEGATEDPFX) { 10067827cba2SAaron LI TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) { 10077827cba2SAaron LI iad->delegating_prefix = NULL; 10087827cba2SAaron LI } 10097827cba2SAaron LI } else if (ia->delegating_prefix != NULL) { 10107827cba2SAaron LI TAILQ_REMOVE(&ia->delegating_prefix->pd_pfxs, ia, pd_next); 10117827cba2SAaron LI } 10127827cba2SAaron LI #endif 10137827cba2SAaron LI 10147827cba2SAaron LI if (ia->dhcp6_fd != -1) { 10157827cba2SAaron LI close(ia->dhcp6_fd); 10166e63cc1fSRoy Marples eloop_event_delete(eloop, ia->dhcp6_fd); 10177827cba2SAaron LI } 10187827cba2SAaron LI 10196e63cc1fSRoy Marples eloop_q_timeout_delete(eloop, ELOOP_QUEUE_ALL, NULL, ia); 10208d36e1dfSRoy Marples free(ia->na); 10217827cba2SAaron LI free(ia); 10227827cba2SAaron LI } 10237827cba2SAaron LI 10247827cba2SAaron LI void 10257827cba2SAaron LI ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop, 10267827cba2SAaron LI const struct interface *ifd) 10277827cba2SAaron LI { 10287827cba2SAaron LI struct ipv6_addr *ap, *apn, *apf; 10297827cba2SAaron LI struct timespec now; 10307827cba2SAaron LI 10317827cba2SAaron LI #ifdef SMALL 10327827cba2SAaron LI UNUSED(ifd); 10337827cba2SAaron LI #endif 10347827cba2SAaron LI timespecclear(&now); 10357827cba2SAaron LI TAILQ_FOREACH_SAFE(ap, addrs, next, apn) { 10367827cba2SAaron LI #ifndef SMALL 10377827cba2SAaron LI if (ifd != NULL && 10387827cba2SAaron LI (ap->delegating_prefix == NULL || 10397827cba2SAaron LI ap->delegating_prefix->iface != ifd)) 10407827cba2SAaron LI continue; 10417827cba2SAaron LI #endif 10427827cba2SAaron LI if (drop != 2) 10437827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next); 10447827cba2SAaron LI if (drop && ap->flags & IPV6_AF_ADDED && 10457827cba2SAaron LI (ap->iface->options->options & 10467827cba2SAaron LI (DHCPCD_EXITING | DHCPCD_PERSISTENT)) != 10477827cba2SAaron LI (DHCPCD_EXITING | DHCPCD_PERSISTENT)) 10487827cba2SAaron LI { 10497827cba2SAaron LI /* Don't drop link-local addresses. */ 10507827cba2SAaron LI if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr) || 10517827cba2SAaron LI CAN_DROP_LLADDR(ap->iface)) 10527827cba2SAaron LI { 10537827cba2SAaron LI if (drop == 2) 10547827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next); 10557827cba2SAaron LI /* Find the same address somewhere else */ 10567827cba2SAaron LI apf = ipv6_findaddr(ap->iface->ctx, &ap->addr, 10577827cba2SAaron LI 0); 10587827cba2SAaron LI if ((apf == NULL || 10597827cba2SAaron LI (apf->iface != ap->iface))) 10607827cba2SAaron LI ipv6_deleteaddr(ap); 10617827cba2SAaron LI if (!(ap->iface->options->options & 10627827cba2SAaron LI DHCPCD_EXITING) && apf) 10637827cba2SAaron LI { 10647827cba2SAaron LI if (!timespecisset(&now)) 10657827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, 10667827cba2SAaron LI &now); 10677827cba2SAaron LI ipv6_addaddr(apf, &now); 10687827cba2SAaron LI } 10697827cba2SAaron LI if (drop == 2) 10707827cba2SAaron LI ipv6_freeaddr(ap); 10717827cba2SAaron LI } 10727827cba2SAaron LI } 10737827cba2SAaron LI if (drop != 2) 10747827cba2SAaron LI ipv6_freeaddr(ap); 10757827cba2SAaron LI } 10767827cba2SAaron LI } 10777827cba2SAaron LI 10787827cba2SAaron LI static struct ipv6_state * 10797827cba2SAaron LI ipv6_getstate(struct interface *ifp) 10807827cba2SAaron LI { 10817827cba2SAaron LI struct ipv6_state *state; 10827827cba2SAaron LI 10837827cba2SAaron LI state = IPV6_STATE(ifp); 10847827cba2SAaron LI if (state == NULL) { 10857827cba2SAaron LI ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state)); 10867827cba2SAaron LI state = IPV6_STATE(ifp); 10877827cba2SAaron LI if (state == NULL) { 10887827cba2SAaron LI logerr(__func__); 10897827cba2SAaron LI return NULL; 10907827cba2SAaron LI } 10917827cba2SAaron LI TAILQ_INIT(&state->addrs); 10927827cba2SAaron LI TAILQ_INIT(&state->ll_callbacks); 10937827cba2SAaron LI } 10947827cba2SAaron LI return state; 10957827cba2SAaron LI } 10967827cba2SAaron LI 10978d36e1dfSRoy Marples struct ipv6_addr * 109812af092aSRoy Marples ipv6_anyglobal(struct interface *sifp) 10998d36e1dfSRoy Marples { 110012af092aSRoy Marples struct interface *ifp; 11018d36e1dfSRoy Marples struct ipv6_state *state; 11028d36e1dfSRoy Marples struct ipv6_addr *ia; 1103d4fb1e02SRoy Marples bool forwarding; 1104d4fb1e02SRoy Marples 1105b8b69544SRoy Marples /* BSD forwarding is either on or off. 1106b8b69544SRoy Marples * Linux forwarding is technically the same as it's 1107b8b69544SRoy Marples * configured by the "all" interface. 1108b8b69544SRoy Marples * Per interface only affects IsRouter of NA messages. */ 1109b8b69544SRoy Marples #if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__)) 1110d4fb1e02SRoy Marples if (IN_PRIVSEP(sifp->ctx)) 1111b8b69544SRoy Marples forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0; 1112d4fb1e02SRoy Marples else 1113d4fb1e02SRoy Marples #endif 1114b8b69544SRoy Marples forwarding = ip6_forwarding(NULL) != 0; 11158d36e1dfSRoy Marples 111612af092aSRoy Marples TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) { 1117d4fb1e02SRoy Marples if (ifp != sifp && !forwarding) 1118d4fb1e02SRoy Marples continue; 11198d36e1dfSRoy Marples 11208d36e1dfSRoy Marples state = IPV6_STATE(ifp); 11218d36e1dfSRoy Marples if (state == NULL) 112212af092aSRoy Marples continue; 11238d36e1dfSRoy Marples 11248d36e1dfSRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) { 11258d36e1dfSRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&ia->addr)) 11268d36e1dfSRoy Marples continue; 11278d36e1dfSRoy Marples /* Let's be optimistic. 11288d36e1dfSRoy Marples * Any decent OS won't forward or accept traffic 11298d36e1dfSRoy Marples * from/to tentative or detached addresses. */ 11308d36e1dfSRoy Marples if (!(ia->addr_flags & IN6_IFF_DUPLICATED)) 11318d36e1dfSRoy Marples return ia; 11328d36e1dfSRoy Marples } 113312af092aSRoy Marples } 113412af092aSRoy Marples return NULL; 113512af092aSRoy Marples } 11368d36e1dfSRoy Marples 11377827cba2SAaron LI void 11387827cba2SAaron LI ipv6_handleifa(struct dhcpcd_ctx *ctx, 11397827cba2SAaron LI int cmd, struct if_head *ifs, const char *ifname, 11407827cba2SAaron LI const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid) 11417827cba2SAaron LI { 11427827cba2SAaron LI struct interface *ifp; 11437827cba2SAaron LI struct ipv6_state *state; 11447827cba2SAaron LI struct ipv6_addr *ia; 11457827cba2SAaron LI struct ll_callback *cb; 11468d36e1dfSRoy Marples bool anyglobal; 11478d36e1dfSRoy Marples 11488d36e1dfSRoy Marples #ifdef __sun 11498d36e1dfSRoy Marples struct sockaddr_in6 subnet; 11508d36e1dfSRoy Marples 11518d36e1dfSRoy Marples /* Solaris on-link route is an unspecified address! */ 11528d36e1dfSRoy Marples if (IN6_IS_ADDR_UNSPECIFIED(addr)) { 11538d36e1dfSRoy Marples if (if_getsubnet(ctx, ifname, AF_INET6, 11548d36e1dfSRoy Marples &subnet, sizeof(subnet)) == -1) 11558d36e1dfSRoy Marples { 11568d36e1dfSRoy Marples logerr(__func__); 11578d36e1dfSRoy Marples return; 11588d36e1dfSRoy Marples } 11598d36e1dfSRoy Marples addr = &subnet.sin6_addr; 11608d36e1dfSRoy Marples } 11618d36e1dfSRoy Marples #endif 11627827cba2SAaron LI 11637827cba2SAaron LI #if 0 11647827cba2SAaron LI char dbuf[INET6_ADDRSTRLEN]; 11657827cba2SAaron LI const char *dbp; 11667827cba2SAaron LI 11677827cba2SAaron LI dbp = inet_ntop(AF_INET6, &addr->s6_addr, 11687827cba2SAaron LI dbuf, INET6_ADDRSTRLEN); 11698d36e1dfSRoy Marples loginfox("%s: cmd %d addr %s addrflags %d", 11708d36e1dfSRoy Marples ifname, cmd, dbp, addrflags); 11717827cba2SAaron LI #endif 11727827cba2SAaron LI 11737827cba2SAaron LI if (ifs == NULL) 11747827cba2SAaron LI ifs = ctx->ifaces; 11757827cba2SAaron LI if (ifs == NULL) 11767827cba2SAaron LI return; 11777827cba2SAaron LI if ((ifp = if_find(ifs, ifname)) == NULL) 11787827cba2SAaron LI return; 11797827cba2SAaron LI if ((state = ipv6_getstate(ifp)) == NULL) 11807827cba2SAaron LI return; 118112af092aSRoy Marples anyglobal = ipv6_anyglobal(ifp) != NULL; 11827827cba2SAaron LI 11837827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 11847827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr)) 11857827cba2SAaron LI break; 11867827cba2SAaron LI } 11877827cba2SAaron LI 11887827cba2SAaron LI switch (cmd) { 11897827cba2SAaron LI case RTM_DELADDR: 11907827cba2SAaron LI if (ia != NULL) { 11917827cba2SAaron LI TAILQ_REMOVE(&state->addrs, ia, next); 11928d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 11938d36e1dfSRoy Marples /* Advertise the address if it exists on 11948d36e1dfSRoy Marples * another interface. */ 11958d36e1dfSRoy Marples ipv6nd_advertise(ia); 11968d36e1dfSRoy Marples #endif 11977827cba2SAaron LI /* We'll free it at the end of the function. */ 11987827cba2SAaron LI } 11997827cba2SAaron LI break; 12007827cba2SAaron LI case RTM_NEWADDR: 12017827cba2SAaron LI if (ia == NULL) { 12027827cba2SAaron LI ia = ipv6_newaddr(ifp, addr, prefix_len, 0); 12037827cba2SAaron LI #ifdef ALIAS_ADDR 12047827cba2SAaron LI strlcpy(ia->alias, ifname, sizeof(ia->alias)); 12057827cba2SAaron LI #endif 12067827cba2SAaron LI if (if_getlifetime6(ia) == -1) { 12077827cba2SAaron LI /* No support or address vanished. 12087827cba2SAaron LI * Either way, just set a deprecated 12097827cba2SAaron LI * infinite time lifetime and continue. 12107827cba2SAaron LI * This is fine because we only want 12117827cba2SAaron LI * to know this when trying to extend 12127827cba2SAaron LI * temporary addresses. 12137827cba2SAaron LI * As we can't extend infinite, we'll 12147827cba2SAaron LI * create a new temporary address. */ 12157827cba2SAaron LI ia->prefix_pltime = 0; 12167827cba2SAaron LI ia->prefix_vltime = 12177827cba2SAaron LI ND6_INFINITE_LIFETIME; 12187827cba2SAaron LI } 12197827cba2SAaron LI /* This is a minor regression against RFC 4941 12207827cba2SAaron LI * because the kernel only knows when the 12217827cba2SAaron LI * lifetimes were last updated, not when the 12227827cba2SAaron LI * address was initially created. 12237827cba2SAaron LI * Provided dhcpcd is not restarted, this 12247827cba2SAaron LI * won't be a problem. 12257827cba2SAaron LI * If we don't like it, we can always 12267827cba2SAaron LI * pretend lifetimes are infinite and always 12277827cba2SAaron LI * generate a new temporary address on 12287827cba2SAaron LI * restart. */ 12297827cba2SAaron LI ia->acquired = ia->created; 12307827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next); 12317827cba2SAaron LI } 12327827cba2SAaron LI ia->addr_flags = addrflags; 12337827cba2SAaron LI ia->flags &= ~IPV6_AF_STALE; 12347827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 12357827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TEMPORARY) 12367827cba2SAaron LI ia->flags |= IPV6_AF_TEMPORARY; 12377827cba2SAaron LI #endif 12387827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) { 12397827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 12407827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TENTATIVE) { 12416e63cc1fSRoy Marples eloop_timeout_add_msec( 12427827cba2SAaron LI ia->iface->ctx->eloop, 12436e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia); 12447827cba2SAaron LI break; 12457827cba2SAaron LI } 12467827cba2SAaron LI #endif 12477827cba2SAaron LI 1248d4fb1e02SRoy Marples if (ia->dadcallback) 12497827cba2SAaron LI ia->dadcallback(ia); 12507827cba2SAaron LI 12517827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) && 12527827cba2SAaron LI !(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 12537827cba2SAaron LI { 12547827cba2SAaron LI /* Now run any callbacks. 12557827cba2SAaron LI * Typically IPv6RS or DHCPv6 */ 12567827cba2SAaron LI while ((cb = 12577827cba2SAaron LI TAILQ_FIRST(&state->ll_callbacks))) 12587827cba2SAaron LI { 12597827cba2SAaron LI TAILQ_REMOVE( 12607827cba2SAaron LI &state->ll_callbacks, 12617827cba2SAaron LI cb, next); 12627827cba2SAaron LI cb->callback(cb->arg); 12637827cba2SAaron LI free(cb); 12647827cba2SAaron LI } 12657827cba2SAaron LI } 12667827cba2SAaron LI } 12677827cba2SAaron LI break; 12687827cba2SAaron LI } 12697827cba2SAaron LI 12707827cba2SAaron LI if (ia == NULL) 12717827cba2SAaron LI return; 12727827cba2SAaron LI 12738d36e1dfSRoy Marples ctx->options &= ~DHCPCD_RTBUILD; 12747827cba2SAaron LI ipv6nd_handleifa(cmd, ia, pid); 12757827cba2SAaron LI #ifdef DHCP6 12767827cba2SAaron LI dhcp6_handleifa(cmd, ia, pid); 12777827cba2SAaron LI #endif 12787827cba2SAaron LI 12797827cba2SAaron LI /* Done with the ia now, so free it. */ 12807827cba2SAaron LI if (cmd == RTM_DELADDR) 12817827cba2SAaron LI ipv6_freeaddr(ia); 12828d36e1dfSRoy Marples else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 12838d36e1dfSRoy Marples ia->flags |= IPV6_AF_DADCOMPLETED; 12848d36e1dfSRoy Marples 12858d36e1dfSRoy Marples /* If we've not already called rt_build via the IPv6ND 12868d36e1dfSRoy Marples * or DHCP6 handlers and the existance of any useable 12878d36e1dfSRoy Marples * global address on the interface has changed, 12888d36e1dfSRoy Marples * call rt_build to add/remove the default route. */ 1289ce3872cbSRoy Marples if (ifp->active && 1290ce3872cbSRoy Marples ((ifp->options != NULL && ifp->options->options & DHCPCD_IPV6) || 1291ce3872cbSRoy Marples (ifp->options == NULL && ctx->options & DHCPCD_IPV6)) && 12928d36e1dfSRoy Marples !(ctx->options & DHCPCD_RTBUILD) && 129312af092aSRoy Marples (ipv6_anyglobal(ifp) != NULL) != anyglobal) 12948d36e1dfSRoy Marples rt_build(ctx, AF_INET6); 12957827cba2SAaron LI } 12967827cba2SAaron LI 12977827cba2SAaron LI int 12987827cba2SAaron LI ipv6_hasaddr(const struct interface *ifp) 12997827cba2SAaron LI { 13007827cba2SAaron LI 13017827cba2SAaron LI if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL) 13027827cba2SAaron LI return 1; 13038d36e1dfSRoy Marples #ifdef DHCP6 13047827cba2SAaron LI if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL) 13057827cba2SAaron LI return 1; 13068d36e1dfSRoy Marples #endif 13077827cba2SAaron LI return 0; 13087827cba2SAaron LI } 13097827cba2SAaron LI 13107827cba2SAaron LI struct ipv6_addr * 13117827cba2SAaron LI ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr, 13127827cba2SAaron LI int revflags) 13137827cba2SAaron LI { 13147827cba2SAaron LI struct ipv6_state *state; 13157827cba2SAaron LI struct ipv6_addr *ap; 13167827cba2SAaron LI 13177827cba2SAaron LI state = IPV6_STATE(ifp); 13187827cba2SAaron LI if (state) { 13197827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) { 13207827cba2SAaron LI if (addr == NULL) { 13217827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) && 13227827cba2SAaron LI (!revflags || !(ap->addr_flags & revflags))) 13237827cba2SAaron LI return ap; 13247827cba2SAaron LI } else { 13257827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) && 13267827cba2SAaron LI (!revflags || !(ap->addr_flags & revflags))) 13277827cba2SAaron LI return ap; 13287827cba2SAaron LI } 13297827cba2SAaron LI } 13307827cba2SAaron LI } 13317827cba2SAaron LI return NULL; 13327827cba2SAaron LI } 13337827cba2SAaron LI 13347827cba2SAaron LI static struct ipv6_addr * 13357827cba2SAaron LI ipv6_iffindmaskaddr(const struct interface *ifp, const struct in6_addr *addr) 13367827cba2SAaron LI { 13377827cba2SAaron LI struct ipv6_state *state; 13387827cba2SAaron LI struct ipv6_addr *ap; 13397827cba2SAaron LI struct in6_addr mask; 13407827cba2SAaron LI 13417827cba2SAaron LI state = IPV6_STATE(ifp); 13427827cba2SAaron LI if (state) { 13437827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) { 13447827cba2SAaron LI if (ipv6_mask(&mask, ap->prefix_len) == -1) 13457827cba2SAaron LI continue; 13467827cba2SAaron LI if (IN6_ARE_MASKED_ADDR_EQUAL(&ap->addr, addr, &mask)) 13477827cba2SAaron LI return ap; 13487827cba2SAaron LI } 13497827cba2SAaron LI } 13507827cba2SAaron LI return NULL; 13517827cba2SAaron LI } 13527827cba2SAaron LI 13537827cba2SAaron LI struct ipv6_addr * 13547827cba2SAaron LI ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr) 13557827cba2SAaron LI { 13567827cba2SAaron LI struct interface *ifp; 13577827cba2SAaron LI struct ipv6_addr *ap; 13587827cba2SAaron LI 13597827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 13607827cba2SAaron LI ap = ipv6_iffindmaskaddr(ifp, addr); 13617827cba2SAaron LI if (ap != NULL) 13627827cba2SAaron LI return ap; 13637827cba2SAaron LI } 13647827cba2SAaron LI return NULL; 13657827cba2SAaron LI } 13667827cba2SAaron LI 13677827cba2SAaron LI int 13687827cba2SAaron LI ipv6_addlinklocalcallback(struct interface *ifp, 13697827cba2SAaron LI void (*callback)(void *), void *arg) 13707827cba2SAaron LI { 13717827cba2SAaron LI struct ipv6_state *state; 13727827cba2SAaron LI struct ll_callback *cb; 13737827cba2SAaron LI 13747827cba2SAaron LI state = ipv6_getstate(ifp); 13757827cba2SAaron LI TAILQ_FOREACH(cb, &state->ll_callbacks, next) { 13767827cba2SAaron LI if (cb->callback == callback && cb->arg == arg) 13777827cba2SAaron LI break; 13787827cba2SAaron LI } 13797827cba2SAaron LI if (cb == NULL) { 13807827cba2SAaron LI cb = malloc(sizeof(*cb)); 13817827cba2SAaron LI if (cb == NULL) { 13827827cba2SAaron LI logerr(__func__); 13837827cba2SAaron LI return -1; 13847827cba2SAaron LI } 13857827cba2SAaron LI cb->callback = callback; 13867827cba2SAaron LI cb->arg = arg; 13877827cba2SAaron LI TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next); 13887827cba2SAaron LI } 13897827cba2SAaron LI return 0; 13907827cba2SAaron LI } 13917827cba2SAaron LI 13927827cba2SAaron LI static struct ipv6_addr * 13937827cba2SAaron LI ipv6_newlinklocal(struct interface *ifp) 13947827cba2SAaron LI { 13957827cba2SAaron LI struct ipv6_addr *ia; 13967827cba2SAaron LI struct in6_addr in6; 13977827cba2SAaron LI 13987827cba2SAaron LI memset(&in6, 0, sizeof(in6)); 13997827cba2SAaron LI in6.s6_addr32[0] = htonl(0xfe800000); 14007827cba2SAaron LI ia = ipv6_newaddr(ifp, &in6, 64, 0); 14017827cba2SAaron LI if (ia != NULL) { 14027827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME; 14037827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME; 14047827cba2SAaron LI } 14057827cba2SAaron LI return ia; 14067827cba2SAaron LI } 14077827cba2SAaron LI 14087827cba2SAaron LI static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 14097827cba2SAaron LI static const uint8_t allone[8] = 14107827cba2SAaron LI { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 14117827cba2SAaron LI 14127827cba2SAaron LI static int 14137827cba2SAaron LI ipv6_addlinklocal(struct interface *ifp) 14147827cba2SAaron LI { 14157827cba2SAaron LI struct ipv6_state *state; 14167827cba2SAaron LI struct ipv6_addr *ap, *ap2; 14177827cba2SAaron LI int dadcounter; 14187827cba2SAaron LI 1419*b2927f2bSRoy Marples if (!(ifp->options->options & DHCPCD_CONFIGURE)) 1420*b2927f2bSRoy Marples return 0; 1421*b2927f2bSRoy Marples 14227827cba2SAaron LI /* Check sanity before malloc */ 14237827cba2SAaron LI if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) { 1424d4fb1e02SRoy Marples switch (ifp->hwtype) { 14257827cba2SAaron LI case ARPHRD_ETHER: 14267827cba2SAaron LI /* Check for a valid hardware address */ 14277827cba2SAaron LI if (ifp->hwlen != 6 && ifp->hwlen != 8) { 14287827cba2SAaron LI errno = ENOTSUP; 14297827cba2SAaron LI return -1; 14307827cba2SAaron LI } 14317827cba2SAaron LI if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 || 14327827cba2SAaron LI memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0) 14337827cba2SAaron LI { 14347827cba2SAaron LI errno = EINVAL; 14357827cba2SAaron LI return -1; 14367827cba2SAaron LI } 14377827cba2SAaron LI break; 14387827cba2SAaron LI default: 14397827cba2SAaron LI errno = ENOTSUP; 14407827cba2SAaron LI return -1; 14417827cba2SAaron LI } 14427827cba2SAaron LI } 14437827cba2SAaron LI 14447827cba2SAaron LI state = ipv6_getstate(ifp); 14457827cba2SAaron LI if (state == NULL) 14467827cba2SAaron LI return -1; 14477827cba2SAaron LI 14487827cba2SAaron LI ap = ipv6_newlinklocal(ifp); 14497827cba2SAaron LI if (ap == NULL) 14507827cba2SAaron LI return -1; 14517827cba2SAaron LI 14527827cba2SAaron LI dadcounter = 0; 14537827cba2SAaron LI if (ifp->options->options & DHCPCD_SLAACPRIVATE) { 14547827cba2SAaron LI nextslaacprivate: 14557827cba2SAaron LI if (ipv6_makestableprivate(&ap->addr, 14567827cba2SAaron LI &ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1) 14577827cba2SAaron LI { 14587827cba2SAaron LI free(ap); 14597827cba2SAaron LI return -1; 14607827cba2SAaron LI } 14617827cba2SAaron LI ap->dadcounter = dadcounter; 14627827cba2SAaron LI } else { 14637827cba2SAaron LI memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8); 1464d4fb1e02SRoy Marples switch (ifp->hwtype) { 14657827cba2SAaron LI case ARPHRD_ETHER: 14667827cba2SAaron LI if (ifp->hwlen == 6) { 14677827cba2SAaron LI ap->addr.s6_addr[ 8] = ifp->hwaddr[0]; 14687827cba2SAaron LI ap->addr.s6_addr[ 9] = ifp->hwaddr[1]; 14697827cba2SAaron LI ap->addr.s6_addr[10] = ifp->hwaddr[2]; 14707827cba2SAaron LI ap->addr.s6_addr[11] = 0xff; 14717827cba2SAaron LI ap->addr.s6_addr[12] = 0xfe; 14727827cba2SAaron LI ap->addr.s6_addr[13] = ifp->hwaddr[3]; 14737827cba2SAaron LI ap->addr.s6_addr[14] = ifp->hwaddr[4]; 14747827cba2SAaron LI ap->addr.s6_addr[15] = ifp->hwaddr[5]; 14757827cba2SAaron LI } else if (ifp->hwlen == 8) 14767827cba2SAaron LI memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8); 14777827cba2SAaron LI else { 14787827cba2SAaron LI free(ap); 14797827cba2SAaron LI errno = ENOTSUP; 14807827cba2SAaron LI return -1; 14817827cba2SAaron LI } 14827827cba2SAaron LI break; 14837827cba2SAaron LI } 14847827cba2SAaron LI 14857827cba2SAaron LI /* Sanity check: g bit must not indciate "group" */ 14867827cba2SAaron LI if (EUI64_GROUP(&ap->addr)) { 14877827cba2SAaron LI free(ap); 14887827cba2SAaron LI errno = EINVAL; 14897827cba2SAaron LI return -1; 14907827cba2SAaron LI } 14917827cba2SAaron LI EUI64_TO_IFID(&ap->addr); 14927827cba2SAaron LI } 14937827cba2SAaron LI 14947827cba2SAaron LI /* Do we already have this address? */ 14957827cba2SAaron LI TAILQ_FOREACH(ap2, &state->addrs, next) { 14967827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ap2->addr)) { 14977827cba2SAaron LI if (ap2->addr_flags & IN6_IFF_DUPLICATED) { 14987827cba2SAaron LI if (ifp->options->options & 14997827cba2SAaron LI DHCPCD_SLAACPRIVATE) 15007827cba2SAaron LI { 15017827cba2SAaron LI dadcounter++; 15027827cba2SAaron LI goto nextslaacprivate; 15037827cba2SAaron LI } 15047827cba2SAaron LI free(ap); 15057827cba2SAaron LI errno = EADDRNOTAVAIL; 15067827cba2SAaron LI return -1; 15077827cba2SAaron LI } 15087827cba2SAaron LI 15097827cba2SAaron LI logwarnx("%s: waiting for %s to complete", 15107827cba2SAaron LI ap2->iface->name, ap2->saddr); 15117827cba2SAaron LI free(ap); 15127827cba2SAaron LI errno = EEXIST; 15137827cba2SAaron LI return 0; 15147827cba2SAaron LI } 15157827cba2SAaron LI } 15167827cba2SAaron LI 15177827cba2SAaron LI inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr)); 15187827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ap, next); 15197827cba2SAaron LI ipv6_addaddr(ap, NULL); 15207827cba2SAaron LI return 1; 15217827cba2SAaron LI } 15227827cba2SAaron LI 15237827cba2SAaron LI static int 15247827cba2SAaron LI ipv6_tryaddlinklocal(struct interface *ifp) 15257827cba2SAaron LI { 15267827cba2SAaron LI struct ipv6_addr *ia; 15277827cba2SAaron LI 15287827cba2SAaron LI /* We can't assign a link-locak address to this, 15297827cba2SAaron LI * the ppp process has to. */ 15307827cba2SAaron LI if (ifp->flags & IFF_POINTOPOINT) 15317827cba2SAaron LI return 0; 15327827cba2SAaron LI 15337827cba2SAaron LI ia = ipv6_iffindaddr(ifp, NULL, IN6_IFF_DUPLICATED); 15347827cba2SAaron LI if (ia != NULL) { 15357827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 15367827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TENTATIVE) { 15376e63cc1fSRoy Marples eloop_timeout_add_msec( 15387827cba2SAaron LI ia->iface->ctx->eloop, 15396e63cc1fSRoy Marples RETRANS_TIMER / 2, ipv6_checkaddrflags, ia); 15407827cba2SAaron LI } 15417827cba2SAaron LI #endif 15427827cba2SAaron LI return 0; 15437827cba2SAaron LI } 15447827cba2SAaron LI if (!CAN_ADD_LLADDR(ifp)) 15457827cba2SAaron LI return 0; 15467827cba2SAaron LI 15477827cba2SAaron LI return ipv6_addlinklocal(ifp); 15487827cba2SAaron LI } 15497827cba2SAaron LI 1550d4fb1e02SRoy Marples void 1551d4fb1e02SRoy Marples ipv6_setscope(struct sockaddr_in6 *sin, unsigned int ifindex) 1552d4fb1e02SRoy Marples { 1553d4fb1e02SRoy Marples 1554d4fb1e02SRoy Marples #ifdef __KAME__ 1555d4fb1e02SRoy Marples /* KAME based systems want to store the scope inside the sin6_addr 1556d4fb1e02SRoy Marples * for link local addresses */ 1557d4fb1e02SRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 1558d4fb1e02SRoy Marples uint16_t scope = htons((uint16_t)ifindex); 1559d4fb1e02SRoy Marples memcpy(&sin->sin6_addr.s6_addr[2], &scope, 1560d4fb1e02SRoy Marples sizeof(scope)); 1561d4fb1e02SRoy Marples } 1562d4fb1e02SRoy Marples sin->sin6_scope_id = 0; 1563d4fb1e02SRoy Marples #else 1564d4fb1e02SRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) 1565d4fb1e02SRoy Marples sin->sin6_scope_id = ifindex; 1566d4fb1e02SRoy Marples else 1567d4fb1e02SRoy Marples sin->sin6_scope_id = 0; 1568d4fb1e02SRoy Marples #endif 1569d4fb1e02SRoy Marples } 1570d4fb1e02SRoy Marples 1571d4fb1e02SRoy Marples unsigned int 1572d4fb1e02SRoy Marples ipv6_getscope(const struct sockaddr_in6 *sin) 1573d4fb1e02SRoy Marples { 1574d4fb1e02SRoy Marples #ifdef __KAME__ 1575d4fb1e02SRoy Marples uint16_t scope; 1576d4fb1e02SRoy Marples #endif 1577d4fb1e02SRoy Marples 1578d4fb1e02SRoy Marples if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) 1579d4fb1e02SRoy Marples return 0; 1580d4fb1e02SRoy Marples #ifdef __KAME__ 1581d4fb1e02SRoy Marples memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope)); 1582d4fb1e02SRoy Marples return (unsigned int)ntohs(scope); 1583d4fb1e02SRoy Marples #else 1584d4fb1e02SRoy Marples return (unsigned int)sin->sin6_scope_id; 1585d4fb1e02SRoy Marples #endif 1586d4fb1e02SRoy Marples } 1587d4fb1e02SRoy Marples 15887827cba2SAaron LI struct ipv6_addr * 15897827cba2SAaron LI ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr, 15907827cba2SAaron LI uint8_t prefix_len, unsigned int flags) 15917827cba2SAaron LI { 15926e63cc1fSRoy Marples struct ipv6_addr *ia, *iaf; 15937827cba2SAaron LI char buf[INET6_ADDRSTRLEN]; 15947827cba2SAaron LI const char *cbp; 15957827cba2SAaron LI bool tempaddr; 15967827cba2SAaron LI int addr_flags; 15977827cba2SAaron LI 15986e63cc1fSRoy Marples #ifdef IPV6_AF_TEMPORARY 15996e63cc1fSRoy Marples tempaddr = flags & IPV6_AF_TEMPORARY; 16006e63cc1fSRoy Marples #else 16016e63cc1fSRoy Marples tempaddr = false; 16026e63cc1fSRoy Marples #endif 16036e63cc1fSRoy Marples 16047827cba2SAaron LI /* If adding a new DHCP / RA derived address, check current flags 16057827cba2SAaron LI * from an existing address. */ 1606280986e4SRoy Marples if (tempaddr) 1607280986e4SRoy Marples iaf = NULL; 1608280986e4SRoy Marples else if (flags & IPV6_AF_AUTOCONF) 16096e63cc1fSRoy Marples iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len); 16107827cba2SAaron LI else 16116e63cc1fSRoy Marples iaf = ipv6_iffindaddr(ifp, addr, 0); 16126e63cc1fSRoy Marples if (iaf != NULL) { 16136e63cc1fSRoy Marples addr_flags = iaf->addr_flags; 16146e63cc1fSRoy Marples flags |= IPV6_AF_ADDED; 16156e63cc1fSRoy Marples } else 16167827cba2SAaron LI addr_flags = IN6_IFF_TENTATIVE; 16177827cba2SAaron LI 16187827cba2SAaron LI ia = calloc(1, sizeof(*ia)); 16197827cba2SAaron LI if (ia == NULL) 16207827cba2SAaron LI goto err; 16217827cba2SAaron LI 16227827cba2SAaron LI ia->iface = ifp; 16237827cba2SAaron LI ia->addr_flags = addr_flags; 16248d36e1dfSRoy Marples ia->flags = IPV6_AF_NEW | flags; 16258d36e1dfSRoy Marples if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 16268d36e1dfSRoy Marples ia->flags |= IPV6_AF_DADCOMPLETED; 16277827cba2SAaron LI ia->prefix_len = prefix_len; 16287827cba2SAaron LI ia->dhcp6_fd = -1; 16297827cba2SAaron LI 1630ce6cc02eSRoy Marples #ifndef SMALL 1631ce6cc02eSRoy Marples TAILQ_INIT(&ia->pd_pfxs); 1632ce6cc02eSRoy Marples #endif 1633ce6cc02eSRoy Marples 16346e63cc1fSRoy Marples if (prefix_len == 128) 16356e63cc1fSRoy Marples goto makepfx; 1636280986e4SRoy Marples else if (ia->flags & IPV6_AF_AUTOCONF) { 16377827cba2SAaron LI ia->prefix = *addr; 16386e63cc1fSRoy Marples if (iaf != NULL) 16396e63cc1fSRoy Marples memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr)); 16406e63cc1fSRoy Marples else { 16417827cba2SAaron LI ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp, 16427827cba2SAaron LI &ia->prefix, 1643280986e4SRoy Marples ia->prefix_len, 1644280986e4SRoy Marples ia->flags); 16457827cba2SAaron LI if (ia->dadcounter == -1) 16467827cba2SAaron LI goto err; 16476e63cc1fSRoy Marples } 16487827cba2SAaron LI } else if (ia->flags & IPV6_AF_RAPFX) { 16497827cba2SAaron LI ia->prefix = *addr; 16508d36e1dfSRoy Marples #ifdef __sun 16518d36e1dfSRoy Marples ia->addr = *addr; 16528d36e1dfSRoy Marples cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf)); 16538d36e1dfSRoy Marples goto paddr; 16548d36e1dfSRoy Marples #else 16557827cba2SAaron LI return ia; 16568d36e1dfSRoy Marples #endif 16576e63cc1fSRoy Marples } else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX)) { 16587827cba2SAaron LI ia->prefix = *addr; 16597827cba2SAaron LI cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf)); 16607827cba2SAaron LI goto paddr; 16617827cba2SAaron LI } else { 16626e63cc1fSRoy Marples makepfx: 16637827cba2SAaron LI ia->addr = *addr; 16647827cba2SAaron LI if (ipv6_makeprefix(&ia->prefix, 16657827cba2SAaron LI &ia->addr, ia->prefix_len) == -1) 16667827cba2SAaron LI goto err; 16677827cba2SAaron LI } 16687827cba2SAaron LI 16697827cba2SAaron LI cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf)); 16707827cba2SAaron LI paddr: 16717827cba2SAaron LI if (cbp == NULL) 16727827cba2SAaron LI goto err; 16737827cba2SAaron LI snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len); 16747827cba2SAaron LI 16757827cba2SAaron LI return ia; 16767827cba2SAaron LI 16777827cba2SAaron LI err: 16787827cba2SAaron LI logerr(__func__); 16797827cba2SAaron LI free(ia); 16807827cba2SAaron LI return NULL; 16817827cba2SAaron LI } 16827827cba2SAaron LI 16837827cba2SAaron LI static void 16847827cba2SAaron LI ipv6_staticdadcallback(void *arg) 16857827cba2SAaron LI { 16867827cba2SAaron LI struct ipv6_addr *ia = arg; 16877827cba2SAaron LI int wascompleted; 16887827cba2SAaron LI 16897827cba2SAaron LI wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED); 16907827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED; 1691d4fb1e02SRoy Marples if (ia->addr_flags & IN6_IFF_DUPLICATED) 16927827cba2SAaron LI logwarnx("%s: DAD detected %s", ia->iface->name, 16937827cba2SAaron LI ia->saddr); 16947827cba2SAaron LI else if (!wascompleted) { 16957827cba2SAaron LI logdebugx("%s: IPv6 static DAD completed", 16967827cba2SAaron LI ia->iface->name); 16977827cba2SAaron LI } 16987827cba2SAaron LI 16997827cba2SAaron LI #define FINISHED (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED) 17007827cba2SAaron LI if (!wascompleted) { 17017827cba2SAaron LI struct interface *ifp; 17027827cba2SAaron LI struct ipv6_state *state; 17037827cba2SAaron LI 17047827cba2SAaron LI ifp = ia->iface; 17057827cba2SAaron LI state = IPV6_STATE(ifp); 17067827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 17077827cba2SAaron LI if (ia->flags & IPV6_AF_STATIC && 17087827cba2SAaron LI (ia->flags & FINISHED) != FINISHED) 17097827cba2SAaron LI { 17107827cba2SAaron LI wascompleted = 1; 17117827cba2SAaron LI break; 17127827cba2SAaron LI } 17137827cba2SAaron LI } 17147827cba2SAaron LI if (!wascompleted) 17157827cba2SAaron LI script_runreason(ifp, "STATIC6"); 17167827cba2SAaron LI } 17177827cba2SAaron LI #undef FINISHED 17187827cba2SAaron LI } 17197827cba2SAaron LI 17207827cba2SAaron LI ssize_t 17218d36e1dfSRoy Marples ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp) 17227827cba2SAaron LI { 17237827cba2SAaron LI struct ipv6_addr *ia; 17247827cba2SAaron LI 17257827cba2SAaron LI ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6, 17267827cba2SAaron LI IN6_IFF_NOTUSEABLE); 17278d36e1dfSRoy Marples if (ia == NULL) 17288d36e1dfSRoy Marples return 0; 17298d36e1dfSRoy Marples if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1) 17308d36e1dfSRoy Marples return -1; 17318d36e1dfSRoy Marples return 1; 17327827cba2SAaron LI } 17337827cba2SAaron LI 17347827cba2SAaron LI int 17357827cba2SAaron LI ipv6_staticdadcompleted(const struct interface *ifp) 17367827cba2SAaron LI { 17377827cba2SAaron LI const struct ipv6_state *state; 17387827cba2SAaron LI const struct ipv6_addr *ia; 17397827cba2SAaron LI int n; 17407827cba2SAaron LI 17417827cba2SAaron LI if ((state = IPV6_CSTATE(ifp)) == NULL) 17427827cba2SAaron LI return 0; 17437827cba2SAaron LI n = 0; 17447827cba2SAaron LI #define COMPLETED (IPV6_AF_STATIC | IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED) 17457827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 17467827cba2SAaron LI if ((ia->flags & COMPLETED) == COMPLETED && 17477827cba2SAaron LI !(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 17487827cba2SAaron LI n++; 17497827cba2SAaron LI } 17507827cba2SAaron LI return n; 17517827cba2SAaron LI } 17527827cba2SAaron LI 17537827cba2SAaron LI int 17547827cba2SAaron LI ipv6_startstatic(struct interface *ifp) 17557827cba2SAaron LI { 17567827cba2SAaron LI struct ipv6_addr *ia; 17577827cba2SAaron LI int run_script; 17587827cba2SAaron LI 17597827cba2SAaron LI if (IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6)) 17607827cba2SAaron LI return 0; 17617827cba2SAaron LI 17627827cba2SAaron LI ia = ipv6_iffindaddr(ifp, &ifp->options->req_addr6, 0); 17637827cba2SAaron LI if (ia != NULL && 17647827cba2SAaron LI (ia->prefix_len != ifp->options->req_prefix_len || 17657827cba2SAaron LI ia->addr_flags & IN6_IFF_NOTUSEABLE)) 17667827cba2SAaron LI { 17677827cba2SAaron LI ipv6_deleteaddr(ia); 17687827cba2SAaron LI ia = NULL; 17697827cba2SAaron LI } 17707827cba2SAaron LI if (ia == NULL) { 17717827cba2SAaron LI struct ipv6_state *state; 17727827cba2SAaron LI 17737827cba2SAaron LI ia = ipv6_newaddr(ifp, &ifp->options->req_addr6, 17747827cba2SAaron LI ifp->options->req_prefix_len, 0); 17757827cba2SAaron LI if (ia == NULL) 17767827cba2SAaron LI return -1; 17777827cba2SAaron LI state = IPV6_STATE(ifp); 17787827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next); 17797827cba2SAaron LI run_script = 0; 17807827cba2SAaron LI } else 17817827cba2SAaron LI run_script = 1; 17827827cba2SAaron LI ia->flags |= IPV6_AF_STATIC | IPV6_AF_ONLINK; 17837827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME; 17847827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME; 17857827cba2SAaron LI ia->dadcallback = ipv6_staticdadcallback; 17867827cba2SAaron LI ipv6_addaddr(ia, NULL); 17877827cba2SAaron LI rt_build(ifp->ctx, AF_INET6); 17887827cba2SAaron LI if (run_script) 17897827cba2SAaron LI script_runreason(ifp, "STATIC6"); 17907827cba2SAaron LI return 1; 17917827cba2SAaron LI } 17927827cba2SAaron LI 17937827cba2SAaron LI /* Ensure the interface has a link-local address */ 17947827cba2SAaron LI int 17957827cba2SAaron LI ipv6_start(struct interface *ifp) 17967827cba2SAaron LI { 17977827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 17987827cba2SAaron LI struct ipv6_state *state; 17997827cba2SAaron LI 18007827cba2SAaron LI /* We need to update the address flags. */ 18017827cba2SAaron LI if ((state = IPV6_STATE(ifp)) != NULL) { 18027827cba2SAaron LI struct ipv6_addr *ia; 18037827cba2SAaron LI const char *alias; 18047827cba2SAaron LI int flags; 18057827cba2SAaron LI 18067827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 18077827cba2SAaron LI #ifdef ALIAS_ADDR 18087827cba2SAaron LI alias = ia->alias; 18097827cba2SAaron LI #else 18107827cba2SAaron LI alias = NULL; 18117827cba2SAaron LI #endif 18127827cba2SAaron LI flags = if_addrflags6(ia->iface, &ia->addr, alias); 18137827cba2SAaron LI if (flags != -1) 18147827cba2SAaron LI ia->addr_flags = flags; 18157827cba2SAaron LI } 18167827cba2SAaron LI } 18177827cba2SAaron LI #endif 18187827cba2SAaron LI 18197827cba2SAaron LI if (ipv6_tryaddlinklocal(ifp) == -1) 18207827cba2SAaron LI return -1; 18217827cba2SAaron LI 18227827cba2SAaron LI return 0; 18237827cba2SAaron LI } 18247827cba2SAaron LI 18257827cba2SAaron LI void 18267827cba2SAaron LI ipv6_freedrop(struct interface *ifp, int drop) 18277827cba2SAaron LI { 18287827cba2SAaron LI struct ipv6_state *state; 18297827cba2SAaron LI struct ll_callback *cb; 18307827cba2SAaron LI 18317827cba2SAaron LI if (ifp == NULL) 18327827cba2SAaron LI return; 18337827cba2SAaron LI 18347827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL) 18357827cba2SAaron LI return; 18367827cba2SAaron LI 18377827cba2SAaron LI /* If we got here, we can get rid of any LL callbacks. */ 18387827cba2SAaron LI while ((cb = TAILQ_FIRST(&state->ll_callbacks))) { 18397827cba2SAaron LI TAILQ_REMOVE(&state->ll_callbacks, cb, next); 18407827cba2SAaron LI free(cb); 18417827cba2SAaron LI } 18427827cba2SAaron LI 18437827cba2SAaron LI ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL); 18447827cba2SAaron LI if (drop) { 18458d36e1dfSRoy Marples if (ifp->ctx->ra_routers != NULL) 18467827cba2SAaron LI rt_build(ifp->ctx, AF_INET6); 18477827cba2SAaron LI } else { 18487827cba2SAaron LI /* Because we need to cache the addresses we don't control, 18497827cba2SAaron LI * we only free the state on when NOT dropping addresses. */ 18507827cba2SAaron LI free(state); 18517827cba2SAaron LI ifp->if_data[IF_DATA_IPV6] = NULL; 18527827cba2SAaron LI eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 18537827cba2SAaron LI } 18547827cba2SAaron LI } 18557827cba2SAaron LI 18567827cba2SAaron LI void 18577827cba2SAaron LI ipv6_ctxfree(struct dhcpcd_ctx *ctx) 18587827cba2SAaron LI { 18597827cba2SAaron LI 18607827cba2SAaron LI free(ctx->ra_routers); 18617827cba2SAaron LI free(ctx->secret); 18627827cba2SAaron LI } 18637827cba2SAaron LI 18647827cba2SAaron LI int 18657827cba2SAaron LI ipv6_handleifa_addrs(int cmd, 18667827cba2SAaron LI struct ipv6_addrhead *addrs, const struct ipv6_addr *addr, pid_t pid) 18677827cba2SAaron LI { 18687827cba2SAaron LI struct ipv6_addr *ia, *ian; 18697827cba2SAaron LI uint8_t found, alldadcompleted; 18707827cba2SAaron LI 18717827cba2SAaron LI alldadcompleted = 1; 18727827cba2SAaron LI found = 0; 18737827cba2SAaron LI TAILQ_FOREACH_SAFE(ia, addrs, next, ian) { 18747827cba2SAaron LI if (!IN6_ARE_ADDR_EQUAL(&addr->addr, &ia->addr)) { 18757827cba2SAaron LI if (ia->flags & IPV6_AF_ADDED && 18767827cba2SAaron LI !(ia->flags & IPV6_AF_DADCOMPLETED)) 18777827cba2SAaron LI alldadcompleted = 0; 18787827cba2SAaron LI continue; 18797827cba2SAaron LI } 18807827cba2SAaron LI switch (cmd) { 18817827cba2SAaron LI case RTM_DELADDR: 18827827cba2SAaron LI if (ia->flags & IPV6_AF_ADDED) { 18837827cba2SAaron LI logwarnx("%s: pid %d deleted address %s", 18847827cba2SAaron LI ia->iface->name, pid, ia->saddr); 18857827cba2SAaron LI ia->flags &= ~IPV6_AF_ADDED; 18867827cba2SAaron LI } 18876e63cc1fSRoy Marples ipv6_deletedaddr(ia); 18887827cba2SAaron LI if (ia->flags & IPV6_AF_DELEGATED) { 18897827cba2SAaron LI TAILQ_REMOVE(addrs, ia, next); 18907827cba2SAaron LI ipv6_freeaddr(ia); 18917827cba2SAaron LI } 18927827cba2SAaron LI break; 18937827cba2SAaron LI case RTM_NEWADDR: 1894d4fb1e02SRoy Marples ia->addr_flags = addr->addr_flags; 18957827cba2SAaron LI /* Safety - ignore tentative announcements */ 1896d4fb1e02SRoy Marples if (ia->addr_flags & 18977827cba2SAaron LI (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE)) 18987827cba2SAaron LI break; 18997827cba2SAaron LI if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) { 19007827cba2SAaron LI found++; 19017827cba2SAaron LI if (ia->dadcallback) 19027827cba2SAaron LI ia->dadcallback(ia); 19037827cba2SAaron LI /* We need to set this here in-case the 19047827cba2SAaron LI * dadcallback function checks it */ 19057827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED; 19067827cba2SAaron LI } 19077827cba2SAaron LI break; 19087827cba2SAaron LI } 19097827cba2SAaron LI } 19107827cba2SAaron LI 19117827cba2SAaron LI return alldadcompleted ? found : 0; 19127827cba2SAaron LI } 19137827cba2SAaron LI 19147827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 19157827cba2SAaron LI static void 1916280986e4SRoy Marples ipv6_regen_desync(struct interface *ifp, bool force) 19177827cba2SAaron LI { 19187827cba2SAaron LI struct ipv6_state *state; 19197a0236bfSRoy Marples unsigned int max; 19207827cba2SAaron LI 19217827cba2SAaron LI state = IPV6_STATE(ifp); 19227827cba2SAaron LI 19237827cba2SAaron LI /* RFC4941 Section 5 states that DESYNC_FACTOR must never be 19247827cba2SAaron LI * greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE. 1925280986e4SRoy Marples * I believe this is an error and it should be never be greater than 19267827cba2SAaron LI * TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */ 19277a0236bfSRoy Marples max = TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE; 19287827cba2SAaron LI if (state->desync_factor && !force && state->desync_factor < max) 19297827cba2SAaron LI return; 19307827cba2SAaron LI if (state->desync_factor == 0) 19317827cba2SAaron LI state->desync_factor = 19326e63cc1fSRoy Marples arc4random_uniform(MIN(MAX_DESYNC_FACTOR, max)); 19337a0236bfSRoy Marples max = TEMP_PREFERRED_LIFETIME - state->desync_factor - REGEN_ADVANCE; 1934280986e4SRoy Marples eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempaddrs, ifp); 19357827cba2SAaron LI } 19367827cba2SAaron LI 19377827cba2SAaron LI /* RFC4941 Section 3.3.7 */ 19387827cba2SAaron LI static void 19397827cba2SAaron LI ipv6_tempdadcallback(void *arg) 19407827cba2SAaron LI { 19417827cba2SAaron LI struct ipv6_addr *ia = arg; 19427827cba2SAaron LI 1943d4fb1e02SRoy Marples if (ia->addr_flags & IN6_IFF_DUPLICATED) { 19447827cba2SAaron LI struct ipv6_addr *ia1; 19457827cba2SAaron LI struct timespec tv; 19467827cba2SAaron LI 19477827cba2SAaron LI if (++ia->dadcounter == TEMP_IDGEN_RETRIES) { 19487827cba2SAaron LI logerrx("%s: too many duplicate temporary addresses", 19497827cba2SAaron LI ia->iface->name); 19507827cba2SAaron LI return; 19517827cba2SAaron LI } 19527827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &tv); 19537827cba2SAaron LI if ((ia1 = ipv6_createtempaddr(ia, &tv)) == NULL) 19547827cba2SAaron LI logerr(__func__); 19557827cba2SAaron LI else 19567827cba2SAaron LI ia1->dadcounter = ia->dadcounter; 19577827cba2SAaron LI ipv6_deleteaddr(ia); 19587827cba2SAaron LI if (ia1) 19597827cba2SAaron LI ipv6_addaddr(ia1, &ia1->acquired); 19607827cba2SAaron LI } 19617827cba2SAaron LI } 19627827cba2SAaron LI 19637827cba2SAaron LI struct ipv6_addr * 19647827cba2SAaron LI ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now) 19657827cba2SAaron LI { 19667827cba2SAaron LI struct ipv6_state *state; 1967280986e4SRoy Marples struct interface *ifp = ia0->iface; 19687827cba2SAaron LI struct ipv6_addr *ia; 19697827cba2SAaron LI 1970280986e4SRoy Marples ia = ipv6_newaddr(ifp, &ia0->prefix, ia0->prefix_len, 19717827cba2SAaron LI IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY); 1972280986e4SRoy Marples if (ia == NULL) 1973280986e4SRoy Marples return NULL; 1974280986e4SRoy Marples 19757827cba2SAaron LI ia->dadcallback = ipv6_tempdadcallback; 19767827cba2SAaron LI ia->created = ia->acquired = now ? *now : ia0->acquired; 19777827cba2SAaron LI 19787827cba2SAaron LI /* Ensure desync is still valid */ 1979280986e4SRoy Marples ipv6_regen_desync(ifp, false); 19807827cba2SAaron LI 19817827cba2SAaron LI /* RFC4941 Section 3.3.4 */ 1982280986e4SRoy Marples state = IPV6_STATE(ia->iface); 19837a0236bfSRoy Marples ia->prefix_pltime = MIN(ia0->prefix_pltime, 19847a0236bfSRoy Marples TEMP_PREFERRED_LIFETIME - state->desync_factor); 19857a0236bfSRoy Marples ia->prefix_vltime = MIN(ia0->prefix_vltime, TEMP_VALID_LIFETIME); 19867827cba2SAaron LI if (ia->prefix_pltime <= REGEN_ADVANCE || 19877827cba2SAaron LI ia->prefix_pltime > ia0->prefix_vltime) 19887827cba2SAaron LI { 19897827cba2SAaron LI errno = EINVAL; 19907827cba2SAaron LI free(ia); 19917827cba2SAaron LI return NULL; 19927827cba2SAaron LI } 19937827cba2SAaron LI 19947827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next); 19957827cba2SAaron LI return ia; 19967827cba2SAaron LI } 19977827cba2SAaron LI 19987827cba2SAaron LI struct ipv6_addr * 19997827cba2SAaron LI ipv6_settemptime(struct ipv6_addr *ia, int flags) 20007827cba2SAaron LI { 20017827cba2SAaron LI struct ipv6_state *state; 20027827cba2SAaron LI struct ipv6_addr *ap, *first; 20037827cba2SAaron LI 20047827cba2SAaron LI state = IPV6_STATE(ia->iface); 20057827cba2SAaron LI first = NULL; 20067827cba2SAaron LI TAILQ_FOREACH_REVERSE(ap, &state->addrs, ipv6_addrhead, next) { 20077827cba2SAaron LI if (ap->flags & IPV6_AF_TEMPORARY && 20087827cba2SAaron LI ap->prefix_pltime && 20097827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix)) 20107827cba2SAaron LI { 20116e63cc1fSRoy Marples unsigned int max, ext; 20127827cba2SAaron LI 20137827cba2SAaron LI if (flags == 0) { 20147827cba2SAaron LI if (ap->prefix_pltime - 20157827cba2SAaron LI (uint32_t)(ia->acquired.tv_sec - 20167827cba2SAaron LI ap->acquired.tv_sec) 20177827cba2SAaron LI < REGEN_ADVANCE) 20187827cba2SAaron LI continue; 20197827cba2SAaron LI 20207827cba2SAaron LI return ap; 20217827cba2SAaron LI } 20227827cba2SAaron LI 20237827cba2SAaron LI if (!(ap->flags & IPV6_AF_ADDED)) 20247827cba2SAaron LI ap->flags |= IPV6_AF_NEW | IPV6_AF_AUTOCONF; 20257827cba2SAaron LI ap->flags &= ~IPV6_AF_STALE; 20267827cba2SAaron LI 20277827cba2SAaron LI /* RFC4941 Section 3.4 20287827cba2SAaron LI * Deprecated prefix, deprecate the temporary address */ 20297827cba2SAaron LI if (ia->prefix_pltime == 0) { 20307827cba2SAaron LI ap->prefix_pltime = 0; 20317827cba2SAaron LI goto valid; 20327827cba2SAaron LI } 20337827cba2SAaron LI 20347827cba2SAaron LI /* Ensure desync is still valid */ 2035280986e4SRoy Marples ipv6_regen_desync(ap->iface, false); 20367827cba2SAaron LI 20377827cba2SAaron LI /* RFC4941 Section 3.3.2 20387827cba2SAaron LI * Extend temporary times, but ensure that they 20397827cba2SAaron LI * never last beyond the system limit. */ 20406e63cc1fSRoy Marples ext = (unsigned int)ia->acquired.tv_sec 20416e63cc1fSRoy Marples + ia->prefix_pltime; 20426e63cc1fSRoy Marples max = (unsigned int)(ap->created.tv_sec + 20437a0236bfSRoy Marples TEMP_PREFERRED_LIFETIME - 20446e63cc1fSRoy Marples state->desync_factor); 20457827cba2SAaron LI if (ext < max) 20467827cba2SAaron LI ap->prefix_pltime = ia->prefix_pltime; 20477827cba2SAaron LI else 20487827cba2SAaron LI ap->prefix_pltime = 20497827cba2SAaron LI (uint32_t)(max - ia->acquired.tv_sec); 20507827cba2SAaron LI 20517827cba2SAaron LI valid: 20526e63cc1fSRoy Marples ext = (unsigned int)ia->acquired.tv_sec + 20536e63cc1fSRoy Marples ia->prefix_vltime; 20546e63cc1fSRoy Marples max = (unsigned int)(ap->created.tv_sec + 20557a0236bfSRoy Marples TEMP_VALID_LIFETIME); 20567827cba2SAaron LI if (ext < max) 20577827cba2SAaron LI ap->prefix_vltime = ia->prefix_vltime; 20587827cba2SAaron LI else 20597827cba2SAaron LI ap->prefix_vltime = 20607827cba2SAaron LI (uint32_t)(max - ia->acquired.tv_sec); 20617827cba2SAaron LI 20627827cba2SAaron LI /* Just extend the latest matching prefix */ 20637827cba2SAaron LI ap->acquired = ia->acquired; 20647827cba2SAaron LI 20657827cba2SAaron LI /* If extending return the last match as 20667827cba2SAaron LI * it's the most current. 20677827cba2SAaron LI * If deprecating, deprecate any other addresses we 20687827cba2SAaron LI * may have, although this should not be needed */ 20697827cba2SAaron LI if (ia->prefix_pltime) 20707827cba2SAaron LI return ap; 20717827cba2SAaron LI if (first == NULL) 20727827cba2SAaron LI first = ap; 20737827cba2SAaron LI } 20747827cba2SAaron LI } 20757827cba2SAaron LI return first; 20767827cba2SAaron LI } 20777827cba2SAaron LI 20787827cba2SAaron LI void 20797827cba2SAaron LI ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now) 20807827cba2SAaron LI { 20817827cba2SAaron LI struct ipv6_state *state; 20827827cba2SAaron LI struct ipv6_addr *ia; 20837827cba2SAaron LI 20847827cba2SAaron LI state = IPV6_STATE(ifp); 20857827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 20867827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY && 20877827cba2SAaron LI !(ia->flags & IPV6_AF_STALE)) 20887827cba2SAaron LI ipv6_addaddr(ia, now); 20897827cba2SAaron LI } 20907827cba2SAaron LI } 20917827cba2SAaron LI 20927827cba2SAaron LI static void 2093280986e4SRoy Marples ipv6_regentempaddr0(struct ipv6_addr *ia, struct timespec *tv) 20947827cba2SAaron LI { 2095280986e4SRoy Marples struct ipv6_addr *ia1; 20967827cba2SAaron LI 20977827cba2SAaron LI logdebugx("%s: regen temp addr %s", ia->iface->name, ia->saddr); 2098280986e4SRoy Marples ia1 = ipv6_createtempaddr(ia, tv); 20997827cba2SAaron LI if (ia1) 2100280986e4SRoy Marples ipv6_addaddr(ia1, tv); 21017827cba2SAaron LI else 21027827cba2SAaron LI logerr(__func__); 21037827cba2SAaron LI } 21047827cba2SAaron LI 21057827cba2SAaron LI static void 2106280986e4SRoy Marples ipv6_regentempaddr(void *arg) 2107280986e4SRoy Marples { 2108280986e4SRoy Marples struct timespec tv; 2109280986e4SRoy Marples 2110280986e4SRoy Marples clock_gettime(CLOCK_MONOTONIC, &tv); 2111280986e4SRoy Marples ipv6_regentempaddr0(arg, &tv); 2112280986e4SRoy Marples } 2113280986e4SRoy Marples 2114280986e4SRoy Marples void 2115280986e4SRoy Marples ipv6_regentempaddrs(void *arg) 21167827cba2SAaron LI { 21177827cba2SAaron LI struct interface *ifp = arg; 2118280986e4SRoy Marples struct timespec tv; 21197827cba2SAaron LI struct ipv6_state *state; 2120280986e4SRoy Marples struct ipv6_addr *ia; 21217827cba2SAaron LI 21227a0236bfSRoy Marples state = IPV6_STATE(ifp); 21237a0236bfSRoy Marples if (state == NULL) 21247a0236bfSRoy Marples return; 21257a0236bfSRoy Marples 2126280986e4SRoy Marples ipv6_regen_desync(ifp, true); 2127280986e4SRoy Marples 2128280986e4SRoy Marples clock_gettime(CLOCK_MONOTONIC, &tv); 2129d4fb1e02SRoy Marples 2130d4fb1e02SRoy Marples /* Mark addresses for regen so we don't infinite loop. */ 2131280986e4SRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) { 2132280986e4SRoy Marples if (ia->flags & IPV6_AF_TEMPORARY && 2133cc34ba0cSRoy Marples ia->flags & IPV6_AF_ADDED && 2134280986e4SRoy Marples !(ia->flags & IPV6_AF_STALE)) 2135d4fb1e02SRoy Marples ia->flags |= IPV6_AF_REGEN; 2136d4fb1e02SRoy Marples else 2137d4fb1e02SRoy Marples ia->flags &= ~IPV6_AF_REGEN; 2138d4fb1e02SRoy Marples } 2139d4fb1e02SRoy Marples 2140d4fb1e02SRoy Marples /* Now regen temp addrs */ 2141d4fb1e02SRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) { 2142d4fb1e02SRoy Marples if (ia->flags & IPV6_AF_REGEN) { 2143280986e4SRoy Marples ipv6_regentempaddr0(ia, &tv); 2144d4fb1e02SRoy Marples ia->flags &= ~IPV6_AF_REGEN; 2145d4fb1e02SRoy Marples } 2146280986e4SRoy Marples } 21477827cba2SAaron LI } 21487827cba2SAaron LI #endif /* IPV6_MANAGETEMPADDR */ 21497827cba2SAaron LI 21507827cba2SAaron LI void 21517827cba2SAaron LI ipv6_markaddrsstale(struct interface *ifp, unsigned int flags) 21527827cba2SAaron LI { 21537827cba2SAaron LI struct ipv6_state *state; 21547827cba2SAaron LI struct ipv6_addr *ia; 21557827cba2SAaron LI 21567827cba2SAaron LI state = IPV6_STATE(ifp); 21577827cba2SAaron LI if (state == NULL) 21587827cba2SAaron LI return; 21597827cba2SAaron LI 21607827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 21617827cba2SAaron LI if (flags == 0 || ia->flags & flags) 21627827cba2SAaron LI ia->flags |= IPV6_AF_STALE; 21637827cba2SAaron LI } 21647827cba2SAaron LI } 21657827cba2SAaron LI 21667827cba2SAaron LI void 21677827cba2SAaron LI ipv6_deletestaleaddrs(struct interface *ifp) 21687827cba2SAaron LI { 21697827cba2SAaron LI struct ipv6_state *state; 21707827cba2SAaron LI struct ipv6_addr *ia, *ia1; 21717827cba2SAaron LI 21727827cba2SAaron LI state = IPV6_STATE(ifp); 21737827cba2SAaron LI if (state == NULL) 21747827cba2SAaron LI return; 21757827cba2SAaron LI 21767827cba2SAaron LI TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ia1) { 21777827cba2SAaron LI if (ia->flags & IPV6_AF_STALE) 21787827cba2SAaron LI ipv6_handleifa(ifp->ctx, RTM_DELADDR, 21797827cba2SAaron LI ifp->ctx->ifaces, ifp->name, 21807827cba2SAaron LI &ia->addr, ia->prefix_len, 0, getpid()); 21817827cba2SAaron LI } 21827827cba2SAaron LI } 21837827cba2SAaron LI 21847827cba2SAaron LI 21857827cba2SAaron LI static struct rt * 21867827cba2SAaron LI inet6_makeroute(struct interface *ifp, const struct ra *rap) 21877827cba2SAaron LI { 21887827cba2SAaron LI struct rt *rt; 21897827cba2SAaron LI 21907827cba2SAaron LI if ((rt = rt_new(ifp)) == NULL) 21917827cba2SAaron LI return NULL; 21927827cba2SAaron LI 21937827cba2SAaron LI #ifdef HAVE_ROUTE_METRIC 21947827cba2SAaron LI rt->rt_metric = ifp->metric; 21957827cba2SAaron LI #endif 21967827cba2SAaron LI if (rap != NULL) 21977827cba2SAaron LI rt->rt_mtu = rap->mtu; 21987827cba2SAaron LI return rt; 21997827cba2SAaron LI } 22007827cba2SAaron LI 22017827cba2SAaron LI static struct rt * 22027827cba2SAaron LI inet6_makeprefix(struct interface *ifp, const struct ra *rap, 22037827cba2SAaron LI const struct ipv6_addr *addr) 22047827cba2SAaron LI { 22057827cba2SAaron LI struct rt *rt; 22067827cba2SAaron LI struct in6_addr netmask; 22077827cba2SAaron LI 22087827cba2SAaron LI if (addr == NULL || addr->prefix_len > 128) { 22097827cba2SAaron LI errno = EINVAL; 22107827cba2SAaron LI return NULL; 22117827cba2SAaron LI } 22127827cba2SAaron LI 22137827cba2SAaron LI /* There is no point in trying to manage a /128 prefix, 22148d36e1dfSRoy Marples * ones without a lifetime. */ 22158d36e1dfSRoy Marples if (addr->prefix_len == 128 || addr->prefix_vltime == 0) 22167827cba2SAaron LI return NULL; 22177827cba2SAaron LI 22188d36e1dfSRoy Marples /* Don't install a reject route when not creating bigger prefixes. */ 22197827cba2SAaron LI if (addr->flags & IPV6_AF_NOREJECT) 22207827cba2SAaron LI return NULL; 22217827cba2SAaron LI 22227827cba2SAaron LI /* This address is the delegated prefix, so add a reject route for 22237827cba2SAaron LI * it via the loopback interface. */ 22247827cba2SAaron LI if (addr->flags & IPV6_AF_DELEGATEDPFX) { 22257827cba2SAaron LI struct interface *lo0; 22267827cba2SAaron LI 22277827cba2SAaron LI TAILQ_FOREACH(lo0, ifp->ctx->ifaces, next) { 22287827cba2SAaron LI if (lo0->flags & IFF_LOOPBACK) 22297827cba2SAaron LI break; 22307827cba2SAaron LI } 22317827cba2SAaron LI if (lo0 == NULL) 22327827cba2SAaron LI logwarnx("cannot find a loopback interface " 22337827cba2SAaron LI "to reject via"); 22347827cba2SAaron LI else 22357827cba2SAaron LI ifp = lo0; 22367827cba2SAaron LI } 22377827cba2SAaron LI 22387827cba2SAaron LI if ((rt = inet6_makeroute(ifp, rap)) == NULL) 22397827cba2SAaron LI return NULL; 22407827cba2SAaron LI 22417827cba2SAaron LI sa_in6_init(&rt->rt_dest, &addr->prefix); 22427827cba2SAaron LI ipv6_mask(&netmask, addr->prefix_len); 22437827cba2SAaron LI sa_in6_init(&rt->rt_netmask, &netmask); 22447827cba2SAaron LI if (addr->flags & IPV6_AF_DELEGATEDPFX) { 22457827cba2SAaron LI rt->rt_flags |= RTF_REJECT; 22467827cba2SAaron LI /* Linux does not like a gateway for a reject route. */ 22477827cba2SAaron LI #ifndef __linux__ 22487827cba2SAaron LI sa_in6_init(&rt->rt_gateway, &in6addr_loopback); 22497827cba2SAaron LI #endif 22508d36e1dfSRoy Marples } else if (!(addr->flags & IPV6_AF_ONLINK)) 22518d36e1dfSRoy Marples sa_in6_init(&rt->rt_gateway, &rap->from); 22528d36e1dfSRoy Marples else 22537827cba2SAaron LI rt->rt_gateway.sa_family = AF_UNSPEC; 22547827cba2SAaron LI sa_in6_init(&rt->rt_ifa, &addr->addr); 22557827cba2SAaron LI return rt; 22567827cba2SAaron LI } 22577827cba2SAaron LI 22587827cba2SAaron LI static struct rt * 22597827cba2SAaron LI inet6_makerouter(struct ra *rap) 22607827cba2SAaron LI { 22617827cba2SAaron LI struct rt *rt; 22627827cba2SAaron LI 22637827cba2SAaron LI if ((rt = inet6_makeroute(rap->iface, rap)) == NULL) 22647827cba2SAaron LI return NULL; 22657827cba2SAaron LI sa_in6_init(&rt->rt_dest, &in6addr_any); 22667827cba2SAaron LI sa_in6_init(&rt->rt_netmask, &in6addr_any); 22677827cba2SAaron LI sa_in6_init(&rt->rt_gateway, &rap->from); 22687827cba2SAaron LI return rt; 22697827cba2SAaron LI } 22707827cba2SAaron LI 22717827cba2SAaron LI #define RT_IS_DEFAULT(rtp) \ 22727827cba2SAaron LI (IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) && \ 22737827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&((rtp)->mask), &in6addr_any)) 22747827cba2SAaron LI 22757827cba2SAaron LI static int 22768d36e1dfSRoy Marples inet6_staticroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) 22777827cba2SAaron LI { 22787827cba2SAaron LI struct interface *ifp; 22797827cba2SAaron LI struct ipv6_state *state; 22807827cba2SAaron LI struct ipv6_addr *ia; 22817827cba2SAaron LI struct rt *rt; 22827827cba2SAaron LI 22837827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 22847827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL) 22857827cba2SAaron LI continue; 22867827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 22877827cba2SAaron LI if ((ia->flags & (IPV6_AF_ADDED | IPV6_AF_STATIC)) == 22887827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_STATIC)) 22897827cba2SAaron LI { 22907827cba2SAaron LI rt = inet6_makeprefix(ifp, NULL, ia); 22917827cba2SAaron LI if (rt) 22928d36e1dfSRoy Marples rt_proto_add(routes, rt); 22937827cba2SAaron LI } 22947827cba2SAaron LI } 22957827cba2SAaron LI } 22967827cba2SAaron LI return 0; 22977827cba2SAaron LI } 22987827cba2SAaron LI 22997827cba2SAaron LI static int 23008d36e1dfSRoy Marples inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) 23017827cba2SAaron LI { 23027827cba2SAaron LI struct rt *rt; 23037827cba2SAaron LI struct ra *rap; 23047827cba2SAaron LI const struct ipv6_addr *addr; 23057827cba2SAaron LI 23066e63cc1fSRoy Marples if (ctx->ra_routers == NULL) 23076e63cc1fSRoy Marples return 0; 23086e63cc1fSRoy Marples 23097827cba2SAaron LI TAILQ_FOREACH(rap, ctx->ra_routers, next) { 23108d36e1dfSRoy Marples if (rap->expired) 23117827cba2SAaron LI continue; 23127827cba2SAaron LI TAILQ_FOREACH(addr, &rap->addrs, next) { 23137827cba2SAaron LI if (addr->prefix_vltime == 0) 23147827cba2SAaron LI continue; 23157827cba2SAaron LI rt = inet6_makeprefix(rap->iface, rap, addr); 23167827cba2SAaron LI if (rt) { 23177827cba2SAaron LI rt->rt_dflags |= RTDF_RA; 2318280986e4SRoy Marples #ifdef HAVE_ROUTE_PREF 2319280986e4SRoy Marples rt->rt_pref = ipv6nd_rtpref(rap); 2320280986e4SRoy Marples #endif 23218d36e1dfSRoy Marples rt_proto_add(routes, rt); 23227827cba2SAaron LI } 23237827cba2SAaron LI } 23248d36e1dfSRoy Marples if (rap->lifetime == 0) 23258d36e1dfSRoy Marples continue; 232612af092aSRoy Marples if (ipv6_anyglobal(rap->iface) == NULL) 23278d36e1dfSRoy Marples continue; 23287827cba2SAaron LI rt = inet6_makerouter(rap); 23298d36e1dfSRoy Marples if (rt == NULL) 23308d36e1dfSRoy Marples continue; 23317827cba2SAaron LI rt->rt_dflags |= RTDF_RA; 2332280986e4SRoy Marples #ifdef HAVE_ROUTE_PREF 2333280986e4SRoy Marples rt->rt_pref = ipv6nd_rtpref(rap); 2334280986e4SRoy Marples #endif 23358d36e1dfSRoy Marples rt_proto_add(routes, rt); 23367827cba2SAaron LI } 23377827cba2SAaron LI return 0; 23387827cba2SAaron LI } 23397827cba2SAaron LI 23408d36e1dfSRoy Marples #ifdef DHCP6 23417827cba2SAaron LI static int 23428d36e1dfSRoy Marples inet6_dhcproutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx, 23437827cba2SAaron LI enum DH6S dstate) 23447827cba2SAaron LI { 23457827cba2SAaron LI struct interface *ifp; 23467827cba2SAaron LI const struct dhcp6_state *d6_state; 23477827cba2SAaron LI const struct ipv6_addr *addr; 23487827cba2SAaron LI struct rt *rt; 23497827cba2SAaron LI 23507827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 23517827cba2SAaron LI d6_state = D6_CSTATE(ifp); 23527827cba2SAaron LI if (d6_state && d6_state->state == dstate) { 23537827cba2SAaron LI TAILQ_FOREACH(addr, &d6_state->addrs, next) { 23547827cba2SAaron LI rt = inet6_makeprefix(ifp, NULL, addr); 23558d36e1dfSRoy Marples if (rt == NULL) 23568d36e1dfSRoy Marples continue; 23577827cba2SAaron LI rt->rt_dflags |= RTDF_DHCP; 23588d36e1dfSRoy Marples rt_proto_add(routes, rt); 23597827cba2SAaron LI } 23607827cba2SAaron LI } 23617827cba2SAaron LI } 23627827cba2SAaron LI return 0; 23637827cba2SAaron LI } 23648d36e1dfSRoy Marples #endif 23657827cba2SAaron LI 23667827cba2SAaron LI bool 23678d36e1dfSRoy Marples inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes) 23687827cba2SAaron LI { 23697827cba2SAaron LI 23707827cba2SAaron LI /* Should static take priority? */ 23717827cba2SAaron LI if (inet6_staticroutes(routes, ctx) == -1) 23727827cba2SAaron LI return false; 23737827cba2SAaron LI 23747827cba2SAaron LI /* First add reachable routers and their prefixes */ 23758d36e1dfSRoy Marples if (inet6_raroutes(routes, ctx) == -1) 23767827cba2SAaron LI return false; 23777827cba2SAaron LI 23788d36e1dfSRoy Marples #ifdef DHCP6 23797827cba2SAaron LI /* We have no way of knowing if prefixes added by DHCP are reachable 23807827cba2SAaron LI * or not, so we have to assume they are. 23818d36e1dfSRoy Marples * Add bound before delegated so we can prefer interfaces better. */ 23827827cba2SAaron LI if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1) 23837827cba2SAaron LI return false; 23847827cba2SAaron LI if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1) 23857827cba2SAaron LI return false; 23867827cba2SAaron LI #endif 23877827cba2SAaron LI 23887827cba2SAaron LI return true; 23897827cba2SAaron LI } 2390