1*8d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd - DHCP client daemon 4*8d36e1dfSRoy Marples * Copyright (c) 2006-2019 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 34*8d36e1dfSRoy 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> 607827cba2SAaron LI #include <unistd.h> 617827cba2SAaron LI 627827cba2SAaron LI #define ELOOP_QUEUE 7 637827cba2SAaron LI #include "common.h" 647827cba2SAaron LI #include "if.h" 657827cba2SAaron LI #include "dhcpcd.h" 667827cba2SAaron LI #include "dhcp6.h" 677827cba2SAaron LI #include "eloop.h" 687827cba2SAaron LI #include "ipv6.h" 697827cba2SAaron LI #include "ipv6nd.h" 707827cba2SAaron LI #include "logerr.h" 717827cba2SAaron LI #include "sa.h" 727827cba2SAaron LI #include "script.h" 737827cba2SAaron LI 747827cba2SAaron LI #ifdef HAVE_MD5_H 757827cba2SAaron LI # ifndef DEPGEN 767827cba2SAaron LI # include <md5.h> 777827cba2SAaron LI # endif 787827cba2SAaron LI #endif 797827cba2SAaron LI 807827cba2SAaron LI #ifdef SHA2_H 817827cba2SAaron LI # include SHA2_H 827827cba2SAaron LI #endif 837827cba2SAaron LI 847827cba2SAaron LI #ifndef SHA256_DIGEST_LENGTH 857827cba2SAaron LI # define SHA256_DIGEST_LENGTH 32 867827cba2SAaron LI #endif 877827cba2SAaron LI 887827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 897827cba2SAaron LI # warning kernel does not report IPv6 address flag changes 907827cba2SAaron LI # warning polling tentative address flags periodically 917827cba2SAaron LI #endif 927827cba2SAaron LI 937827cba2SAaron LI /* Hackery at it's finest. */ 947827cba2SAaron LI #ifndef s6_addr32 957827cba2SAaron LI # ifdef __sun 967827cba2SAaron LI # define s6_addr32 _S6_un._S6_u32 977827cba2SAaron LI # else 987827cba2SAaron LI # define s6_addr32 __u6_addr.__u6_addr32 997827cba2SAaron LI # endif 1007827cba2SAaron LI #endif 1017827cba2SAaron LI 1027827cba2SAaron LI #if defined(HAVE_IN6_ADDR_GEN_MODE_NONE) || defined(ND6_IFF_AUTO_LINKLOCAL) || \ 1037827cba2SAaron LI defined(IFF_NOLINKLOCAL) 1047827cba2SAaron LI /* Only add the LL address if we have a carrier, so DaD works. */ 1057827cba2SAaron LI #define CAN_ADD_LLADDR(ifp) \ 1067827cba2SAaron LI (!((ifp)->options->options & DHCPCD_LINK) || (ifp)->carrier != LINK_DOWN) 1077827cba2SAaron LI #ifdef __sun 1087827cba2SAaron LI /* Although we can add our own LL address, we cannot drop it 1097827cba2SAaron LI * without unplumbing the if which is a lot of code. 1107827cba2SAaron LI * So just keep it for the time being. */ 1117827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (0) 1127827cba2SAaron LI #else 1137827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (1) 1147827cba2SAaron LI #endif 1157827cba2SAaron LI #else 1167827cba2SAaron LI /* We have no control over the OS adding the LLADDR, so just let it do it 1177827cba2SAaron LI * as we cannot force our own view on it. */ 1187827cba2SAaron LI #define CAN_ADD_LLADDR(ifp) (0) 1197827cba2SAaron LI #define CAN_DROP_LLADDR(ifp) (0) 1207827cba2SAaron LI #endif 1217827cba2SAaron LI 1227827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 1237827cba2SAaron LI static void ipv6_regentempifid(void *); 1247827cba2SAaron LI static void ipv6_regentempaddr(void *); 1257827cba2SAaron LI #else 1267827cba2SAaron LI #define ipv6_regentempifid(a) {} 1277827cba2SAaron LI #endif 1287827cba2SAaron LI 1297827cba2SAaron LI int 1307827cba2SAaron LI ipv6_init(struct dhcpcd_ctx *ctx) 1317827cba2SAaron LI { 1327827cba2SAaron LI 133*8d36e1dfSRoy Marples if (ctx->ra_routers != NULL) 1347827cba2SAaron LI return 0; 1357827cba2SAaron LI 1367827cba2SAaron LI ctx->ra_routers = malloc(sizeof(*ctx->ra_routers)); 1377827cba2SAaron LI if (ctx->ra_routers == NULL) 1387827cba2SAaron LI return -1; 1397827cba2SAaron LI TAILQ_INIT(ctx->ra_routers); 1407827cba2SAaron LI 141*8d36e1dfSRoy Marples #ifndef __sun 1427827cba2SAaron LI ctx->nd_fd = -1; 143*8d36e1dfSRoy Marples #endif 1447827cba2SAaron LI ctx->dhcp6_fd = -1; 1457827cba2SAaron LI return 0; 1467827cba2SAaron LI } 1477827cba2SAaron LI 1487827cba2SAaron LI static ssize_t 1497827cba2SAaron LI ipv6_readsecret(struct dhcpcd_ctx *ctx) 1507827cba2SAaron LI { 1517827cba2SAaron LI FILE *fp; 1527827cba2SAaron LI char line[1024]; 1537827cba2SAaron LI unsigned char *p; 1547827cba2SAaron LI size_t len; 1557827cba2SAaron LI uint32_t r; 1567827cba2SAaron LI int x; 1577827cba2SAaron LI 1587827cba2SAaron LI if ((ctx->secret_len = read_hwaddr_aton(&ctx->secret, SECRET)) != 0) 1597827cba2SAaron LI return (ssize_t)ctx->secret_len; 1607827cba2SAaron LI 1617827cba2SAaron LI if (errno != ENOENT) 1627827cba2SAaron LI logerr("%s: %s", __func__, SECRET); 1637827cba2SAaron LI 1647827cba2SAaron LI /* Chaining arc4random should be good enough. 1657827cba2SAaron LI * RFC7217 section 5.1 states the key SHOULD be at least 128 bits. 1667827cba2SAaron LI * To attempt and future proof ourselves, we'll generate a key of 1677827cba2SAaron LI * 512 bits (64 bytes). */ 1687827cba2SAaron LI if (ctx->secret_len < 64) { 1697827cba2SAaron LI if ((ctx->secret = malloc(64)) == NULL) { 1707827cba2SAaron LI logerr(__func__); 1717827cba2SAaron LI return -1; 1727827cba2SAaron LI } 1737827cba2SAaron LI ctx->secret_len = 64; 1747827cba2SAaron LI } 1757827cba2SAaron LI p = ctx->secret; 1767827cba2SAaron LI for (len = 0; len < 512 / NBBY; len += sizeof(r)) { 1777827cba2SAaron LI r = arc4random(); 1787827cba2SAaron LI memcpy(p, &r, sizeof(r)); 1797827cba2SAaron LI p += sizeof(r); 1807827cba2SAaron LI } 1817827cba2SAaron LI 1827827cba2SAaron LI /* Ensure that only the dhcpcd user can read the secret. 1837827cba2SAaron LI * Write permission is also denied as chaning it would remove 1847827cba2SAaron LI * it's stability. */ 1857827cba2SAaron LI if ((fp = fopen(SECRET, "w")) == NULL || 1867827cba2SAaron LI chmod(SECRET, S_IRUSR) == -1) 1877827cba2SAaron LI goto eexit; 1887827cba2SAaron LI x = fprintf(fp, "%s\n", 1897827cba2SAaron LI hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line))); 1907827cba2SAaron LI if (fclose(fp) == EOF) 1917827cba2SAaron LI x = -1; 1927827cba2SAaron LI fp = NULL; 1937827cba2SAaron LI if (x > 0) 1947827cba2SAaron LI return (ssize_t)ctx->secret_len; 1957827cba2SAaron LI 1967827cba2SAaron LI eexit: 1977827cba2SAaron LI logerr("%s: %s", __func__, SECRET); 1987827cba2SAaron LI if (fp != NULL) 1997827cba2SAaron LI fclose(fp); 2007827cba2SAaron LI unlink(SECRET); 2017827cba2SAaron LI ctx->secret_len = 0; 2027827cba2SAaron LI return -1; 2037827cba2SAaron LI } 2047827cba2SAaron LI 2057827cba2SAaron LI /* http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml 2067827cba2SAaron LI * RFC5453 */ 2077827cba2SAaron LI static const struct reslowhigh { 2087827cba2SAaron LI const uint8_t high[8]; 2097827cba2SAaron LI const uint8_t low[8]; 2107827cba2SAaron LI } reslowhigh[] = { 2117827cba2SAaron LI /* RFC4291 + RFC6543 */ 2127827cba2SAaron LI { { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x00, 0x00 }, 2137827cba2SAaron LI { 0x02, 0x00, 0x5e, 0xff, 0xfe, 0xff, 0xff, 0xff } }, 2147827cba2SAaron LI /* RFC2526 */ 2157827cba2SAaron LI { { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }, 2167827cba2SAaron LI { 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } 2177827cba2SAaron LI }; 2187827cba2SAaron LI 2197827cba2SAaron LI static int 2207827cba2SAaron LI ipv6_reserved(const struct in6_addr *addr) 2217827cba2SAaron LI { 2227827cba2SAaron LI uint64_t id, low, high; 2237827cba2SAaron LI size_t i; 2247827cba2SAaron LI const struct reslowhigh *r; 2257827cba2SAaron LI 2267827cba2SAaron LI id = be64dec(addr->s6_addr + sizeof(id)); 2277827cba2SAaron LI if (id == 0) /* RFC4291 */ 2287827cba2SAaron LI return 1; 2297827cba2SAaron LI for (i = 0; i < sizeof(reslowhigh) / sizeof(reslowhigh[0]); i++) { 2307827cba2SAaron LI r = &reslowhigh[i]; 2317827cba2SAaron LI low = be64dec(r->low); 2327827cba2SAaron LI high = be64dec(r->high); 2337827cba2SAaron LI if (id >= low && id <= high) 2347827cba2SAaron LI return 1; 2357827cba2SAaron LI } 2367827cba2SAaron LI return 0; 2377827cba2SAaron LI } 2387827cba2SAaron LI 2397827cba2SAaron LI /* RFC7217 */ 2407827cba2SAaron LI static int 2417827cba2SAaron LI ipv6_makestableprivate1(struct in6_addr *addr, 2427827cba2SAaron LI const struct in6_addr *prefix, int prefix_len, 2437827cba2SAaron LI const unsigned char *netiface, size_t netiface_len, 2447827cba2SAaron LI const unsigned char *netid, size_t netid_len, 2457827cba2SAaron LI unsigned short vlanid, 2467827cba2SAaron LI uint32_t *dad_counter, 2477827cba2SAaron LI const unsigned char *secret, size_t secret_len) 2487827cba2SAaron LI { 2497827cba2SAaron LI unsigned char buf[2048], *p, digest[SHA256_DIGEST_LENGTH]; 2507827cba2SAaron LI size_t len, l; 2517827cba2SAaron LI SHA256_CTX ctx; 2527827cba2SAaron LI 2537827cba2SAaron LI if (prefix_len < 0 || prefix_len > 120) { 2547827cba2SAaron LI errno = EINVAL; 2557827cba2SAaron LI return -1; 2567827cba2SAaron LI } 2577827cba2SAaron LI 2587827cba2SAaron LI l = (size_t)(ROUNDUP8(prefix_len) / NBBY); 2597827cba2SAaron LI len = l + netiface_len + netid_len + sizeof(*dad_counter) + secret_len; 2607827cba2SAaron LI if (vlanid != 0) 2617827cba2SAaron LI len += sizeof(vlanid); 2627827cba2SAaron LI if (len > sizeof(buf)) { 2637827cba2SAaron LI errno = ENOBUFS; 2647827cba2SAaron LI return -1; 2657827cba2SAaron LI } 2667827cba2SAaron LI 2677827cba2SAaron LI for (;; (*dad_counter)++) { 2687827cba2SAaron LI /* Combine all parameters into one buffer */ 2697827cba2SAaron LI p = buf; 2707827cba2SAaron LI memcpy(p, prefix, l); 2717827cba2SAaron LI p += l; 2727827cba2SAaron LI memcpy(p, netiface, netiface_len); 2737827cba2SAaron LI p += netiface_len; 2747827cba2SAaron LI memcpy(p, netid, netid_len); 2757827cba2SAaron LI p += netid_len; 2767827cba2SAaron LI /* Don't use a vlanid if not set. 2777827cba2SAaron LI * This ensures prior versions have the same unique address. */ 2787827cba2SAaron LI if (vlanid != 0) { 2797827cba2SAaron LI memcpy(p, &vlanid, sizeof(vlanid)); 2807827cba2SAaron LI p += sizeof(vlanid); 2817827cba2SAaron LI } 2827827cba2SAaron LI memcpy(p, dad_counter, sizeof(*dad_counter)); 2837827cba2SAaron LI p += sizeof(*dad_counter); 2847827cba2SAaron LI memcpy(p, secret, secret_len); 2857827cba2SAaron LI 2867827cba2SAaron LI /* Make an address using the digest of the above. 2877827cba2SAaron LI * RFC7217 Section 5.1 states that we shouldn't use MD5. 2887827cba2SAaron LI * Pity as we use that for HMAC-MD5 which is still deemed OK. 2897827cba2SAaron LI * SHA-256 is recommended */ 2907827cba2SAaron LI SHA256_Init(&ctx); 2917827cba2SAaron LI SHA256_Update(&ctx, buf, len); 2927827cba2SAaron LI SHA256_Final(digest, &ctx); 2937827cba2SAaron LI 2947827cba2SAaron LI p = addr->s6_addr; 2957827cba2SAaron LI memcpy(p, prefix, l); 2967827cba2SAaron LI /* RFC7217 section 5.2 says we need to start taking the id from 2977827cba2SAaron LI * the least significant bit */ 2987827cba2SAaron LI len = sizeof(addr->s6_addr) - l; 2997827cba2SAaron LI memcpy(p + l, digest + (sizeof(digest) - len), len); 3007827cba2SAaron LI 3017827cba2SAaron LI /* Ensure that the Interface ID does not match a reserved one, 3027827cba2SAaron LI * if it does then treat it as a DAD failure. 3037827cba2SAaron LI * RFC7217 section 5.2 */ 3047827cba2SAaron LI if (prefix_len != 64) 3057827cba2SAaron LI break; 3067827cba2SAaron LI if (!ipv6_reserved(addr)) 3077827cba2SAaron LI break; 3087827cba2SAaron LI } 3097827cba2SAaron LI 3107827cba2SAaron LI return 0; 3117827cba2SAaron LI } 3127827cba2SAaron LI 3137827cba2SAaron LI int 3147827cba2SAaron LI ipv6_makestableprivate(struct in6_addr *addr, 3157827cba2SAaron LI const struct in6_addr *prefix, int prefix_len, 3167827cba2SAaron LI const struct interface *ifp, 3177827cba2SAaron LI int *dad_counter) 3187827cba2SAaron LI { 3197827cba2SAaron LI uint32_t dad; 3207827cba2SAaron LI int r; 3217827cba2SAaron LI 3227827cba2SAaron LI if (ifp->ctx->secret_len == 0) { 3237827cba2SAaron LI if (ipv6_readsecret(ifp->ctx) == -1) 3247827cba2SAaron LI return -1; 3257827cba2SAaron LI } 3267827cba2SAaron LI 3277827cba2SAaron LI dad = (uint32_t)*dad_counter; 3287827cba2SAaron LI 3297827cba2SAaron LI /* For our implementation, we shall set the hardware address 3307827cba2SAaron LI * as the interface identifier */ 3317827cba2SAaron LI r = ipv6_makestableprivate1(addr, prefix, prefix_len, 3327827cba2SAaron LI ifp->hwaddr, ifp->hwlen, 3337827cba2SAaron LI ifp->ssid, ifp->ssid_len, 3347827cba2SAaron LI ifp->vlanid, &dad, 3357827cba2SAaron LI ifp->ctx->secret, ifp->ctx->secret_len); 3367827cba2SAaron LI 3377827cba2SAaron LI if (r == 0) 3387827cba2SAaron LI *dad_counter = (int)dad; 3397827cba2SAaron LI return r; 3407827cba2SAaron LI } 3417827cba2SAaron LI 3427827cba2SAaron LI int 3437827cba2SAaron LI ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp, 3447827cba2SAaron LI const struct in6_addr *prefix, int prefix_len) 3457827cba2SAaron LI { 3467827cba2SAaron LI const struct ipv6_addr *ap; 3477827cba2SAaron LI int dad; 3487827cba2SAaron LI 3497827cba2SAaron LI if (prefix_len < 0 || prefix_len > 120) { 3507827cba2SAaron LI errno = EINVAL; 3517827cba2SAaron LI return -1; 3527827cba2SAaron LI } 3537827cba2SAaron LI 3547827cba2SAaron LI if (ifp->options->options & DHCPCD_SLAACPRIVATE) { 3557827cba2SAaron LI dad = 0; 3567827cba2SAaron LI if (ipv6_makestableprivate(addr, 3577827cba2SAaron LI prefix, prefix_len, ifp, &dad) == -1) 3587827cba2SAaron LI return -1; 3597827cba2SAaron LI return dad; 3607827cba2SAaron LI } 3617827cba2SAaron LI 3627827cba2SAaron LI if (prefix_len > 64) { 3637827cba2SAaron LI errno = EINVAL; 3647827cba2SAaron LI return -1; 3657827cba2SAaron LI } 3667827cba2SAaron LI if ((ap = ipv6_linklocal(ifp)) == NULL) { 3677827cba2SAaron LI /* We delay a few functions until we get a local-link address 3687827cba2SAaron LI * so this should never be hit. */ 3697827cba2SAaron LI errno = ENOENT; 3707827cba2SAaron LI return -1; 3717827cba2SAaron LI } 3727827cba2SAaron LI 3737827cba2SAaron LI /* Make the address from the first local-link address */ 3747827cba2SAaron LI memcpy(addr, prefix, sizeof(*prefix)); 3757827cba2SAaron LI addr->s6_addr32[2] = ap->addr.s6_addr32[2]; 3767827cba2SAaron LI addr->s6_addr32[3] = ap->addr.s6_addr32[3]; 3777827cba2SAaron LI return 0; 3787827cba2SAaron LI } 3797827cba2SAaron LI 3807827cba2SAaron LI static int 3817827cba2SAaron LI ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len) 3827827cba2SAaron LI { 3837827cba2SAaron LI int bytes, bits; 3847827cba2SAaron LI 3857827cba2SAaron LI if (len < 0 || len > 128) { 3867827cba2SAaron LI errno = EINVAL; 3877827cba2SAaron LI return -1; 3887827cba2SAaron LI } 3897827cba2SAaron LI 3907827cba2SAaron LI bytes = len / NBBY; 3917827cba2SAaron LI bits = len % NBBY; 3927827cba2SAaron LI memcpy(&prefix->s6_addr, &addr->s6_addr, (size_t)bytes); 3937827cba2SAaron LI if (bits != 0) { 3947827cba2SAaron LI /* Coverify false positive. 3957827cba2SAaron LI * bytelen cannot be 16 if bitlen is non zero */ 3967827cba2SAaron LI /* coverity[overrun-local] */ 3977827cba2SAaron LI prefix->s6_addr[bytes] = 3987827cba2SAaron LI (uint8_t)(prefix->s6_addr[bytes] >> (NBBY - bits)); 3997827cba2SAaron LI } 4007827cba2SAaron LI memset((char *)prefix->s6_addr + bytes, 0, 4017827cba2SAaron LI sizeof(prefix->s6_addr) - (size_t)bytes); 4027827cba2SAaron LI return 0; 4037827cba2SAaron LI } 4047827cba2SAaron LI 4057827cba2SAaron LI int 4067827cba2SAaron LI ipv6_mask(struct in6_addr *mask, int len) 4077827cba2SAaron LI { 4087827cba2SAaron LI static const unsigned char masks[NBBY] = 4097827cba2SAaron LI { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 4107827cba2SAaron LI int bytes, bits, i; 4117827cba2SAaron LI 4127827cba2SAaron LI if (len < 0 || len > 128) { 4137827cba2SAaron LI errno = EINVAL; 4147827cba2SAaron LI return -1; 4157827cba2SAaron LI } 4167827cba2SAaron LI 4177827cba2SAaron LI memset(mask, 0, sizeof(*mask)); 4187827cba2SAaron LI bytes = len / NBBY; 4197827cba2SAaron LI bits = len % NBBY; 4207827cba2SAaron LI for (i = 0; i < bytes; i++) 4217827cba2SAaron LI mask->s6_addr[i] = 0xff; 4227827cba2SAaron LI if (bits != 0) { 4237827cba2SAaron LI /* Coverify false positive. 4247827cba2SAaron LI * bytelen cannot be 16 if bitlen is non zero */ 4257827cba2SAaron LI /* coverity[overrun-local] */ 4267827cba2SAaron LI mask->s6_addr[bytes] = masks[bits - 1]; 4277827cba2SAaron LI } 4287827cba2SAaron LI return 0; 4297827cba2SAaron LI } 4307827cba2SAaron LI 4317827cba2SAaron LI uint8_t 4327827cba2SAaron LI ipv6_prefixlen(const struct in6_addr *mask) 4337827cba2SAaron LI { 4347827cba2SAaron LI int x = 0, y; 4357827cba2SAaron LI const unsigned char *lim, *p; 4367827cba2SAaron LI 4377827cba2SAaron LI lim = (const unsigned char *)mask + sizeof(*mask); 4387827cba2SAaron LI for (p = (const unsigned char *)mask; p < lim; x++, p++) { 4397827cba2SAaron LI if (*p != 0xff) 4407827cba2SAaron LI break; 4417827cba2SAaron LI } 4427827cba2SAaron LI y = 0; 4437827cba2SAaron LI if (p < lim) { 4447827cba2SAaron LI for (y = 0; y < NBBY; y++) { 4457827cba2SAaron LI if ((*p & (0x80 >> y)) == 0) 4467827cba2SAaron LI break; 4477827cba2SAaron LI } 4487827cba2SAaron LI } 4497827cba2SAaron LI 4507827cba2SAaron LI /* 4517827cba2SAaron LI * when the limit pointer is given, do a stricter check on the 4527827cba2SAaron LI * remaining bits. 4537827cba2SAaron LI */ 4547827cba2SAaron LI if (p < lim) { 4557827cba2SAaron LI if (y != 0 && (*p & (0x00ff >> y)) != 0) 4567827cba2SAaron LI return 0; 4577827cba2SAaron LI for (p = p + 1; p < lim; p++) 4587827cba2SAaron LI if (*p != 0) 4597827cba2SAaron LI return 0; 4607827cba2SAaron LI } 4617827cba2SAaron LI 4627827cba2SAaron LI return (uint8_t)(x * NBBY + y); 4637827cba2SAaron LI } 4647827cba2SAaron LI 4657827cba2SAaron LI static void 4667827cba2SAaron LI in6_to_h64(uint64_t *vhigh, uint64_t *vlow, const struct in6_addr *addr) 4677827cba2SAaron LI { 4687827cba2SAaron LI 4697827cba2SAaron LI *vhigh = be64dec(addr->s6_addr); 4707827cba2SAaron LI *vlow = be64dec(addr->s6_addr + 8); 4717827cba2SAaron LI } 4727827cba2SAaron LI 4737827cba2SAaron LI static void 4747827cba2SAaron LI h64_to_in6(struct in6_addr *addr, uint64_t vhigh, uint64_t vlow) 4757827cba2SAaron LI { 4767827cba2SAaron LI 4777827cba2SAaron LI be64enc(addr->s6_addr, vhigh); 4787827cba2SAaron LI be64enc(addr->s6_addr + 8, vlow); 4797827cba2SAaron LI } 4807827cba2SAaron LI 4817827cba2SAaron LI int 4827827cba2SAaron LI ipv6_userprefix( 4837827cba2SAaron LI const struct in6_addr *prefix, // prefix from router 4847827cba2SAaron LI short prefix_len, // length of prefix received 4857827cba2SAaron LI uint64_t user_number, // "random" number from user 4867827cba2SAaron LI struct in6_addr *result, // resultant prefix 4877827cba2SAaron LI short result_len) // desired prefix length 4887827cba2SAaron LI { 4897827cba2SAaron LI uint64_t vh, vl, user_low, user_high; 4907827cba2SAaron LI 4917827cba2SAaron LI if (prefix_len < 1 || prefix_len > 128 || 4927827cba2SAaron LI result_len < 1 || result_len > 128) 4937827cba2SAaron LI { 4947827cba2SAaron LI errno = EINVAL; 4957827cba2SAaron LI return -1; 4967827cba2SAaron LI } 4977827cba2SAaron LI 4987827cba2SAaron LI /* Check that the user_number fits inside result_len less prefix_len */ 4997827cba2SAaron LI if (result_len < prefix_len || 5007827cba2SAaron LI fls64(user_number) > result_len - prefix_len) 5017827cba2SAaron LI { 5027827cba2SAaron LI errno = ERANGE; 5037827cba2SAaron LI return -1; 5047827cba2SAaron LI } 5057827cba2SAaron LI 5067827cba2SAaron LI /* If user_number is zero, just copy the prefix into the result. */ 5077827cba2SAaron LI if (user_number == 0) { 5087827cba2SAaron LI *result = *prefix; 5097827cba2SAaron LI return 0; 5107827cba2SAaron LI } 5117827cba2SAaron LI 5127827cba2SAaron LI /* Shift user_number so it fit's just inside result_len. 5137827cba2SAaron LI * Shifting by 0 or sizeof(user_number) is undefined, 5147827cba2SAaron LI * so we cater for that. */ 5157827cba2SAaron LI if (result_len == 128) { 5167827cba2SAaron LI user_high = 0; 5177827cba2SAaron LI user_low = user_number; 5187827cba2SAaron LI } else if (result_len > 64) { 5197827cba2SAaron LI if (prefix_len >= 64) 5207827cba2SAaron LI user_high = 0; 5217827cba2SAaron LI else 5227827cba2SAaron LI user_high = user_number >> (result_len - prefix_len); 5237827cba2SAaron LI user_low = user_number << (128 - result_len); 5247827cba2SAaron LI } else if (result_len == 64) { 5257827cba2SAaron LI user_high = user_number; 5267827cba2SAaron LI user_low = 0; 5277827cba2SAaron LI } else { 5287827cba2SAaron LI user_high = user_number << (64 - result_len); 5297827cba2SAaron LI user_low = 0; 5307827cba2SAaron LI } 5317827cba2SAaron LI 5327827cba2SAaron LI /* convert to two 64bit host order values */ 5337827cba2SAaron LI in6_to_h64(&vh, &vl, prefix); 5347827cba2SAaron LI 5357827cba2SAaron LI vh |= user_high; 5367827cba2SAaron LI vl |= user_low; 5377827cba2SAaron LI 5387827cba2SAaron LI /* copy back result */ 5397827cba2SAaron LI h64_to_in6(result, vh, vl); 5407827cba2SAaron LI 5417827cba2SAaron LI return 0; 5427827cba2SAaron LI } 5437827cba2SAaron LI 5447827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 5457827cba2SAaron LI void 5467827cba2SAaron LI ipv6_checkaddrflags(void *arg) 5477827cba2SAaron LI { 5487827cba2SAaron LI struct ipv6_addr *ia; 5497827cba2SAaron LI int flags; 5507827cba2SAaron LI const char *alias; 5517827cba2SAaron LI 5527827cba2SAaron LI ia = arg; 5537827cba2SAaron LI #ifdef ALIAS_ADDR 5547827cba2SAaron LI alias = ia->alias; 5557827cba2SAaron LI #else 5567827cba2SAaron LI alias = NULL; 5577827cba2SAaron LI #endif 5587827cba2SAaron LI if ((flags = if_addrflags6(ia->iface, &ia->addr, alias)) == -1) { 5597827cba2SAaron LI if (errno != EEXIST && errno != EADDRNOTAVAIL) 5607827cba2SAaron LI logerr("%s: if_addrflags6", __func__); 5617827cba2SAaron LI return; 5627827cba2SAaron LI } 5637827cba2SAaron LI 5647827cba2SAaron LI if (!(flags & IN6_IFF_TENTATIVE)) { 5657827cba2SAaron LI /* Simulate the kernel announcing the new address. */ 5667827cba2SAaron LI ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR, 5677827cba2SAaron LI ia->iface->ctx->ifaces, ia->iface->name, 5687827cba2SAaron LI &ia->addr, ia->prefix_len, flags, 0); 5697827cba2SAaron LI } else { 5707827cba2SAaron LI /* Still tentative? Check again in a bit. */ 5717827cba2SAaron LI struct timespec tv; 5727827cba2SAaron LI 5737827cba2SAaron LI ms_to_ts(&tv, RETRANS_TIMER / 2); 5747827cba2SAaron LI eloop_timeout_add_tv(ia->iface->ctx->eloop, &tv, 5757827cba2SAaron LI ipv6_checkaddrflags, ia); 5767827cba2SAaron LI } 5777827cba2SAaron LI } 5787827cba2SAaron LI #endif 5797827cba2SAaron LI 5807827cba2SAaron LI static void 5817827cba2SAaron LI ipv6_deletedaddr(struct ipv6_addr *ia) 5827827cba2SAaron LI { 5837827cba2SAaron LI 5847827cba2SAaron LI #ifdef SMALL 5857827cba2SAaron LI UNUSED(ia); 5867827cba2SAaron LI #else 5877827cba2SAaron LI /* NOREJECT is set if we delegated exactly the prefix to another 5887827cba2SAaron LI * address. 5897827cba2SAaron LI * This can only be one address, so just clear the flag. 5907827cba2SAaron LI * This should ensure the reject route will be restored. */ 5917827cba2SAaron LI if (ia->delegating_prefix != NULL) 5927827cba2SAaron LI ia->delegating_prefix->flags &= ~IPV6_AF_NOREJECT; 5937827cba2SAaron LI #endif 5947827cba2SAaron LI } 5957827cba2SAaron LI 5967827cba2SAaron LI void 5977827cba2SAaron LI ipv6_deleteaddr(struct ipv6_addr *ia) 5987827cba2SAaron LI { 5997827cba2SAaron LI struct ipv6_state *state; 6007827cba2SAaron LI struct ipv6_addr *ap; 6017827cba2SAaron LI 6027827cba2SAaron LI loginfox("%s: deleting address %s", ia->iface->name, ia->saddr); 6037827cba2SAaron LI if (if_address6(RTM_DELADDR, ia) == -1 && 6047827cba2SAaron LI errno != EADDRNOTAVAIL && errno != ESRCH && 6057827cba2SAaron LI errno != ENXIO && errno != ENODEV) 6067827cba2SAaron LI logerr(__func__); 6077827cba2SAaron LI 6087827cba2SAaron LI ipv6_deletedaddr(ia); 6097827cba2SAaron LI 6107827cba2SAaron LI state = IPV6_STATE(ia->iface); 6117827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) { 6127827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ia->addr)) { 6137827cba2SAaron LI TAILQ_REMOVE(&state->addrs, ap, next); 6147827cba2SAaron LI ipv6_freeaddr(ap); 6157827cba2SAaron LI break; 6167827cba2SAaron LI } 6177827cba2SAaron LI } 618*8d36e1dfSRoy Marples 619*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 620*8d36e1dfSRoy Marples /* Advertise the address if it exists on another interface. */ 621*8d36e1dfSRoy Marples ipv6nd_advertise(ia); 622*8d36e1dfSRoy Marples #endif 6237827cba2SAaron LI } 6247827cba2SAaron LI 6257827cba2SAaron LI static int 6267827cba2SAaron LI ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now) 6277827cba2SAaron LI { 6287827cba2SAaron LI struct interface *ifp; 6297827cba2SAaron LI uint32_t pltime, vltime; 6307827cba2SAaron LI __printflike(1, 2) void (*logfunc)(const char *, ...); 631*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 632*8d36e1dfSRoy Marples bool vltime_was_zero = ia->prefix_vltime == 0; 633*8d36e1dfSRoy Marples #endif 634*8d36e1dfSRoy Marples #ifdef __sun 635*8d36e1dfSRoy Marples struct ipv6_state *state; 636*8d36e1dfSRoy Marples struct ipv6_addr *ia2; 6377827cba2SAaron LI 638*8d36e1dfSRoy Marples /* If we re-add then address on Solaris then the prefix 639*8d36e1dfSRoy Marples * route will be scrubbed and re-added. Something might 640*8d36e1dfSRoy Marples * be using it, so let's avoid it. */ 641*8d36e1dfSRoy Marples if (ia->flags & IPV6_AF_DADCOMPLETED) { 642*8d36e1dfSRoy Marples logdebugx("%s: IP address %s already exists", 643*8d36e1dfSRoy Marples ia->iface->name, ia->saddr); 644*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 645*8d36e1dfSRoy Marples goto advertise; 646*8d36e1dfSRoy Marples #else 647*8d36e1dfSRoy Marples return 0; 648*8d36e1dfSRoy Marples #endif 6497827cba2SAaron LI } 650*8d36e1dfSRoy Marples #endif 6517827cba2SAaron LI 6527827cba2SAaron LI /* Remember the interface of the address. */ 6537827cba2SAaron LI ifp = ia->iface; 6547827cba2SAaron LI 6557827cba2SAaron LI if (!(ia->flags & IPV6_AF_DADCOMPLETED) && 6567827cba2SAaron LI ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE)) 6577827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED; 6587827cba2SAaron LI 6597827cba2SAaron LI /* Adjust plftime and vltime based on acquired time */ 6607827cba2SAaron LI pltime = ia->prefix_pltime; 6617827cba2SAaron LI vltime = ia->prefix_vltime; 6627827cba2SAaron LI if (timespecisset(&ia->acquired) && 6637827cba2SAaron LI (ia->prefix_pltime != ND6_INFINITE_LIFETIME || 6647827cba2SAaron LI ia->prefix_vltime != ND6_INFINITE_LIFETIME)) 6657827cba2SAaron LI { 6667827cba2SAaron LI struct timespec n; 6677827cba2SAaron LI 6687827cba2SAaron LI if (now == NULL) { 6697827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &n); 6707827cba2SAaron LI now = &n; 6717827cba2SAaron LI } 6727827cba2SAaron LI timespecsub(now, &ia->acquired, &n); 6737827cba2SAaron LI if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) { 6747827cba2SAaron LI ia->prefix_pltime -= (uint32_t)n.tv_sec; 6757827cba2SAaron LI /* This can happen when confirming a 6767827cba2SAaron LI * deprecated but still valid lease. */ 6777827cba2SAaron LI if (ia->prefix_pltime > pltime) 6787827cba2SAaron LI ia->prefix_pltime = 0; 6797827cba2SAaron LI } 6807827cba2SAaron LI if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) { 6817827cba2SAaron LI ia->prefix_vltime -= (uint32_t)n.tv_sec; 6827827cba2SAaron LI /* This should never happen. */ 6837827cba2SAaron LI if (ia->prefix_vltime > vltime) { 6847827cba2SAaron LI logerrx("%s: %s: lifetime overflow", 6857827cba2SAaron LI ifp->name, ia->saddr); 6867827cba2SAaron LI ia->prefix_vltime = ia->prefix_pltime = 0; 6877827cba2SAaron LI } 6887827cba2SAaron LI } 6897827cba2SAaron LI } 6907827cba2SAaron LI 6917827cba2SAaron LI logfunc = ia->flags & IPV6_AF_NEW ? loginfox : logdebugx; 6927827cba2SAaron LI logfunc("%s: adding %saddress %s", ifp->name, 6937827cba2SAaron LI #ifdef IPV6_AF_TEMPORARY 6947827cba2SAaron LI ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "", 6957827cba2SAaron LI #else 6967827cba2SAaron LI "", 6977827cba2SAaron LI #endif 6987827cba2SAaron LI ia->saddr); 6997827cba2SAaron LI if (ia->prefix_pltime == ND6_INFINITE_LIFETIME && 7007827cba2SAaron LI ia->prefix_vltime == ND6_INFINITE_LIFETIME) 7017827cba2SAaron LI logdebugx("%s: pltime infinity, vltime infinity", 7027827cba2SAaron LI ifp->name); 7037827cba2SAaron LI else if (ia->prefix_pltime == ND6_INFINITE_LIFETIME) 7047827cba2SAaron LI logdebugx("%s: pltime infinity, vltime %"PRIu32" seconds", 7057827cba2SAaron LI ifp->name, ia->prefix_vltime); 7067827cba2SAaron LI else if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) 7077827cba2SAaron LI logdebugx("%s: pltime %"PRIu32"seconds, vltime infinity", 7087827cba2SAaron LI ifp->name, ia->prefix_pltime); 7097827cba2SAaron LI else 7107827cba2SAaron LI logdebugx("%s: pltime %"PRIu32" seconds, vltime %"PRIu32 7117827cba2SAaron LI " seconds", 7127827cba2SAaron LI ifp->name, ia->prefix_pltime, ia->prefix_vltime); 7137827cba2SAaron LI 7147827cba2SAaron LI if (if_address6(RTM_NEWADDR, ia) == -1) { 7157827cba2SAaron LI logerr(__func__); 7167827cba2SAaron LI /* Restore real pltime and vltime */ 7177827cba2SAaron LI ia->prefix_pltime = pltime; 7187827cba2SAaron LI ia->prefix_vltime = vltime; 7197827cba2SAaron LI return -1; 7207827cba2SAaron LI } 7217827cba2SAaron LI 7227827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 7237827cba2SAaron LI /* RFC4941 Section 3.4 */ 7247827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY && 7257827cba2SAaron LI ia->prefix_pltime && 7267827cba2SAaron LI ia->prefix_vltime && 7277827cba2SAaron LI ip6_use_tempaddr(ifp->name)) 7287827cba2SAaron LI eloop_timeout_add_sec(ifp->ctx->eloop, 7297827cba2SAaron LI (time_t)ia->prefix_pltime - REGEN_ADVANCE, 7307827cba2SAaron LI ipv6_regentempaddr, ia); 7317827cba2SAaron LI #endif 7327827cba2SAaron LI 7337827cba2SAaron LI /* Restore real pltime and vltime */ 7347827cba2SAaron LI ia->prefix_pltime = pltime; 7357827cba2SAaron LI ia->prefix_vltime = vltime; 7367827cba2SAaron LI 7377827cba2SAaron LI ia->flags &= ~IPV6_AF_NEW; 7387827cba2SAaron LI ia->flags |= IPV6_AF_ADDED; 7397827cba2SAaron LI #ifndef SMALL 7407827cba2SAaron LI if (ia->delegating_prefix != NULL) 7417827cba2SAaron LI ia->flags |= IPV6_AF_DELEGATED; 7427827cba2SAaron LI #endif 7437827cba2SAaron LI 7447827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 7457827cba2SAaron LI eloop_timeout_delete(ifp->ctx->eloop, 7467827cba2SAaron LI ipv6_checkaddrflags, ia); 7477827cba2SAaron LI if (!(ia->flags & IPV6_AF_DADCOMPLETED)) { 7487827cba2SAaron LI struct timespec tv; 7497827cba2SAaron LI 7507827cba2SAaron LI ms_to_ts(&tv, RETRANS_TIMER / 2); 7517827cba2SAaron LI eloop_timeout_add_tv(ifp->ctx->eloop, 7527827cba2SAaron LI &tv, ipv6_checkaddrflags, ia); 7537827cba2SAaron LI } 7547827cba2SAaron LI #endif 7557827cba2SAaron LI 7567827cba2SAaron LI #ifdef __sun 7577827cba2SAaron LI /* Solaris does not announce new addresses which need DaD 7587827cba2SAaron LI * so we need to take a copy and add it to our list. 7597827cba2SAaron LI * Otherwise aliasing gets confused if we add another 7607827cba2SAaron LI * address during DaD. */ 7617827cba2SAaron LI 7627827cba2SAaron LI state = IPV6_STATE(ifp); 7637827cba2SAaron LI TAILQ_FOREACH(ia2, &state->addrs, next) { 7647827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr)) 7657827cba2SAaron LI break; 7667827cba2SAaron LI } 7677827cba2SAaron LI if (ia2 == NULL) { 7687827cba2SAaron LI if ((ia2 = malloc(sizeof(*ia2))) == NULL) { 7697827cba2SAaron LI logerr(__func__); 7707827cba2SAaron LI return 0; /* Well, we did add the address */ 7717827cba2SAaron LI } 7727827cba2SAaron LI memcpy(ia2, ia, sizeof(*ia2)); 7737827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia2, next); 7747827cba2SAaron LI } 7757827cba2SAaron LI #endif 7767827cba2SAaron LI 777*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 778*8d36e1dfSRoy Marples #ifdef __sun 779*8d36e1dfSRoy Marples advertise: 780*8d36e1dfSRoy Marples #endif 781*8d36e1dfSRoy Marples /* Re-advertise the preferred address to be safe. */ 782*8d36e1dfSRoy Marples if (!vltime_was_zero) 783*8d36e1dfSRoy Marples ipv6nd_advertise(ia); 784*8d36e1dfSRoy Marples #endif 785*8d36e1dfSRoy Marples 7867827cba2SAaron LI return 0; 7877827cba2SAaron LI } 7887827cba2SAaron LI 7897827cba2SAaron LI #ifdef ALIAS_ADDR 790*8d36e1dfSRoy Marples /* Find the next logical alias address we can use. */ 7917827cba2SAaron LI static int 7927827cba2SAaron LI ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl) 7937827cba2SAaron LI { 7947827cba2SAaron LI struct ipv6_state *state; 7957827cba2SAaron LI struct ipv6_addr *iap; 796*8d36e1dfSRoy Marples unsigned int lun; 7977827cba2SAaron LI char alias[IF_NAMESIZE]; 7987827cba2SAaron LI 7997827cba2SAaron LI if (ia->alias[0] != '\0') 8007827cba2SAaron LI return 0; 8017827cba2SAaron LI state = IPV6_STATE(ia->iface); 8027827cba2SAaron LI 8037827cba2SAaron LI /* First find an existng address. 8047827cba2SAaron LI * This can happen when dhcpcd restarts as ND and DHCPv6 8057827cba2SAaron LI * maintain their own lists of addresses. */ 8067827cba2SAaron LI TAILQ_FOREACH(iap, &state->addrs, next) { 8077827cba2SAaron LI if (iap->alias[0] != '\0' && 8087827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr)) 8097827cba2SAaron LI { 8107827cba2SAaron LI strlcpy(ia->alias, iap->alias, sizeof(ia->alias)); 8117827cba2SAaron LI return 0; 8127827cba2SAaron LI } 8137827cba2SAaron LI } 8147827cba2SAaron LI 815*8d36e1dfSRoy Marples lun = 0; 8167827cba2SAaron LI find_unit: 817*8d36e1dfSRoy Marples if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >= 818*8d36e1dfSRoy Marples IF_NAMESIZE) 819*8d36e1dfSRoy Marples { 820*8d36e1dfSRoy Marples errno = ENOMEM; 821*8d36e1dfSRoy Marples return -1; 822*8d36e1dfSRoy Marples } 8237827cba2SAaron LI TAILQ_FOREACH(iap, &state->addrs, next) { 8247827cba2SAaron LI if (iap->alias[0] == '\0') 8257827cba2SAaron LI continue; 8267827cba2SAaron LI if (IN6_IS_ADDR_UNSPECIFIED(&iap->addr)) { 8277827cba2SAaron LI /* No address assigned? Lets use it. */ 8287827cba2SAaron LI strlcpy(ia->alias, iap->alias, sizeof(ia->alias)); 8297827cba2SAaron LI if (repl) 8307827cba2SAaron LI *repl = iap; 8317827cba2SAaron LI return 1; 8327827cba2SAaron LI } 8337827cba2SAaron LI if (strcmp(iap->alias, alias) == 0) 8347827cba2SAaron LI break; 8357827cba2SAaron LI } 8367827cba2SAaron LI 8377827cba2SAaron LI if (iap != NULL) { 838*8d36e1dfSRoy Marples if (lun == UINT_MAX) { 8397827cba2SAaron LI errno = ERANGE; 8407827cba2SAaron LI return -1; 8417827cba2SAaron LI } 842*8d36e1dfSRoy Marples lun++; 8437827cba2SAaron LI goto find_unit; 8447827cba2SAaron LI } 8457827cba2SAaron LI 8467827cba2SAaron LI strlcpy(ia->alias, alias, sizeof(ia->alias)); 8477827cba2SAaron LI return 0; 8487827cba2SAaron LI } 8497827cba2SAaron LI #endif 8507827cba2SAaron LI 8517827cba2SAaron LI int 8527827cba2SAaron LI ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now) 8537827cba2SAaron LI { 8547827cba2SAaron LI int r; 8557827cba2SAaron LI #ifdef ALIAS_ADDR 8567827cba2SAaron LI int replaced, blank; 8577827cba2SAaron LI struct ipv6_addr *replaced_ia; 8587827cba2SAaron LI 8597827cba2SAaron LI blank = (ia->alias[0] == '\0'); 8607827cba2SAaron LI if ((replaced = ipv6_aliasaddr(ia, &replaced_ia)) == -1) 8617827cba2SAaron LI return -1; 8627827cba2SAaron LI if (blank) 8637827cba2SAaron LI logdebugx("%s: aliased %s", ia->alias, ia->saddr); 8647827cba2SAaron LI #endif 8657827cba2SAaron LI 8667827cba2SAaron LI if ((r = ipv6_addaddr1(ia, now)) == 0) { 8677827cba2SAaron LI #ifdef ALIAS_ADDR 8687827cba2SAaron LI if (replaced) { 8697827cba2SAaron LI struct ipv6_state *state; 8707827cba2SAaron LI 8717827cba2SAaron LI state = IPV6_STATE(ia->iface); 8727827cba2SAaron LI TAILQ_REMOVE(&state->addrs, replaced_ia, next); 8737827cba2SAaron LI ipv6_freeaddr(replaced_ia); 8747827cba2SAaron LI } 8757827cba2SAaron LI #endif 8767827cba2SAaron LI } 8777827cba2SAaron LI return r; 8787827cba2SAaron LI } 8797827cba2SAaron LI 8807827cba2SAaron LI int 8817827cba2SAaron LI ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match, 8827827cba2SAaron LI unsigned int flags) 8837827cba2SAaron LI { 8847827cba2SAaron LI 8857827cba2SAaron LI if (match == NULL) { 8867827cba2SAaron LI if ((addr->flags & 8877827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) == 8887827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) 8897827cba2SAaron LI return 1; 8907827cba2SAaron LI } else if (addr->prefix_vltime && 8917827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&addr->addr, match) && 8927827cba2SAaron LI (!flags || addr->flags & flags)) 8937827cba2SAaron LI return 1; 8947827cba2SAaron LI 8957827cba2SAaron LI return 0; 8967827cba2SAaron LI } 8977827cba2SAaron LI 8987827cba2SAaron LI struct ipv6_addr * 8997827cba2SAaron LI ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags) 9007827cba2SAaron LI { 901*8d36e1dfSRoy Marples struct ipv6_addr *nap; 902*8d36e1dfSRoy Marples #ifdef DHCP6 903*8d36e1dfSRoy Marples struct ipv6_addr *dap; 904*8d36e1dfSRoy Marples #endif 9057827cba2SAaron LI 9067827cba2SAaron LI nap = ipv6nd_findaddr(ctx, addr, flags); 907*8d36e1dfSRoy Marples #ifdef DHCP6 908*8d36e1dfSRoy Marples dap = dhcp6_findaddr(ctx, addr, flags); 9097827cba2SAaron LI if (!dap && !nap) 9107827cba2SAaron LI return NULL; 9117827cba2SAaron LI if (dap && !nap) 9127827cba2SAaron LI return dap; 9137827cba2SAaron LI if (nap && !dap) 9147827cba2SAaron LI return nap; 9157827cba2SAaron LI if (nap->iface->metric < dap->iface->metric) 9167827cba2SAaron LI return nap; 9177827cba2SAaron LI return dap; 918*8d36e1dfSRoy Marples #else 919*8d36e1dfSRoy Marples return nap; 920*8d36e1dfSRoy Marples #endif 9217827cba2SAaron LI } 9227827cba2SAaron LI 9237827cba2SAaron LI ssize_t 9247827cba2SAaron LI ipv6_addaddrs(struct ipv6_addrhead *addrs) 9257827cba2SAaron LI { 926*8d36e1dfSRoy Marples struct ipv6_addr *ap, *apn; 9277827cba2SAaron LI ssize_t i; 9287827cba2SAaron LI struct timespec now; 9297827cba2SAaron LI 9307827cba2SAaron LI i = 0; 9317827cba2SAaron LI timespecclear(&now); 9327827cba2SAaron LI TAILQ_FOREACH_SAFE(ap, addrs, next, apn) { 9337827cba2SAaron LI /* A delegated prefix is not an address. */ 9347827cba2SAaron LI if (ap->flags & IPV6_AF_DELEGATEDPFX) 9357827cba2SAaron LI continue; 9367827cba2SAaron LI if (ap->prefix_vltime == 0) { 9377827cba2SAaron LI if (ap->flags & IPV6_AF_ADDED) { 9387827cba2SAaron LI ipv6_deleteaddr(ap); 9397827cba2SAaron LI i++; 9407827cba2SAaron LI } 9417827cba2SAaron LI eloop_q_timeout_delete(ap->iface->ctx->eloop, 9427827cba2SAaron LI 0, NULL, ap); 9437827cba2SAaron LI if (ap->flags & IPV6_AF_REQUEST) { 9447827cba2SAaron LI ap->flags &= ~IPV6_AF_ADDED; 9457827cba2SAaron LI } else { 9467827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next); 9477827cba2SAaron LI ipv6_freeaddr(ap); 9487827cba2SAaron LI } 9497827cba2SAaron LI } else if (!(ap->flags & IPV6_AF_STALE) && 9507827cba2SAaron LI !IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) 9517827cba2SAaron LI { 9527827cba2SAaron LI if (ap->flags & IPV6_AF_NEW) 9537827cba2SAaron LI i++; 9547827cba2SAaron LI if (!timespecisset(&now)) 9557827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &now); 9567827cba2SAaron LI ipv6_addaddr(ap, &now); 9577827cba2SAaron LI } 9587827cba2SAaron LI } 9597827cba2SAaron LI 9607827cba2SAaron LI return i; 9617827cba2SAaron LI } 9627827cba2SAaron LI 9637827cba2SAaron LI void 9647827cba2SAaron LI ipv6_freeaddr(struct ipv6_addr *ia) 9657827cba2SAaron LI { 9667827cba2SAaron LI #ifndef SMALL 9677827cba2SAaron LI struct ipv6_addr *iad; 9687827cba2SAaron LI 9697827cba2SAaron LI /* Forget the reference */ 9707827cba2SAaron LI if (ia->flags & IPV6_AF_DELEGATEDPFX) { 9717827cba2SAaron LI TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) { 9727827cba2SAaron LI iad->delegating_prefix = NULL; 9737827cba2SAaron LI } 9747827cba2SAaron LI } else if (ia->delegating_prefix != NULL) { 9757827cba2SAaron LI TAILQ_REMOVE(&ia->delegating_prefix->pd_pfxs, ia, pd_next); 9767827cba2SAaron LI } 9777827cba2SAaron LI #endif 9787827cba2SAaron LI 9797827cba2SAaron LI if (ia->dhcp6_fd != -1) { 9807827cba2SAaron LI close(ia->dhcp6_fd); 9817827cba2SAaron LI eloop_event_delete(ia->iface->ctx->eloop, ia->dhcp6_fd); 9827827cba2SAaron LI } 9837827cba2SAaron LI 9847827cba2SAaron LI eloop_q_timeout_delete(ia->iface->ctx->eloop, 0, NULL, ia); 985*8d36e1dfSRoy Marples free(ia->na); 9867827cba2SAaron LI free(ia); 9877827cba2SAaron LI } 9887827cba2SAaron LI 9897827cba2SAaron LI void 9907827cba2SAaron LI ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop, 9917827cba2SAaron LI const struct interface *ifd) 9927827cba2SAaron LI { 9937827cba2SAaron LI struct ipv6_addr *ap, *apn, *apf; 9947827cba2SAaron LI struct timespec now; 9957827cba2SAaron LI 9967827cba2SAaron LI #ifdef SMALL 9977827cba2SAaron LI UNUSED(ifd); 9987827cba2SAaron LI #endif 9997827cba2SAaron LI timespecclear(&now); 10007827cba2SAaron LI TAILQ_FOREACH_SAFE(ap, addrs, next, apn) { 10017827cba2SAaron LI #ifndef SMALL 10027827cba2SAaron LI if (ifd != NULL && 10037827cba2SAaron LI (ap->delegating_prefix == NULL || 10047827cba2SAaron LI ap->delegating_prefix->iface != ifd)) 10057827cba2SAaron LI continue; 10067827cba2SAaron LI #endif 10077827cba2SAaron LI if (drop != 2) 10087827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next); 10097827cba2SAaron LI if (drop && ap->flags & IPV6_AF_ADDED && 10107827cba2SAaron LI (ap->iface->options->options & 10117827cba2SAaron LI (DHCPCD_EXITING | DHCPCD_PERSISTENT)) != 10127827cba2SAaron LI (DHCPCD_EXITING | DHCPCD_PERSISTENT)) 10137827cba2SAaron LI { 10147827cba2SAaron LI /* Don't drop link-local addresses. */ 10157827cba2SAaron LI if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr) || 10167827cba2SAaron LI CAN_DROP_LLADDR(ap->iface)) 10177827cba2SAaron LI { 10187827cba2SAaron LI if (drop == 2) 10197827cba2SAaron LI TAILQ_REMOVE(addrs, ap, next); 10207827cba2SAaron LI /* Find the same address somewhere else */ 10217827cba2SAaron LI apf = ipv6_findaddr(ap->iface->ctx, &ap->addr, 10227827cba2SAaron LI 0); 10237827cba2SAaron LI if ((apf == NULL || 10247827cba2SAaron LI (apf->iface != ap->iface))) 10257827cba2SAaron LI ipv6_deleteaddr(ap); 10267827cba2SAaron LI if (!(ap->iface->options->options & 10277827cba2SAaron LI DHCPCD_EXITING) && apf) 10287827cba2SAaron LI { 10297827cba2SAaron LI if (!timespecisset(&now)) 10307827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, 10317827cba2SAaron LI &now); 10327827cba2SAaron LI ipv6_addaddr(apf, &now); 10337827cba2SAaron LI } 10347827cba2SAaron LI if (drop == 2) 10357827cba2SAaron LI ipv6_freeaddr(ap); 10367827cba2SAaron LI } 10377827cba2SAaron LI } 10387827cba2SAaron LI if (drop != 2) 10397827cba2SAaron LI ipv6_freeaddr(ap); 10407827cba2SAaron LI } 10417827cba2SAaron LI } 10427827cba2SAaron LI 10437827cba2SAaron LI static struct ipv6_state * 10447827cba2SAaron LI ipv6_getstate(struct interface *ifp) 10457827cba2SAaron LI { 10467827cba2SAaron LI struct ipv6_state *state; 10477827cba2SAaron LI 10487827cba2SAaron LI state = IPV6_STATE(ifp); 10497827cba2SAaron LI if (state == NULL) { 10507827cba2SAaron LI ifp->if_data[IF_DATA_IPV6] = calloc(1, sizeof(*state)); 10517827cba2SAaron LI state = IPV6_STATE(ifp); 10527827cba2SAaron LI if (state == NULL) { 10537827cba2SAaron LI logerr(__func__); 10547827cba2SAaron LI return NULL; 10557827cba2SAaron LI } 10567827cba2SAaron LI TAILQ_INIT(&state->addrs); 10577827cba2SAaron LI TAILQ_INIT(&state->ll_callbacks); 10587827cba2SAaron LI 10597827cba2SAaron LI /* Regenerate new ids */ 10607827cba2SAaron LI if (ifp->options && 10617827cba2SAaron LI ip6_use_tempaddr(ifp->name)) 10627827cba2SAaron LI ipv6_regentempifid(ifp); 10637827cba2SAaron LI } 10647827cba2SAaron LI return state; 10657827cba2SAaron LI } 10667827cba2SAaron LI 1067*8d36e1dfSRoy Marples struct ipv6_addr * 1068*8d36e1dfSRoy Marples ipv6_ifanyglobal(struct interface *ifp) 1069*8d36e1dfSRoy Marples { 1070*8d36e1dfSRoy Marples struct ipv6_state *state; 1071*8d36e1dfSRoy Marples struct ipv6_addr *ia; 1072*8d36e1dfSRoy Marples 1073*8d36e1dfSRoy Marples if (ifp->carrier == LINK_DOWN) 1074*8d36e1dfSRoy Marples return NULL; 1075*8d36e1dfSRoy Marples 1076*8d36e1dfSRoy Marples state = IPV6_STATE(ifp); 1077*8d36e1dfSRoy Marples if (state == NULL) 1078*8d36e1dfSRoy Marples return NULL; 1079*8d36e1dfSRoy Marples 1080*8d36e1dfSRoy Marples TAILQ_FOREACH(ia, &state->addrs, next) { 1081*8d36e1dfSRoy Marples if (IN6_IS_ADDR_LINKLOCAL(&ia->addr)) 1082*8d36e1dfSRoy Marples continue; 1083*8d36e1dfSRoy Marples /* Let's be optimistic. 1084*8d36e1dfSRoy Marples * Any decent OS won't forward or accept traffic 1085*8d36e1dfSRoy Marples * from/to tentative or detached addresses. */ 1086*8d36e1dfSRoy Marples if (!(ia->addr_flags & IN6_IFF_DUPLICATED)) 1087*8d36e1dfSRoy Marples break; 1088*8d36e1dfSRoy Marples } 1089*8d36e1dfSRoy Marples return ia; 1090*8d36e1dfSRoy Marples } 1091*8d36e1dfSRoy Marples 10927827cba2SAaron LI void 10937827cba2SAaron LI ipv6_handleifa(struct dhcpcd_ctx *ctx, 10947827cba2SAaron LI int cmd, struct if_head *ifs, const char *ifname, 10957827cba2SAaron LI const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid) 10967827cba2SAaron LI { 10977827cba2SAaron LI struct interface *ifp; 10987827cba2SAaron LI struct ipv6_state *state; 10997827cba2SAaron LI struct ipv6_addr *ia; 11007827cba2SAaron LI struct ll_callback *cb; 1101*8d36e1dfSRoy Marples bool anyglobal; 1102*8d36e1dfSRoy Marples 1103*8d36e1dfSRoy Marples #ifdef __sun 1104*8d36e1dfSRoy Marples struct sockaddr_in6 subnet; 1105*8d36e1dfSRoy Marples 1106*8d36e1dfSRoy Marples /* Solaris on-link route is an unspecified address! */ 1107*8d36e1dfSRoy Marples if (IN6_IS_ADDR_UNSPECIFIED(addr)) { 1108*8d36e1dfSRoy Marples if (if_getsubnet(ctx, ifname, AF_INET6, 1109*8d36e1dfSRoy Marples &subnet, sizeof(subnet)) == -1) 1110*8d36e1dfSRoy Marples { 1111*8d36e1dfSRoy Marples logerr(__func__); 1112*8d36e1dfSRoy Marples return; 1113*8d36e1dfSRoy Marples } 1114*8d36e1dfSRoy Marples addr = &subnet.sin6_addr; 1115*8d36e1dfSRoy Marples } 1116*8d36e1dfSRoy Marples #endif 11177827cba2SAaron LI 11187827cba2SAaron LI #if 0 11197827cba2SAaron LI char dbuf[INET6_ADDRSTRLEN]; 11207827cba2SAaron LI const char *dbp; 11217827cba2SAaron LI 11227827cba2SAaron LI dbp = inet_ntop(AF_INET6, &addr->s6_addr, 11237827cba2SAaron LI dbuf, INET6_ADDRSTRLEN); 1124*8d36e1dfSRoy Marples loginfox("%s: cmd %d addr %s addrflags %d", 1125*8d36e1dfSRoy Marples ifname, cmd, dbp, addrflags); 11267827cba2SAaron LI #endif 11277827cba2SAaron LI 11287827cba2SAaron LI if (ifs == NULL) 11297827cba2SAaron LI ifs = ctx->ifaces; 11307827cba2SAaron LI if (ifs == NULL) 11317827cba2SAaron LI return; 11327827cba2SAaron LI if ((ifp = if_find(ifs, ifname)) == NULL) 11337827cba2SAaron LI return; 11347827cba2SAaron LI if ((state = ipv6_getstate(ifp)) == NULL) 11357827cba2SAaron LI return; 1136*8d36e1dfSRoy Marples anyglobal = ipv6_ifanyglobal(ifp) != NULL; 11377827cba2SAaron LI 11387827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 11397827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr)) 11407827cba2SAaron LI break; 11417827cba2SAaron LI } 11427827cba2SAaron LI 11437827cba2SAaron LI switch (cmd) { 11447827cba2SAaron LI case RTM_DELADDR: 11457827cba2SAaron LI if (ia != NULL) { 11467827cba2SAaron LI TAILQ_REMOVE(&state->addrs, ia, next); 1147*8d36e1dfSRoy Marples #ifdef ND6_ADVERTISE 1148*8d36e1dfSRoy Marples /* Advertise the address if it exists on 1149*8d36e1dfSRoy Marples * another interface. */ 1150*8d36e1dfSRoy Marples ipv6nd_advertise(ia); 1151*8d36e1dfSRoy Marples #endif 11527827cba2SAaron LI /* We'll free it at the end of the function. */ 11537827cba2SAaron LI } 11547827cba2SAaron LI break; 11557827cba2SAaron LI case RTM_NEWADDR: 11567827cba2SAaron LI if (ia == NULL) { 11577827cba2SAaron LI ia = ipv6_newaddr(ifp, addr, prefix_len, 0); 11587827cba2SAaron LI #ifdef ALIAS_ADDR 11597827cba2SAaron LI strlcpy(ia->alias, ifname, sizeof(ia->alias)); 11607827cba2SAaron LI #endif 11617827cba2SAaron LI if (if_getlifetime6(ia) == -1) { 11627827cba2SAaron LI /* No support or address vanished. 11637827cba2SAaron LI * Either way, just set a deprecated 11647827cba2SAaron LI * infinite time lifetime and continue. 11657827cba2SAaron LI * This is fine because we only want 11667827cba2SAaron LI * to know this when trying to extend 11677827cba2SAaron LI * temporary addresses. 11687827cba2SAaron LI * As we can't extend infinite, we'll 11697827cba2SAaron LI * create a new temporary address. */ 11707827cba2SAaron LI ia->prefix_pltime = 0; 11717827cba2SAaron LI ia->prefix_vltime = 11727827cba2SAaron LI ND6_INFINITE_LIFETIME; 11737827cba2SAaron LI } 11747827cba2SAaron LI /* This is a minor regression against RFC 4941 11757827cba2SAaron LI * because the kernel only knows when the 11767827cba2SAaron LI * lifetimes were last updated, not when the 11777827cba2SAaron LI * address was initially created. 11787827cba2SAaron LI * Provided dhcpcd is not restarted, this 11797827cba2SAaron LI * won't be a problem. 11807827cba2SAaron LI * If we don't like it, we can always 11817827cba2SAaron LI * pretend lifetimes are infinite and always 11827827cba2SAaron LI * generate a new temporary address on 11837827cba2SAaron LI * restart. */ 11847827cba2SAaron LI ia->acquired = ia->created; 11857827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next); 11867827cba2SAaron LI } 11877827cba2SAaron LI ia->addr_flags = addrflags; 11887827cba2SAaron LI ia->flags &= ~IPV6_AF_STALE; 11897827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 11907827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TEMPORARY) 11917827cba2SAaron LI ia->flags |= IPV6_AF_TEMPORARY; 11927827cba2SAaron LI #endif 11937827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) { 11947827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 11957827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TENTATIVE) { 11967827cba2SAaron LI struct timespec tv; 11977827cba2SAaron LI 11987827cba2SAaron LI ms_to_ts(&tv, RETRANS_TIMER / 2); 11997827cba2SAaron LI eloop_timeout_add_tv( 12007827cba2SAaron LI ia->iface->ctx->eloop, 12017827cba2SAaron LI &tv, ipv6_checkaddrflags, ia); 12027827cba2SAaron LI break; 12037827cba2SAaron LI } 12047827cba2SAaron LI #endif 12057827cba2SAaron LI 12067827cba2SAaron LI if (ia->dadcallback) { 12077827cba2SAaron LI ia->dadcallback(ia); 12087827cba2SAaron LI if (ctx->options & DHCPCD_FORKED) 12097827cba2SAaron LI goto out; 12107827cba2SAaron LI } 12117827cba2SAaron LI 12127827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) && 12137827cba2SAaron LI !(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 12147827cba2SAaron LI { 12157827cba2SAaron LI /* Now run any callbacks. 12167827cba2SAaron LI * Typically IPv6RS or DHCPv6 */ 12177827cba2SAaron LI while ((cb = 12187827cba2SAaron LI TAILQ_FIRST(&state->ll_callbacks))) 12197827cba2SAaron LI { 12207827cba2SAaron LI TAILQ_REMOVE( 12217827cba2SAaron LI &state->ll_callbacks, 12227827cba2SAaron LI cb, next); 12237827cba2SAaron LI cb->callback(cb->arg); 12247827cba2SAaron LI free(cb); 12257827cba2SAaron LI if (ctx->options & DHCPCD_FORKED) 12267827cba2SAaron LI goto out; 12277827cba2SAaron LI } 12287827cba2SAaron LI } 12297827cba2SAaron LI } 12307827cba2SAaron LI break; 12317827cba2SAaron LI } 12327827cba2SAaron LI 12337827cba2SAaron LI if (ia == NULL) 12347827cba2SAaron LI return; 12357827cba2SAaron LI 1236*8d36e1dfSRoy Marples ctx->options &= ~DHCPCD_RTBUILD; 12377827cba2SAaron LI ipv6nd_handleifa(cmd, ia, pid); 12387827cba2SAaron LI #ifdef DHCP6 12397827cba2SAaron LI dhcp6_handleifa(cmd, ia, pid); 12407827cba2SAaron LI #endif 12417827cba2SAaron LI 12427827cba2SAaron LI out: 12437827cba2SAaron LI /* Done with the ia now, so free it. */ 12447827cba2SAaron LI if (cmd == RTM_DELADDR) 12457827cba2SAaron LI ipv6_freeaddr(ia); 1246*8d36e1dfSRoy Marples else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 1247*8d36e1dfSRoy Marples ia->flags |= IPV6_AF_DADCOMPLETED; 1248*8d36e1dfSRoy Marples 1249*8d36e1dfSRoy Marples /* If we've not already called rt_build via the IPv6ND 1250*8d36e1dfSRoy Marples * or DHCP6 handlers and the existance of any useable 1251*8d36e1dfSRoy Marples * global address on the interface has changed, 1252*8d36e1dfSRoy Marples * call rt_build to add/remove the default route. */ 1253*8d36e1dfSRoy Marples if (ifp->active && ifp->options->options & DHCPCD_IPV6 && 1254*8d36e1dfSRoy Marples !(ctx->options & DHCPCD_RTBUILD) && 1255*8d36e1dfSRoy Marples (ipv6_ifanyglobal(ifp) != NULL) != anyglobal) 1256*8d36e1dfSRoy Marples rt_build(ctx, AF_INET6); 12577827cba2SAaron LI } 12587827cba2SAaron LI 12597827cba2SAaron LI int 12607827cba2SAaron LI ipv6_hasaddr(const struct interface *ifp) 12617827cba2SAaron LI { 12627827cba2SAaron LI 12637827cba2SAaron LI if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL) 12647827cba2SAaron LI return 1; 1265*8d36e1dfSRoy Marples #ifdef DHCP6 12667827cba2SAaron LI if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL) 12677827cba2SAaron LI return 1; 1268*8d36e1dfSRoy Marples #endif 12697827cba2SAaron LI return 0; 12707827cba2SAaron LI } 12717827cba2SAaron LI 12727827cba2SAaron LI struct ipv6_addr * 12737827cba2SAaron LI ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr, 12747827cba2SAaron LI int revflags) 12757827cba2SAaron LI { 12767827cba2SAaron LI struct ipv6_state *state; 12777827cba2SAaron LI struct ipv6_addr *ap; 12787827cba2SAaron LI 12797827cba2SAaron LI state = IPV6_STATE(ifp); 12807827cba2SAaron LI if (state) { 12817827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) { 12827827cba2SAaron LI if (addr == NULL) { 12837827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) && 12847827cba2SAaron LI (!revflags || !(ap->addr_flags & revflags))) 12857827cba2SAaron LI return ap; 12867827cba2SAaron LI } else { 12877827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) && 12887827cba2SAaron LI (!revflags || !(ap->addr_flags & revflags))) 12897827cba2SAaron LI return ap; 12907827cba2SAaron LI } 12917827cba2SAaron LI } 12927827cba2SAaron LI } 12937827cba2SAaron LI return NULL; 12947827cba2SAaron LI } 12957827cba2SAaron LI 12967827cba2SAaron LI static struct ipv6_addr * 12977827cba2SAaron LI ipv6_iffindmaskaddr(const struct interface *ifp, const struct in6_addr *addr) 12987827cba2SAaron LI { 12997827cba2SAaron LI struct ipv6_state *state; 13007827cba2SAaron LI struct ipv6_addr *ap; 13017827cba2SAaron LI struct in6_addr mask; 13027827cba2SAaron LI 13037827cba2SAaron LI state = IPV6_STATE(ifp); 13047827cba2SAaron LI if (state) { 13057827cba2SAaron LI TAILQ_FOREACH(ap, &state->addrs, next) { 13067827cba2SAaron LI if (ipv6_mask(&mask, ap->prefix_len) == -1) 13077827cba2SAaron LI continue; 13087827cba2SAaron LI if (IN6_ARE_MASKED_ADDR_EQUAL(&ap->addr, addr, &mask)) 13097827cba2SAaron LI return ap; 13107827cba2SAaron LI } 13117827cba2SAaron LI } 13127827cba2SAaron LI return NULL; 13137827cba2SAaron LI } 13147827cba2SAaron LI 13157827cba2SAaron LI struct ipv6_addr * 13167827cba2SAaron LI ipv6_findmaskaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr) 13177827cba2SAaron LI { 13187827cba2SAaron LI struct interface *ifp; 13197827cba2SAaron LI struct ipv6_addr *ap; 13207827cba2SAaron LI 13217827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 13227827cba2SAaron LI ap = ipv6_iffindmaskaddr(ifp, addr); 13237827cba2SAaron LI if (ap != NULL) 13247827cba2SAaron LI return ap; 13257827cba2SAaron LI } 13267827cba2SAaron LI return NULL; 13277827cba2SAaron LI } 13287827cba2SAaron LI 13297827cba2SAaron LI int 13307827cba2SAaron LI ipv6_addlinklocalcallback(struct interface *ifp, 13317827cba2SAaron LI void (*callback)(void *), void *arg) 13327827cba2SAaron LI { 13337827cba2SAaron LI struct ipv6_state *state; 13347827cba2SAaron LI struct ll_callback *cb; 13357827cba2SAaron LI 13367827cba2SAaron LI state = ipv6_getstate(ifp); 13377827cba2SAaron LI TAILQ_FOREACH(cb, &state->ll_callbacks, next) { 13387827cba2SAaron LI if (cb->callback == callback && cb->arg == arg) 13397827cba2SAaron LI break; 13407827cba2SAaron LI } 13417827cba2SAaron LI if (cb == NULL) { 13427827cba2SAaron LI cb = malloc(sizeof(*cb)); 13437827cba2SAaron LI if (cb == NULL) { 13447827cba2SAaron LI logerr(__func__); 13457827cba2SAaron LI return -1; 13467827cba2SAaron LI } 13477827cba2SAaron LI cb->callback = callback; 13487827cba2SAaron LI cb->arg = arg; 13497827cba2SAaron LI TAILQ_INSERT_TAIL(&state->ll_callbacks, cb, next); 13507827cba2SAaron LI } 13517827cba2SAaron LI return 0; 13527827cba2SAaron LI } 13537827cba2SAaron LI 13547827cba2SAaron LI static struct ipv6_addr * 13557827cba2SAaron LI ipv6_newlinklocal(struct interface *ifp) 13567827cba2SAaron LI { 13577827cba2SAaron LI struct ipv6_addr *ia; 13587827cba2SAaron LI struct in6_addr in6; 13597827cba2SAaron LI 13607827cba2SAaron LI memset(&in6, 0, sizeof(in6)); 13617827cba2SAaron LI in6.s6_addr32[0] = htonl(0xfe800000); 13627827cba2SAaron LI ia = ipv6_newaddr(ifp, &in6, 64, 0); 13637827cba2SAaron LI if (ia != NULL) { 13647827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME; 13657827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME; 13667827cba2SAaron LI } 13677827cba2SAaron LI return ia; 13687827cba2SAaron LI } 13697827cba2SAaron LI 13707827cba2SAaron LI static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 13717827cba2SAaron LI static const uint8_t allone[8] = 13727827cba2SAaron LI { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 13737827cba2SAaron LI 13747827cba2SAaron LI static int 13757827cba2SAaron LI ipv6_addlinklocal(struct interface *ifp) 13767827cba2SAaron LI { 13777827cba2SAaron LI struct ipv6_state *state; 13787827cba2SAaron LI struct ipv6_addr *ap, *ap2; 13797827cba2SAaron LI int dadcounter; 13807827cba2SAaron LI 13817827cba2SAaron LI /* Check sanity before malloc */ 13827827cba2SAaron LI if (!(ifp->options->options & DHCPCD_SLAACPRIVATE)) { 13837827cba2SAaron LI switch (ifp->family) { 13847827cba2SAaron LI case ARPHRD_ETHER: 13857827cba2SAaron LI /* Check for a valid hardware address */ 13867827cba2SAaron LI if (ifp->hwlen != 6 && ifp->hwlen != 8) { 13877827cba2SAaron LI errno = ENOTSUP; 13887827cba2SAaron LI return -1; 13897827cba2SAaron LI } 13907827cba2SAaron LI if (memcmp(ifp->hwaddr, allzero, ifp->hwlen) == 0 || 13917827cba2SAaron LI memcmp(ifp->hwaddr, allone, ifp->hwlen) == 0) 13927827cba2SAaron LI { 13937827cba2SAaron LI errno = EINVAL; 13947827cba2SAaron LI return -1; 13957827cba2SAaron LI } 13967827cba2SAaron LI break; 13977827cba2SAaron LI default: 13987827cba2SAaron LI errno = ENOTSUP; 13997827cba2SAaron LI return -1; 14007827cba2SAaron LI } 14017827cba2SAaron LI } 14027827cba2SAaron LI 14037827cba2SAaron LI state = ipv6_getstate(ifp); 14047827cba2SAaron LI if (state == NULL) 14057827cba2SAaron LI return -1; 14067827cba2SAaron LI 14077827cba2SAaron LI ap = ipv6_newlinklocal(ifp); 14087827cba2SAaron LI if (ap == NULL) 14097827cba2SAaron LI return -1; 14107827cba2SAaron LI 14117827cba2SAaron LI dadcounter = 0; 14127827cba2SAaron LI if (ifp->options->options & DHCPCD_SLAACPRIVATE) { 14137827cba2SAaron LI nextslaacprivate: 14147827cba2SAaron LI if (ipv6_makestableprivate(&ap->addr, 14157827cba2SAaron LI &ap->prefix, ap->prefix_len, ifp, &dadcounter) == -1) 14167827cba2SAaron LI { 14177827cba2SAaron LI free(ap); 14187827cba2SAaron LI return -1; 14197827cba2SAaron LI } 14207827cba2SAaron LI ap->dadcounter = dadcounter; 14217827cba2SAaron LI } else { 14227827cba2SAaron LI memcpy(ap->addr.s6_addr, ap->prefix.s6_addr, 8); 14237827cba2SAaron LI switch (ifp->family) { 14247827cba2SAaron LI case ARPHRD_ETHER: 14257827cba2SAaron LI if (ifp->hwlen == 6) { 14267827cba2SAaron LI ap->addr.s6_addr[ 8] = ifp->hwaddr[0]; 14277827cba2SAaron LI ap->addr.s6_addr[ 9] = ifp->hwaddr[1]; 14287827cba2SAaron LI ap->addr.s6_addr[10] = ifp->hwaddr[2]; 14297827cba2SAaron LI ap->addr.s6_addr[11] = 0xff; 14307827cba2SAaron LI ap->addr.s6_addr[12] = 0xfe; 14317827cba2SAaron LI ap->addr.s6_addr[13] = ifp->hwaddr[3]; 14327827cba2SAaron LI ap->addr.s6_addr[14] = ifp->hwaddr[4]; 14337827cba2SAaron LI ap->addr.s6_addr[15] = ifp->hwaddr[5]; 14347827cba2SAaron LI } else if (ifp->hwlen == 8) 14357827cba2SAaron LI memcpy(&ap->addr.s6_addr[8], ifp->hwaddr, 8); 14367827cba2SAaron LI else { 14377827cba2SAaron LI free(ap); 14387827cba2SAaron LI errno = ENOTSUP; 14397827cba2SAaron LI return -1; 14407827cba2SAaron LI } 14417827cba2SAaron LI break; 14427827cba2SAaron LI } 14437827cba2SAaron LI 14447827cba2SAaron LI /* Sanity check: g bit must not indciate "group" */ 14457827cba2SAaron LI if (EUI64_GROUP(&ap->addr)) { 14467827cba2SAaron LI free(ap); 14477827cba2SAaron LI errno = EINVAL; 14487827cba2SAaron LI return -1; 14497827cba2SAaron LI } 14507827cba2SAaron LI EUI64_TO_IFID(&ap->addr); 14517827cba2SAaron LI } 14527827cba2SAaron LI 14537827cba2SAaron LI /* Do we already have this address? */ 14547827cba2SAaron LI TAILQ_FOREACH(ap2, &state->addrs, next) { 14557827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &ap2->addr)) { 14567827cba2SAaron LI if (ap2->addr_flags & IN6_IFF_DUPLICATED) { 14577827cba2SAaron LI if (ifp->options->options & 14587827cba2SAaron LI DHCPCD_SLAACPRIVATE) 14597827cba2SAaron LI { 14607827cba2SAaron LI dadcounter++; 14617827cba2SAaron LI goto nextslaacprivate; 14627827cba2SAaron LI } 14637827cba2SAaron LI free(ap); 14647827cba2SAaron LI errno = EADDRNOTAVAIL; 14657827cba2SAaron LI return -1; 14667827cba2SAaron LI } 14677827cba2SAaron LI 14687827cba2SAaron LI logwarnx("%s: waiting for %s to complete", 14697827cba2SAaron LI ap2->iface->name, ap2->saddr); 14707827cba2SAaron LI free(ap); 14717827cba2SAaron LI errno = EEXIST; 14727827cba2SAaron LI return 0; 14737827cba2SAaron LI } 14747827cba2SAaron LI } 14757827cba2SAaron LI 14767827cba2SAaron LI inet_ntop(AF_INET6, &ap->addr, ap->saddr, sizeof(ap->saddr)); 14777827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ap, next); 14787827cba2SAaron LI ipv6_addaddr(ap, NULL); 14797827cba2SAaron LI return 1; 14807827cba2SAaron LI } 14817827cba2SAaron LI 14827827cba2SAaron LI static int 14837827cba2SAaron LI ipv6_tryaddlinklocal(struct interface *ifp) 14847827cba2SAaron LI { 14857827cba2SAaron LI struct ipv6_addr *ia; 14867827cba2SAaron LI 14877827cba2SAaron LI /* We can't assign a link-locak address to this, 14887827cba2SAaron LI * the ppp process has to. */ 14897827cba2SAaron LI if (ifp->flags & IFF_POINTOPOINT) 14907827cba2SAaron LI return 0; 14917827cba2SAaron LI 14927827cba2SAaron LI ia = ipv6_iffindaddr(ifp, NULL, IN6_IFF_DUPLICATED); 14937827cba2SAaron LI if (ia != NULL) { 14947827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 14957827cba2SAaron LI if (ia->addr_flags & IN6_IFF_TENTATIVE) { 14967827cba2SAaron LI struct timespec tv; 14977827cba2SAaron LI 14987827cba2SAaron LI ms_to_ts(&tv, RETRANS_TIMER / 2); 14997827cba2SAaron LI eloop_timeout_add_tv( 15007827cba2SAaron LI ia->iface->ctx->eloop, 15017827cba2SAaron LI &tv, ipv6_checkaddrflags, ia); 15027827cba2SAaron LI } 15037827cba2SAaron LI #endif 15047827cba2SAaron LI return 0; 15057827cba2SAaron LI } 15067827cba2SAaron LI if (!CAN_ADD_LLADDR(ifp)) 15077827cba2SAaron LI return 0; 15087827cba2SAaron LI 15097827cba2SAaron LI return ipv6_addlinklocal(ifp); 15107827cba2SAaron LI } 15117827cba2SAaron LI 15127827cba2SAaron LI struct ipv6_addr * 15137827cba2SAaron LI ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr, 15147827cba2SAaron LI uint8_t prefix_len, unsigned int flags) 15157827cba2SAaron LI { 15167827cba2SAaron LI struct ipv6_addr *ia; 15177827cba2SAaron LI char buf[INET6_ADDRSTRLEN]; 15187827cba2SAaron LI const char *cbp; 15197827cba2SAaron LI bool tempaddr; 15207827cba2SAaron LI int addr_flags; 15217827cba2SAaron LI 15227827cba2SAaron LI /* If adding a new DHCP / RA derived address, check current flags 15237827cba2SAaron LI * from an existing address. */ 15247827cba2SAaron LI ia = ipv6_iffindaddr(ifp, addr, 0); 15257827cba2SAaron LI if (ia != NULL) 15267827cba2SAaron LI addr_flags = ia->addr_flags; 15277827cba2SAaron LI else 15287827cba2SAaron LI addr_flags = IN6_IFF_TENTATIVE; 15297827cba2SAaron LI 15307827cba2SAaron LI ia = calloc(1, sizeof(*ia)); 15317827cba2SAaron LI if (ia == NULL) 15327827cba2SAaron LI goto err; 15337827cba2SAaron LI 15347827cba2SAaron LI ia->iface = ifp; 15357827cba2SAaron LI ia->addr_flags = addr_flags; 1536*8d36e1dfSRoy Marples ia->flags = IPV6_AF_NEW | flags; 1537*8d36e1dfSRoy Marples if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 1538*8d36e1dfSRoy Marples ia->flags |= IPV6_AF_DADCOMPLETED; 15397827cba2SAaron LI ia->prefix_len = prefix_len; 15407827cba2SAaron LI ia->dhcp6_fd = -1; 15417827cba2SAaron LI 15427827cba2SAaron LI #ifdef IPV6_AF_TEMPORARY 15437827cba2SAaron LI tempaddr = ia->flags & IPV6_AF_TEMPORARY; 15447827cba2SAaron LI #else 15457827cba2SAaron LI tempaddr = false; 15467827cba2SAaron LI #endif 15477827cba2SAaron LI 15487827cba2SAaron LI if (ia->flags & IPV6_AF_AUTOCONF && !tempaddr) { 15497827cba2SAaron LI ia->prefix = *addr; 15507827cba2SAaron LI ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp, 15517827cba2SAaron LI &ia->prefix, 15527827cba2SAaron LI ia->prefix_len); 15537827cba2SAaron LI if (ia->dadcounter == -1) 15547827cba2SAaron LI goto err; 15557827cba2SAaron LI } else if (ia->flags & IPV6_AF_RAPFX) { 15567827cba2SAaron LI ia->prefix = *addr; 1557*8d36e1dfSRoy Marples #ifdef __sun 1558*8d36e1dfSRoy Marples ia->addr = *addr; 1559*8d36e1dfSRoy Marples cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf)); 1560*8d36e1dfSRoy Marples goto paddr; 1561*8d36e1dfSRoy Marples #else 15627827cba2SAaron LI return ia; 1563*8d36e1dfSRoy Marples #endif 15647827cba2SAaron LI } else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX) && 15657827cba2SAaron LI prefix_len != 128) 15667827cba2SAaron LI { 15677827cba2SAaron LI ia->prefix = *addr; 15687827cba2SAaron LI cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf)); 15697827cba2SAaron LI goto paddr; 15707827cba2SAaron LI } else { 15717827cba2SAaron LI ia->addr = *addr; 15727827cba2SAaron LI if (ipv6_makeprefix(&ia->prefix, 15737827cba2SAaron LI &ia->addr, ia->prefix_len) == -1) 15747827cba2SAaron LI goto err; 15757827cba2SAaron LI } 15767827cba2SAaron LI 15777827cba2SAaron LI cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf)); 15787827cba2SAaron LI paddr: 15797827cba2SAaron LI if (cbp == NULL) 15807827cba2SAaron LI goto err; 15817827cba2SAaron LI snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len); 15827827cba2SAaron LI 15837827cba2SAaron LI return ia; 15847827cba2SAaron LI 15857827cba2SAaron LI err: 15867827cba2SAaron LI logerr(__func__); 15877827cba2SAaron LI free(ia); 15887827cba2SAaron LI return NULL; 15897827cba2SAaron LI } 15907827cba2SAaron LI 15917827cba2SAaron LI static void 15927827cba2SAaron LI ipv6_staticdadcallback(void *arg) 15937827cba2SAaron LI { 15947827cba2SAaron LI struct ipv6_addr *ia = arg; 15957827cba2SAaron LI int wascompleted; 15967827cba2SAaron LI 15977827cba2SAaron LI wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED); 15987827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED; 15997827cba2SAaron LI if (ia->flags & IPV6_AF_DUPLICATED) 16007827cba2SAaron LI logwarnx("%s: DAD detected %s", ia->iface->name, 16017827cba2SAaron LI ia->saddr); 16027827cba2SAaron LI else if (!wascompleted) { 16037827cba2SAaron LI logdebugx("%s: IPv6 static DAD completed", 16047827cba2SAaron LI ia->iface->name); 16057827cba2SAaron LI } 16067827cba2SAaron LI 16077827cba2SAaron LI #define FINISHED (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED) 16087827cba2SAaron LI if (!wascompleted) { 16097827cba2SAaron LI struct interface *ifp; 16107827cba2SAaron LI struct ipv6_state *state; 16117827cba2SAaron LI 16127827cba2SAaron LI ifp = ia->iface; 16137827cba2SAaron LI state = IPV6_STATE(ifp); 16147827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 16157827cba2SAaron LI if (ia->flags & IPV6_AF_STATIC && 16167827cba2SAaron LI (ia->flags & FINISHED) != FINISHED) 16177827cba2SAaron LI { 16187827cba2SAaron LI wascompleted = 1; 16197827cba2SAaron LI break; 16207827cba2SAaron LI } 16217827cba2SAaron LI } 16227827cba2SAaron LI if (!wascompleted) 16237827cba2SAaron LI script_runreason(ifp, "STATIC6"); 16247827cba2SAaron LI } 16257827cba2SAaron LI #undef FINISHED 16267827cba2SAaron LI } 16277827cba2SAaron LI 16287827cba2SAaron LI ssize_t 1629*8d36e1dfSRoy Marples ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp) 16307827cba2SAaron LI { 16317827cba2SAaron LI struct ipv6_addr *ia; 16327827cba2SAaron LI 16337827cba2SAaron LI ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6, 16347827cba2SAaron LI IN6_IFF_NOTUSEABLE); 1635*8d36e1dfSRoy Marples if (ia == NULL) 1636*8d36e1dfSRoy Marples return 0; 1637*8d36e1dfSRoy Marples if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1) 1638*8d36e1dfSRoy Marples return -1; 1639*8d36e1dfSRoy Marples return 1; 16407827cba2SAaron LI } 16417827cba2SAaron LI 16427827cba2SAaron LI int 16437827cba2SAaron LI ipv6_staticdadcompleted(const struct interface *ifp) 16447827cba2SAaron LI { 16457827cba2SAaron LI const struct ipv6_state *state; 16467827cba2SAaron LI const struct ipv6_addr *ia; 16477827cba2SAaron LI int n; 16487827cba2SAaron LI 16497827cba2SAaron LI if ((state = IPV6_CSTATE(ifp)) == NULL) 16507827cba2SAaron LI return 0; 16517827cba2SAaron LI n = 0; 16527827cba2SAaron LI #define COMPLETED (IPV6_AF_STATIC | IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED) 16537827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 16547827cba2SAaron LI if ((ia->flags & COMPLETED) == COMPLETED && 16557827cba2SAaron LI !(ia->addr_flags & IN6_IFF_NOTUSEABLE)) 16567827cba2SAaron LI n++; 16577827cba2SAaron LI } 16587827cba2SAaron LI return n; 16597827cba2SAaron LI } 16607827cba2SAaron LI 16617827cba2SAaron LI int 16627827cba2SAaron LI ipv6_startstatic(struct interface *ifp) 16637827cba2SAaron LI { 16647827cba2SAaron LI struct ipv6_addr *ia; 16657827cba2SAaron LI int run_script; 16667827cba2SAaron LI 16677827cba2SAaron LI if (IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6)) 16687827cba2SAaron LI return 0; 16697827cba2SAaron LI 16707827cba2SAaron LI ia = ipv6_iffindaddr(ifp, &ifp->options->req_addr6, 0); 16717827cba2SAaron LI if (ia != NULL && 16727827cba2SAaron LI (ia->prefix_len != ifp->options->req_prefix_len || 16737827cba2SAaron LI ia->addr_flags & IN6_IFF_NOTUSEABLE)) 16747827cba2SAaron LI { 16757827cba2SAaron LI ipv6_deleteaddr(ia); 16767827cba2SAaron LI ia = NULL; 16777827cba2SAaron LI } 16787827cba2SAaron LI if (ia == NULL) { 16797827cba2SAaron LI struct ipv6_state *state; 16807827cba2SAaron LI 16817827cba2SAaron LI ia = ipv6_newaddr(ifp, &ifp->options->req_addr6, 16827827cba2SAaron LI ifp->options->req_prefix_len, 0); 16837827cba2SAaron LI if (ia == NULL) 16847827cba2SAaron LI return -1; 16857827cba2SAaron LI state = IPV6_STATE(ifp); 16867827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next); 16877827cba2SAaron LI run_script = 0; 16887827cba2SAaron LI } else 16897827cba2SAaron LI run_script = 1; 16907827cba2SAaron LI ia->flags |= IPV6_AF_STATIC | IPV6_AF_ONLINK; 16917827cba2SAaron LI ia->prefix_vltime = ND6_INFINITE_LIFETIME; 16927827cba2SAaron LI ia->prefix_pltime = ND6_INFINITE_LIFETIME; 16937827cba2SAaron LI ia->dadcallback = ipv6_staticdadcallback; 16947827cba2SAaron LI ipv6_addaddr(ia, NULL); 16957827cba2SAaron LI rt_build(ifp->ctx, AF_INET6); 16967827cba2SAaron LI if (run_script) 16977827cba2SAaron LI script_runreason(ifp, "STATIC6"); 16987827cba2SAaron LI return 1; 16997827cba2SAaron LI } 17007827cba2SAaron LI 17017827cba2SAaron LI /* Ensure the interface has a link-local address */ 17027827cba2SAaron LI int 17037827cba2SAaron LI ipv6_start(struct interface *ifp) 17047827cba2SAaron LI { 17057827cba2SAaron LI #ifdef IPV6_POLLADDRFLAG 17067827cba2SAaron LI struct ipv6_state *state; 17077827cba2SAaron LI 17087827cba2SAaron LI /* We need to update the address flags. */ 17097827cba2SAaron LI if ((state = IPV6_STATE(ifp)) != NULL) { 17107827cba2SAaron LI struct ipv6_addr *ia; 17117827cba2SAaron LI const char *alias; 17127827cba2SAaron LI int flags; 17137827cba2SAaron LI 17147827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 17157827cba2SAaron LI #ifdef ALIAS_ADDR 17167827cba2SAaron LI alias = ia->alias; 17177827cba2SAaron LI #else 17187827cba2SAaron LI alias = NULL; 17197827cba2SAaron LI #endif 17207827cba2SAaron LI flags = if_addrflags6(ia->iface, &ia->addr, alias); 17217827cba2SAaron LI if (flags != -1) 17227827cba2SAaron LI ia->addr_flags = flags; 17237827cba2SAaron LI } 17247827cba2SAaron LI } 17257827cba2SAaron LI #endif 17267827cba2SAaron LI 17277827cba2SAaron LI if (ipv6_tryaddlinklocal(ifp) == -1) 17287827cba2SAaron LI return -1; 17297827cba2SAaron LI 17307827cba2SAaron LI if (IPV6_CSTATE(ifp)) { 17317827cba2SAaron LI /* Regenerate new ids */ 17327827cba2SAaron LI if (ip6_use_tempaddr(ifp->name)) 17337827cba2SAaron LI ipv6_regentempifid(ifp); 17347827cba2SAaron LI } 17357827cba2SAaron LI 17367827cba2SAaron LI return 0; 17377827cba2SAaron LI } 17387827cba2SAaron LI 17397827cba2SAaron LI void 17407827cba2SAaron LI ipv6_freedrop(struct interface *ifp, int drop) 17417827cba2SAaron LI { 17427827cba2SAaron LI struct ipv6_state *state; 17437827cba2SAaron LI struct ll_callback *cb; 17447827cba2SAaron LI 17457827cba2SAaron LI if (ifp == NULL) 17467827cba2SAaron LI return; 17477827cba2SAaron LI 17487827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL) 17497827cba2SAaron LI return; 17507827cba2SAaron LI 17517827cba2SAaron LI /* If we got here, we can get rid of any LL callbacks. */ 17527827cba2SAaron LI while ((cb = TAILQ_FIRST(&state->ll_callbacks))) { 17537827cba2SAaron LI TAILQ_REMOVE(&state->ll_callbacks, cb, next); 17547827cba2SAaron LI free(cb); 17557827cba2SAaron LI } 17567827cba2SAaron LI 17577827cba2SAaron LI ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL); 17587827cba2SAaron LI if (drop) { 1759*8d36e1dfSRoy Marples if (ifp->ctx->ra_routers != NULL) 17607827cba2SAaron LI rt_build(ifp->ctx, AF_INET6); 17617827cba2SAaron LI } else { 17627827cba2SAaron LI /* Because we need to cache the addresses we don't control, 17637827cba2SAaron LI * we only free the state on when NOT dropping addresses. */ 17647827cba2SAaron LI free(state); 17657827cba2SAaron LI ifp->if_data[IF_DATA_IPV6] = NULL; 17667827cba2SAaron LI eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); 17677827cba2SAaron LI } 17687827cba2SAaron LI } 17697827cba2SAaron LI 17707827cba2SAaron LI void 17717827cba2SAaron LI ipv6_ctxfree(struct dhcpcd_ctx *ctx) 17727827cba2SAaron LI { 17737827cba2SAaron LI 17747827cba2SAaron LI free(ctx->ra_routers); 17757827cba2SAaron LI free(ctx->secret); 17767827cba2SAaron LI } 17777827cba2SAaron LI 17787827cba2SAaron LI int 17797827cba2SAaron LI ipv6_handleifa_addrs(int cmd, 17807827cba2SAaron LI struct ipv6_addrhead *addrs, const struct ipv6_addr *addr, pid_t pid) 17817827cba2SAaron LI { 17827827cba2SAaron LI struct ipv6_addr *ia, *ian; 17837827cba2SAaron LI uint8_t found, alldadcompleted; 17847827cba2SAaron LI 17857827cba2SAaron LI alldadcompleted = 1; 17867827cba2SAaron LI found = 0; 17877827cba2SAaron LI TAILQ_FOREACH_SAFE(ia, addrs, next, ian) { 17887827cba2SAaron LI if (!IN6_ARE_ADDR_EQUAL(&addr->addr, &ia->addr)) { 17897827cba2SAaron LI if (ia->flags & IPV6_AF_ADDED && 17907827cba2SAaron LI !(ia->flags & IPV6_AF_DADCOMPLETED)) 17917827cba2SAaron LI alldadcompleted = 0; 17927827cba2SAaron LI continue; 17937827cba2SAaron LI } 17947827cba2SAaron LI switch (cmd) { 17957827cba2SAaron LI case RTM_DELADDR: 17967827cba2SAaron LI if (ia->flags & IPV6_AF_ADDED) { 17977827cba2SAaron LI logwarnx("%s: pid %d deleted address %s", 17987827cba2SAaron LI ia->iface->name, pid, ia->saddr); 17997827cba2SAaron LI ia->flags &= ~IPV6_AF_ADDED; 18007827cba2SAaron LI } 18017827cba2SAaron LI if (ia->flags & IPV6_AF_DELEGATED) { 18027827cba2SAaron LI TAILQ_REMOVE(addrs, ia, next); 18037827cba2SAaron LI ipv6_deletedaddr(ia); 18047827cba2SAaron LI ipv6_freeaddr(ia); 18057827cba2SAaron LI } 18067827cba2SAaron LI break; 18077827cba2SAaron LI case RTM_NEWADDR: 18087827cba2SAaron LI /* Safety - ignore tentative announcements */ 18097827cba2SAaron LI if (addr->addr_flags & 18107827cba2SAaron LI (IN6_IFF_DETACHED | IN6_IFF_TENTATIVE)) 18117827cba2SAaron LI break; 18127827cba2SAaron LI if ((ia->flags & IPV6_AF_DADCOMPLETED) == 0) { 18137827cba2SAaron LI found++; 18147827cba2SAaron LI if (addr->addr_flags & IN6_IFF_DUPLICATED) 18157827cba2SAaron LI ia->flags |= IPV6_AF_DUPLICATED; 18167827cba2SAaron LI else 18177827cba2SAaron LI ia->flags &= ~IPV6_AF_DUPLICATED; 18187827cba2SAaron LI if (ia->dadcallback) 18197827cba2SAaron LI ia->dadcallback(ia); 18207827cba2SAaron LI /* We need to set this here in-case the 18217827cba2SAaron LI * dadcallback function checks it */ 18227827cba2SAaron LI ia->flags |= IPV6_AF_DADCOMPLETED; 18237827cba2SAaron LI } 18247827cba2SAaron LI break; 18257827cba2SAaron LI } 18267827cba2SAaron LI } 18277827cba2SAaron LI 18287827cba2SAaron LI return alldadcompleted ? found : 0; 18297827cba2SAaron LI } 18307827cba2SAaron LI 18317827cba2SAaron LI #ifdef IPV6_MANAGETEMPADDR 18327827cba2SAaron LI static const struct ipv6_addr * 18337827cba2SAaron LI ipv6_findaddrid(struct dhcpcd_ctx *ctx, uint8_t *addr) 18347827cba2SAaron LI { 18357827cba2SAaron LI const struct interface *ifp; 18367827cba2SAaron LI const struct ipv6_state *state; 18377827cba2SAaron LI const struct ipv6_addr *ia; 18387827cba2SAaron LI 18397827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 18407827cba2SAaron LI if ((state = IPV6_CSTATE(ifp))) { 18417827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 18427827cba2SAaron LI if (memcmp(&ia->addr.s6_addr[8], addr, 8) == 0) 18437827cba2SAaron LI return ia; 18447827cba2SAaron LI } 18457827cba2SAaron LI } 18467827cba2SAaron LI } 18477827cba2SAaron LI return NULL; 18487827cba2SAaron LI } 18497827cba2SAaron LI 18507827cba2SAaron LI static const uint8_t nullid[8]; 18517827cba2SAaron LI static const uint8_t anycastid[8] = { 18527827cba2SAaron LI 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; 18537827cba2SAaron LI static const uint8_t isatapid[4] = { 0x00, 0x00, 0x5e, 0xfe }; 18547827cba2SAaron LI 18557827cba2SAaron LI static void 18567827cba2SAaron LI ipv6_regen_desync(struct interface *ifp, int force) 18577827cba2SAaron LI { 18587827cba2SAaron LI struct ipv6_state *state; 18597827cba2SAaron LI time_t max; 18607827cba2SAaron LI 18617827cba2SAaron LI state = IPV6_STATE(ifp); 18627827cba2SAaron LI 18637827cba2SAaron LI /* RFC4941 Section 5 states that DESYNC_FACTOR must never be 18647827cba2SAaron LI * greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE. 18657827cba2SAaron LI * I believe this is an error and it should be never be greateter than 18667827cba2SAaron LI * TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */ 18677827cba2SAaron LI max = ip6_temp_preferred_lifetime(ifp->name) - REGEN_ADVANCE; 18687827cba2SAaron LI if (state->desync_factor && !force && state->desync_factor < max) 18697827cba2SAaron LI return; 18707827cba2SAaron LI if (state->desync_factor == 0) 18717827cba2SAaron LI state->desync_factor = 18727827cba2SAaron LI (time_t)arc4random_uniform(MIN(MAX_DESYNC_FACTOR, 18737827cba2SAaron LI (uint32_t)max)); 18747827cba2SAaron LI max = ip6_temp_preferred_lifetime(ifp->name) - 18757827cba2SAaron LI state->desync_factor - REGEN_ADVANCE; 18767827cba2SAaron LI eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempifid, ifp); 18777827cba2SAaron LI } 18787827cba2SAaron LI 18797827cba2SAaron LI void 18807827cba2SAaron LI ipv6_gentempifid(struct interface *ifp) 18817827cba2SAaron LI { 18827827cba2SAaron LI struct ipv6_state *state; 18837827cba2SAaron LI MD5_CTX md5; 18847827cba2SAaron LI uint8_t seed[16], digest[16]; 18857827cba2SAaron LI int retry; 18867827cba2SAaron LI 18877827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL) 18887827cba2SAaron LI return; 18897827cba2SAaron LI 18907827cba2SAaron LI retry = 0; 18917827cba2SAaron LI if (memcmp(nullid, state->randomseed0, sizeof(nullid)) == 0) { 18927827cba2SAaron LI uint32_t r; 18937827cba2SAaron LI 18947827cba2SAaron LI r = arc4random(); 18957827cba2SAaron LI memcpy(seed, &r, sizeof(r)); 18967827cba2SAaron LI r = arc4random(); 18977827cba2SAaron LI memcpy(seed + sizeof(r), &r, sizeof(r)); 18987827cba2SAaron LI } else 18997827cba2SAaron LI memcpy(seed, state->randomseed0, sizeof(state->randomseed0)); 19007827cba2SAaron LI 19017827cba2SAaron LI memcpy(seed + sizeof(state->randomseed0), 19027827cba2SAaron LI state->randomseed1, sizeof(state->randomseed1)); 19037827cba2SAaron LI 19047827cba2SAaron LI again: 19057827cba2SAaron LI MD5Init(&md5); 19067827cba2SAaron LI MD5Update(&md5, seed, sizeof(seed)); 19077827cba2SAaron LI MD5Final(digest, &md5); 19087827cba2SAaron LI 19097827cba2SAaron LI /* RFC4941 Section 3.2.1.1 19107827cba2SAaron LI * Take the left-most 64bits and set bit 6 to zero */ 19117827cba2SAaron LI memcpy(state->randomid, digest, sizeof(state->randomid)); 19127827cba2SAaron LI state->randomid[0] = (uint8_t)(state->randomid[0] & ~EUI64_UBIT); 19137827cba2SAaron LI 19147827cba2SAaron LI /* RFC4941 Section 3.2.1.4 19157827cba2SAaron LI * Reject reserved or existing id's */ 19167827cba2SAaron LI if (memcmp(nullid, state->randomid, sizeof(nullid)) == 0 || 19177827cba2SAaron LI (memcmp(anycastid, state->randomid, 7) == 0 && 19187827cba2SAaron LI (anycastid[7] & state->randomid[7]) == anycastid[7]) || 19197827cba2SAaron LI memcmp(isatapid, state->randomid, sizeof(isatapid)) == 0 || 19207827cba2SAaron LI ipv6_findaddrid(ifp->ctx, state->randomid)) 19217827cba2SAaron LI { 19227827cba2SAaron LI if (++retry < GEN_TEMPID_RETRY_MAX) { 19237827cba2SAaron LI memcpy(seed, digest + 8, 8); 19247827cba2SAaron LI goto again; 19257827cba2SAaron LI } 19267827cba2SAaron LI memset(state->randomid, 0, sizeof(state->randomid)); 19277827cba2SAaron LI } 19287827cba2SAaron LI 19297827cba2SAaron LI /* RFC4941 Section 3.2.1.6 19307827cba2SAaron LI * Save the right-most 64bits of the digest */ 19317827cba2SAaron LI memcpy(state->randomseed0, digest + 8, 19327827cba2SAaron LI sizeof(state->randomseed0)); 19337827cba2SAaron LI } 19347827cba2SAaron LI 19357827cba2SAaron LI /* RFC4941 Section 3.3.7 */ 19367827cba2SAaron LI static void 19377827cba2SAaron LI ipv6_tempdadcallback(void *arg) 19387827cba2SAaron LI { 19397827cba2SAaron LI struct ipv6_addr *ia = arg; 19407827cba2SAaron LI 19417827cba2SAaron LI if (ia->flags & IPV6_AF_DUPLICATED) { 19427827cba2SAaron LI struct ipv6_addr *ia1; 19437827cba2SAaron LI struct timespec tv; 19447827cba2SAaron LI 19457827cba2SAaron LI if (++ia->dadcounter == TEMP_IDGEN_RETRIES) { 19467827cba2SAaron LI logerrx("%s: too many duplicate temporary addresses", 19477827cba2SAaron LI ia->iface->name); 19487827cba2SAaron LI return; 19497827cba2SAaron LI } 19507827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &tv); 19517827cba2SAaron LI if ((ia1 = ipv6_createtempaddr(ia, &tv)) == NULL) 19527827cba2SAaron LI logerr(__func__); 19537827cba2SAaron LI else 19547827cba2SAaron LI ia1->dadcounter = ia->dadcounter; 19557827cba2SAaron LI ipv6_deleteaddr(ia); 19567827cba2SAaron LI if (ia1) 19577827cba2SAaron LI ipv6_addaddr(ia1, &ia1->acquired); 19587827cba2SAaron LI } 19597827cba2SAaron LI } 19607827cba2SAaron LI 19617827cba2SAaron LI struct ipv6_addr * 19627827cba2SAaron LI ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now) 19637827cba2SAaron LI { 19647827cba2SAaron LI struct ipv6_state *state; 19657827cba2SAaron LI const struct ipv6_state *cstate; 19667827cba2SAaron LI int genid; 19677827cba2SAaron LI struct in6_addr addr, mask; 19687827cba2SAaron LI uint32_t randid[2]; 19697827cba2SAaron LI const struct interface *ifp; 19707827cba2SAaron LI const struct ipv6_addr *ap; 19717827cba2SAaron LI struct ipv6_addr *ia; 19727827cba2SAaron LI uint32_t i, trylimit; 19737827cba2SAaron LI 19747827cba2SAaron LI trylimit = TEMP_IDGEN_RETRIES; 19757827cba2SAaron LI state = IPV6_STATE(ia0->iface); 19767827cba2SAaron LI genid = 0; 19777827cba2SAaron LI 19787827cba2SAaron LI addr = ia0->addr; 19797827cba2SAaron LI ipv6_mask(&mask, ia0->prefix_len); 19807827cba2SAaron LI /* clear the old ifid */ 19817827cba2SAaron LI for (i = 0; i < 4; i++) 19827827cba2SAaron LI addr.s6_addr32[i] &= mask.s6_addr32[i]; 19837827cba2SAaron LI 19847827cba2SAaron LI again: 19857827cba2SAaron LI if (memcmp(state->randomid, nullid, sizeof(nullid)) == 0) 19867827cba2SAaron LI genid = 1; 19877827cba2SAaron LI if (genid) { 19887827cba2SAaron LI memcpy(state->randomseed1, &ia0->addr.s6_addr[8], 19897827cba2SAaron LI sizeof(state->randomseed1)); 19907827cba2SAaron LI ipv6_gentempifid(ia0->iface); 19917827cba2SAaron LI if (memcmp(state->randomid, nullid, sizeof(nullid)) == 0) { 19927827cba2SAaron LI errno = EFAULT; 19937827cba2SAaron LI return NULL; 19947827cba2SAaron LI } 19957827cba2SAaron LI } 19967827cba2SAaron LI memcpy(&randid[0], state->randomid, sizeof(randid[0])); 19977827cba2SAaron LI memcpy(&randid[1], state->randomid + sizeof(randid[1]), 19987827cba2SAaron LI sizeof(randid[2])); 19997827cba2SAaron LI addr.s6_addr32[2] |= randid[0] & ~mask.s6_addr32[2]; 20007827cba2SAaron LI addr.s6_addr32[3] |= randid[1] & ~mask.s6_addr32[3]; 20017827cba2SAaron LI 20027827cba2SAaron LI /* Ensure we don't already have it */ 20037827cba2SAaron LI TAILQ_FOREACH(ifp, ia0->iface->ctx->ifaces, next) { 20047827cba2SAaron LI cstate = IPV6_CSTATE(ifp); 20057827cba2SAaron LI if (cstate) { 20067827cba2SAaron LI TAILQ_FOREACH(ap, &cstate->addrs, next) { 20077827cba2SAaron LI if (IN6_ARE_ADDR_EQUAL(&ap->addr, &addr)) { 20087827cba2SAaron LI if (--trylimit == 0) { 20097827cba2SAaron LI errno = EEXIST; 20107827cba2SAaron LI return NULL; 20117827cba2SAaron LI } 20127827cba2SAaron LI genid = 1; 20137827cba2SAaron LI goto again; 20147827cba2SAaron LI } 20157827cba2SAaron LI } 20167827cba2SAaron LI } 20177827cba2SAaron LI } 20187827cba2SAaron LI 20197827cba2SAaron LI ia = ipv6_newaddr(ia0->iface, &addr, ia0->prefix_len, 20207827cba2SAaron LI IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY); 20217827cba2SAaron LI /* Must be made tentative, for our DaD to work */ 20227827cba2SAaron LI ia->addr_flags = IN6_IFF_TENTATIVE; 20237827cba2SAaron LI ia->dadcallback = ipv6_tempdadcallback; 20247827cba2SAaron LI ia->created = ia->acquired = now ? *now : ia0->acquired; 20257827cba2SAaron LI 20267827cba2SAaron LI /* Ensure desync is still valid */ 20277827cba2SAaron LI ipv6_regen_desync(ia->iface, 0); 20287827cba2SAaron LI 20297827cba2SAaron LI /* RFC4941 Section 3.3.4 */ 20307827cba2SAaron LI i = (uint32_t)(ip6_temp_preferred_lifetime(ia0->iface->name) - 20317827cba2SAaron LI state->desync_factor); 20327827cba2SAaron LI ia->prefix_pltime = MIN(ia0->prefix_pltime, i); 20337827cba2SAaron LI i = (uint32_t)ip6_temp_valid_lifetime(ia0->iface->name); 20347827cba2SAaron LI ia->prefix_vltime = MIN(ia0->prefix_vltime, i); 20357827cba2SAaron LI if (ia->prefix_pltime <= REGEN_ADVANCE || 20367827cba2SAaron LI ia->prefix_pltime > ia0->prefix_vltime) 20377827cba2SAaron LI { 20387827cba2SAaron LI errno = EINVAL; 20397827cba2SAaron LI free(ia); 20407827cba2SAaron LI return NULL; 20417827cba2SAaron LI } 20427827cba2SAaron LI 20437827cba2SAaron LI TAILQ_INSERT_TAIL(&state->addrs, ia, next); 20447827cba2SAaron LI return ia; 20457827cba2SAaron LI } 20467827cba2SAaron LI 20477827cba2SAaron LI struct ipv6_addr * 20487827cba2SAaron LI ipv6_settemptime(struct ipv6_addr *ia, int flags) 20497827cba2SAaron LI { 20507827cba2SAaron LI struct ipv6_state *state; 20517827cba2SAaron LI struct ipv6_addr *ap, *first; 20527827cba2SAaron LI 20537827cba2SAaron LI state = IPV6_STATE(ia->iface); 20547827cba2SAaron LI first = NULL; 20557827cba2SAaron LI TAILQ_FOREACH_REVERSE(ap, &state->addrs, ipv6_addrhead, next) { 20567827cba2SAaron LI if (ap->flags & IPV6_AF_TEMPORARY && 20577827cba2SAaron LI ap->prefix_pltime && 20587827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix)) 20597827cba2SAaron LI { 20607827cba2SAaron LI time_t max, ext; 20617827cba2SAaron LI 20627827cba2SAaron LI if (flags == 0) { 20637827cba2SAaron LI if (ap->prefix_pltime - 20647827cba2SAaron LI (uint32_t)(ia->acquired.tv_sec - 20657827cba2SAaron LI ap->acquired.tv_sec) 20667827cba2SAaron LI < REGEN_ADVANCE) 20677827cba2SAaron LI continue; 20687827cba2SAaron LI 20697827cba2SAaron LI return ap; 20707827cba2SAaron LI } 20717827cba2SAaron LI 20727827cba2SAaron LI if (!(ap->flags & IPV6_AF_ADDED)) 20737827cba2SAaron LI ap->flags |= IPV6_AF_NEW | IPV6_AF_AUTOCONF; 20747827cba2SAaron LI ap->flags &= ~IPV6_AF_STALE; 20757827cba2SAaron LI 20767827cba2SAaron LI /* RFC4941 Section 3.4 20777827cba2SAaron LI * Deprecated prefix, deprecate the temporary address */ 20787827cba2SAaron LI if (ia->prefix_pltime == 0) { 20797827cba2SAaron LI ap->prefix_pltime = 0; 20807827cba2SAaron LI goto valid; 20817827cba2SAaron LI } 20827827cba2SAaron LI 20837827cba2SAaron LI /* Ensure desync is still valid */ 20847827cba2SAaron LI ipv6_regen_desync(ap->iface, 0); 20857827cba2SAaron LI 20867827cba2SAaron LI /* RFC4941 Section 3.3.2 20877827cba2SAaron LI * Extend temporary times, but ensure that they 20887827cba2SAaron LI * never last beyond the system limit. */ 20897827cba2SAaron LI ext = ia->acquired.tv_sec + (time_t)ia->prefix_pltime; 20907827cba2SAaron LI max = ap->created.tv_sec + 20917827cba2SAaron LI ip6_temp_preferred_lifetime(ap->iface->name) - 20927827cba2SAaron LI state->desync_factor; 20937827cba2SAaron LI if (ext < max) 20947827cba2SAaron LI ap->prefix_pltime = ia->prefix_pltime; 20957827cba2SAaron LI else 20967827cba2SAaron LI ap->prefix_pltime = 20977827cba2SAaron LI (uint32_t)(max - ia->acquired.tv_sec); 20987827cba2SAaron LI 20997827cba2SAaron LI valid: 21007827cba2SAaron LI ext = ia->acquired.tv_sec + (time_t)ia->prefix_vltime; 21017827cba2SAaron LI max = ap->created.tv_sec + 21027827cba2SAaron LI ip6_temp_valid_lifetime(ap->iface->name); 21037827cba2SAaron LI if (ext < max) 21047827cba2SAaron LI ap->prefix_vltime = ia->prefix_vltime; 21057827cba2SAaron LI else 21067827cba2SAaron LI ap->prefix_vltime = 21077827cba2SAaron LI (uint32_t)(max - ia->acquired.tv_sec); 21087827cba2SAaron LI 21097827cba2SAaron LI /* Just extend the latest matching prefix */ 21107827cba2SAaron LI ap->acquired = ia->acquired; 21117827cba2SAaron LI 21127827cba2SAaron LI /* If extending return the last match as 21137827cba2SAaron LI * it's the most current. 21147827cba2SAaron LI * If deprecating, deprecate any other addresses we 21157827cba2SAaron LI * may have, although this should not be needed */ 21167827cba2SAaron LI if (ia->prefix_pltime) 21177827cba2SAaron LI return ap; 21187827cba2SAaron LI if (first == NULL) 21197827cba2SAaron LI first = ap; 21207827cba2SAaron LI } 21217827cba2SAaron LI } 21227827cba2SAaron LI return first; 21237827cba2SAaron LI } 21247827cba2SAaron LI 21257827cba2SAaron LI void 21267827cba2SAaron LI ipv6_addtempaddrs(struct interface *ifp, const struct timespec *now) 21277827cba2SAaron LI { 21287827cba2SAaron LI struct ipv6_state *state; 21297827cba2SAaron LI struct ipv6_addr *ia; 21307827cba2SAaron LI 21317827cba2SAaron LI state = IPV6_STATE(ifp); 21327827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 21337827cba2SAaron LI if (ia->flags & IPV6_AF_TEMPORARY && 21347827cba2SAaron LI !(ia->flags & IPV6_AF_STALE)) 21357827cba2SAaron LI ipv6_addaddr(ia, now); 21367827cba2SAaron LI } 21377827cba2SAaron LI } 21387827cba2SAaron LI 21397827cba2SAaron LI static void 21407827cba2SAaron LI ipv6_regentempaddr(void *arg) 21417827cba2SAaron LI { 21427827cba2SAaron LI struct ipv6_addr *ia = arg, *ia1; 21437827cba2SAaron LI struct timespec tv; 21447827cba2SAaron LI 21457827cba2SAaron LI logdebugx("%s: regen temp addr %s", ia->iface->name, ia->saddr); 21467827cba2SAaron LI clock_gettime(CLOCK_MONOTONIC, &tv); 21477827cba2SAaron LI ia1 = ipv6_createtempaddr(ia, &tv); 21487827cba2SAaron LI if (ia1) 21497827cba2SAaron LI ipv6_addaddr(ia1, &tv); 21507827cba2SAaron LI else 21517827cba2SAaron LI logerr(__func__); 21527827cba2SAaron LI } 21537827cba2SAaron LI 21547827cba2SAaron LI static void 21557827cba2SAaron LI ipv6_regentempifid(void *arg) 21567827cba2SAaron LI { 21577827cba2SAaron LI struct interface *ifp = arg; 21587827cba2SAaron LI struct ipv6_state *state; 21597827cba2SAaron LI 21607827cba2SAaron LI state = IPV6_STATE(ifp); 21617827cba2SAaron LI if (memcmp(state->randomid, nullid, sizeof(state->randomid))) 21627827cba2SAaron LI ipv6_gentempifid(ifp); 21637827cba2SAaron LI 21647827cba2SAaron LI ipv6_regen_desync(ifp, 1); 21657827cba2SAaron LI } 21667827cba2SAaron LI #endif /* IPV6_MANAGETEMPADDR */ 21677827cba2SAaron LI 21687827cba2SAaron LI void 21697827cba2SAaron LI ipv6_markaddrsstale(struct interface *ifp, unsigned int flags) 21707827cba2SAaron LI { 21717827cba2SAaron LI struct ipv6_state *state; 21727827cba2SAaron LI struct ipv6_addr *ia; 21737827cba2SAaron LI 21747827cba2SAaron LI state = IPV6_STATE(ifp); 21757827cba2SAaron LI if (state == NULL) 21767827cba2SAaron LI return; 21777827cba2SAaron LI 21787827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 21797827cba2SAaron LI if (flags == 0 || ia->flags & flags) 21807827cba2SAaron LI ia->flags |= IPV6_AF_STALE; 21817827cba2SAaron LI } 21827827cba2SAaron LI } 21837827cba2SAaron LI 21847827cba2SAaron LI void 21857827cba2SAaron LI ipv6_deletestaleaddrs(struct interface *ifp) 21867827cba2SAaron LI { 21877827cba2SAaron LI struct ipv6_state *state; 21887827cba2SAaron LI struct ipv6_addr *ia, *ia1; 21897827cba2SAaron LI 21907827cba2SAaron LI state = IPV6_STATE(ifp); 21917827cba2SAaron LI if (state == NULL) 21927827cba2SAaron LI return; 21937827cba2SAaron LI 21947827cba2SAaron LI TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ia1) { 21957827cba2SAaron LI if (ia->flags & IPV6_AF_STALE) 21967827cba2SAaron LI ipv6_handleifa(ifp->ctx, RTM_DELADDR, 21977827cba2SAaron LI ifp->ctx->ifaces, ifp->name, 21987827cba2SAaron LI &ia->addr, ia->prefix_len, 0, getpid()); 21997827cba2SAaron LI } 22007827cba2SAaron LI } 22017827cba2SAaron LI 22027827cba2SAaron LI 22037827cba2SAaron LI static struct rt * 22047827cba2SAaron LI inet6_makeroute(struct interface *ifp, const struct ra *rap) 22057827cba2SAaron LI { 22067827cba2SAaron LI struct rt *rt; 22077827cba2SAaron LI 22087827cba2SAaron LI if ((rt = rt_new(ifp)) == NULL) 22097827cba2SAaron LI return NULL; 22107827cba2SAaron LI 22117827cba2SAaron LI #ifdef HAVE_ROUTE_METRIC 22127827cba2SAaron LI rt->rt_metric = ifp->metric; 22137827cba2SAaron LI #endif 22147827cba2SAaron LI if (rap != NULL) 22157827cba2SAaron LI rt->rt_mtu = rap->mtu; 22167827cba2SAaron LI return rt; 22177827cba2SAaron LI } 22187827cba2SAaron LI 22197827cba2SAaron LI static struct rt * 22207827cba2SAaron LI inet6_makeprefix(struct interface *ifp, const struct ra *rap, 22217827cba2SAaron LI const struct ipv6_addr *addr) 22227827cba2SAaron LI { 22237827cba2SAaron LI struct rt *rt; 22247827cba2SAaron LI struct in6_addr netmask; 22257827cba2SAaron LI 22267827cba2SAaron LI if (addr == NULL || addr->prefix_len > 128) { 22277827cba2SAaron LI errno = EINVAL; 22287827cba2SAaron LI return NULL; 22297827cba2SAaron LI } 22307827cba2SAaron LI 22317827cba2SAaron LI /* There is no point in trying to manage a /128 prefix, 2232*8d36e1dfSRoy Marples * ones without a lifetime. */ 2233*8d36e1dfSRoy Marples if (addr->prefix_len == 128 || addr->prefix_vltime == 0) 22347827cba2SAaron LI return NULL; 22357827cba2SAaron LI 2236*8d36e1dfSRoy Marples /* Don't install a reject route when not creating bigger prefixes. */ 22377827cba2SAaron LI if (addr->flags & IPV6_AF_NOREJECT) 22387827cba2SAaron LI return NULL; 22397827cba2SAaron LI 22407827cba2SAaron LI /* This address is the delegated prefix, so add a reject route for 22417827cba2SAaron LI * it via the loopback interface. */ 22427827cba2SAaron LI if (addr->flags & IPV6_AF_DELEGATEDPFX) { 22437827cba2SAaron LI struct interface *lo0; 22447827cba2SAaron LI 22457827cba2SAaron LI TAILQ_FOREACH(lo0, ifp->ctx->ifaces, next) { 22467827cba2SAaron LI if (lo0->flags & IFF_LOOPBACK) 22477827cba2SAaron LI break; 22487827cba2SAaron LI } 22497827cba2SAaron LI if (lo0 == NULL) 22507827cba2SAaron LI logwarnx("cannot find a loopback interface " 22517827cba2SAaron LI "to reject via"); 22527827cba2SAaron LI else 22537827cba2SAaron LI ifp = lo0; 22547827cba2SAaron LI } 22557827cba2SAaron LI 22567827cba2SAaron LI if ((rt = inet6_makeroute(ifp, rap)) == NULL) 22577827cba2SAaron LI return NULL; 22587827cba2SAaron LI 22597827cba2SAaron LI sa_in6_init(&rt->rt_dest, &addr->prefix); 22607827cba2SAaron LI ipv6_mask(&netmask, addr->prefix_len); 22617827cba2SAaron LI sa_in6_init(&rt->rt_netmask, &netmask); 22627827cba2SAaron LI if (addr->flags & IPV6_AF_DELEGATEDPFX) { 22637827cba2SAaron LI rt->rt_flags |= RTF_REJECT; 22647827cba2SAaron LI /* Linux does not like a gateway for a reject route. */ 22657827cba2SAaron LI #ifndef __linux__ 22667827cba2SAaron LI sa_in6_init(&rt->rt_gateway, &in6addr_loopback); 22677827cba2SAaron LI #endif 2268*8d36e1dfSRoy Marples } else if (!(addr->flags & IPV6_AF_ONLINK)) 2269*8d36e1dfSRoy Marples sa_in6_init(&rt->rt_gateway, &rap->from); 2270*8d36e1dfSRoy Marples else 22717827cba2SAaron LI rt->rt_gateway.sa_family = AF_UNSPEC; 22727827cba2SAaron LI sa_in6_init(&rt->rt_ifa, &addr->addr); 22737827cba2SAaron LI return rt; 22747827cba2SAaron LI } 22757827cba2SAaron LI 22767827cba2SAaron LI static struct rt * 22777827cba2SAaron LI inet6_makerouter(struct ra *rap) 22787827cba2SAaron LI { 22797827cba2SAaron LI struct rt *rt; 22807827cba2SAaron LI 22817827cba2SAaron LI if ((rt = inet6_makeroute(rap->iface, rap)) == NULL) 22827827cba2SAaron LI return NULL; 22837827cba2SAaron LI sa_in6_init(&rt->rt_dest, &in6addr_any); 22847827cba2SAaron LI sa_in6_init(&rt->rt_netmask, &in6addr_any); 22857827cba2SAaron LI sa_in6_init(&rt->rt_gateway, &rap->from); 22867827cba2SAaron LI return rt; 22877827cba2SAaron LI } 22887827cba2SAaron LI 22897827cba2SAaron LI #define RT_IS_DEFAULT(rtp) \ 22907827cba2SAaron LI (IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) && \ 22917827cba2SAaron LI IN6_ARE_ADDR_EQUAL(&((rtp)->mask), &in6addr_any)) 22927827cba2SAaron LI 22937827cba2SAaron LI static int 2294*8d36e1dfSRoy Marples inet6_staticroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) 22957827cba2SAaron LI { 22967827cba2SAaron LI struct interface *ifp; 22977827cba2SAaron LI struct ipv6_state *state; 22987827cba2SAaron LI struct ipv6_addr *ia; 22997827cba2SAaron LI struct rt *rt; 23007827cba2SAaron LI 23017827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 23027827cba2SAaron LI if ((state = IPV6_STATE(ifp)) == NULL) 23037827cba2SAaron LI continue; 23047827cba2SAaron LI TAILQ_FOREACH(ia, &state->addrs, next) { 23057827cba2SAaron LI if ((ia->flags & (IPV6_AF_ADDED | IPV6_AF_STATIC)) == 23067827cba2SAaron LI (IPV6_AF_ADDED | IPV6_AF_STATIC)) 23077827cba2SAaron LI { 23087827cba2SAaron LI rt = inet6_makeprefix(ifp, NULL, ia); 23097827cba2SAaron LI if (rt) 2310*8d36e1dfSRoy Marples rt_proto_add(routes, rt); 23117827cba2SAaron LI } 23127827cba2SAaron LI } 23137827cba2SAaron LI } 23147827cba2SAaron LI return 0; 23157827cba2SAaron LI } 23167827cba2SAaron LI 23177827cba2SAaron LI static int 2318*8d36e1dfSRoy Marples inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) 23197827cba2SAaron LI { 23207827cba2SAaron LI struct rt *rt; 23217827cba2SAaron LI struct ra *rap; 23227827cba2SAaron LI const struct ipv6_addr *addr; 23237827cba2SAaron LI 23247827cba2SAaron LI TAILQ_FOREACH(rap, ctx->ra_routers, next) { 2325*8d36e1dfSRoy Marples if (rap->expired) 23267827cba2SAaron LI continue; 23277827cba2SAaron LI TAILQ_FOREACH(addr, &rap->addrs, next) { 23287827cba2SAaron LI if (addr->prefix_vltime == 0) 23297827cba2SAaron LI continue; 23307827cba2SAaron LI rt = inet6_makeprefix(rap->iface, rap, addr); 23317827cba2SAaron LI if (rt) { 23327827cba2SAaron LI rt->rt_dflags |= RTDF_RA; 2333*8d36e1dfSRoy Marples rt_proto_add(routes, rt); 23347827cba2SAaron LI } 23357827cba2SAaron LI } 2336*8d36e1dfSRoy Marples if (rap->lifetime == 0) 2337*8d36e1dfSRoy Marples continue; 2338*8d36e1dfSRoy Marples if (ipv6_ifanyglobal(rap->iface) == NULL) 2339*8d36e1dfSRoy Marples continue; 23407827cba2SAaron LI rt = inet6_makerouter(rap); 2341*8d36e1dfSRoy Marples if (rt == NULL) 2342*8d36e1dfSRoy Marples continue; 23437827cba2SAaron LI rt->rt_dflags |= RTDF_RA; 2344*8d36e1dfSRoy Marples rt_proto_add(routes, rt); 23457827cba2SAaron LI } 23467827cba2SAaron LI return 0; 23477827cba2SAaron LI } 23487827cba2SAaron LI 2349*8d36e1dfSRoy Marples #ifdef DHCP6 23507827cba2SAaron LI static int 2351*8d36e1dfSRoy Marples inet6_dhcproutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx, 23527827cba2SAaron LI enum DH6S dstate) 23537827cba2SAaron LI { 23547827cba2SAaron LI struct interface *ifp; 23557827cba2SAaron LI const struct dhcp6_state *d6_state; 23567827cba2SAaron LI const struct ipv6_addr *addr; 23577827cba2SAaron LI struct rt *rt; 23587827cba2SAaron LI 23597827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) { 23607827cba2SAaron LI d6_state = D6_CSTATE(ifp); 23617827cba2SAaron LI if (d6_state && d6_state->state == dstate) { 23627827cba2SAaron LI TAILQ_FOREACH(addr, &d6_state->addrs, next) { 23637827cba2SAaron LI rt = inet6_makeprefix(ifp, NULL, addr); 2364*8d36e1dfSRoy Marples if (rt == NULL) 2365*8d36e1dfSRoy Marples continue; 23667827cba2SAaron LI rt->rt_dflags |= RTDF_DHCP; 2367*8d36e1dfSRoy Marples rt_proto_add(routes, rt); 23687827cba2SAaron LI } 23697827cba2SAaron LI } 23707827cba2SAaron LI } 23717827cba2SAaron LI return 0; 23727827cba2SAaron LI } 2373*8d36e1dfSRoy Marples #endif 23747827cba2SAaron LI 23757827cba2SAaron LI bool 2376*8d36e1dfSRoy Marples inet6_getroutes(struct dhcpcd_ctx *ctx, rb_tree_t *routes) 23777827cba2SAaron LI { 23787827cba2SAaron LI 23797827cba2SAaron LI /* Should static take priority? */ 23807827cba2SAaron LI if (inet6_staticroutes(routes, ctx) == -1) 23817827cba2SAaron LI return false; 23827827cba2SAaron LI 23837827cba2SAaron LI /* First add reachable routers and their prefixes */ 2384*8d36e1dfSRoy Marples if (inet6_raroutes(routes, ctx) == -1) 23857827cba2SAaron LI return false; 23867827cba2SAaron LI 2387*8d36e1dfSRoy Marples #ifdef DHCP6 23887827cba2SAaron LI /* We have no way of knowing if prefixes added by DHCP are reachable 23897827cba2SAaron LI * or not, so we have to assume they are. 2390*8d36e1dfSRoy Marples * Add bound before delegated so we can prefer interfaces better. */ 23917827cba2SAaron LI if (inet6_dhcproutes(routes, ctx, DH6S_BOUND) == -1) 23927827cba2SAaron LI return false; 23937827cba2SAaron LI if (inet6_dhcproutes(routes, ctx, DH6S_DELEGATED) == -1) 23947827cba2SAaron LI return false; 23957827cba2SAaron LI #endif 23967827cba2SAaron LI 23977827cba2SAaron LI return true; 23987827cba2SAaron LI } 2399