From owner-freebsd-net@freebsd.org Fri Apr 3 01:56:15 2020 Return-Path: Delivered-To: freebsd-net@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 89A3F26FAEA for ; Fri, 3 Apr 2020 01:56:15 +0000 (UTC) (envelope-from fernando@gont.com.ar) Received: from fgont.go6lab.si (fgont.go6lab.si [91.239.96.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 48tjhN4Msvz4cCs; Fri, 3 Apr 2020 01:56:03 +0000 (UTC) (envelope-from fernando@gont.com.ar) Received: from [192.168.0.10] (unknown [181.45.84.85]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by fgont.go6lab.si (Postfix) with ESMTPSA id 9ABB2893AE; Fri, 3 Apr 2020 03:55:52 +0200 (CEST) To: FreeBSD Net Cc: Hiroki Sato From: Fernando Gont Subject: [PATCH] Implement the upcoming RFC4941bis (IPv6 SLAAC temporary addresses/privacy extensions) Message-ID: <93726ba6-6d96-2b45-81c5-6fd8a83f95a9@gont.com.ar> Date: Thu, 2 Apr 2020 22:55:20 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.9.1 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-Rspamd-Queue-Id: 48tjhN4Msvz4cCs X-Spamd-Bar: ----- Authentication-Results: mx1.freebsd.org; dkim=none; dmarc=none; spf=pass (mx1.freebsd.org: domain of fernando@gont.com.ar designates 91.239.96.14 as permitted sender) smtp.mailfrom=fernando@gont.com.ar X-Spamd-Result: default: False [-5.79 / 15.00]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; FROM_HAS_DN(0.00)[]; R_SPF_ALLOW(-0.20)[+a]; TO_MATCH_ENVRCPT_ALL(0.00)[]; MIME_GOOD(-0.10)[text/plain]; DMARC_NA(0.00)[gont.com.ar]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; IP_SCORE(-3.49)[ip: (-9.26), ipnet: 91.239.96.0/23(-4.63), asn: 198644(-3.59), country: SI(0.01)]; TO_DN_ALL(0.00)[]; RCPT_COUNT_TWO(0.00)[2]; RCVD_IN_DNSWL_NONE(0.00)[14.96.239.91.list.dnswl.org : 127.0.10.0]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; MIME_TRACE(0.00)[0:+]; ASN(0.00)[asn:198644, ipnet:91.239.96.0/23, country:SI]; MID_RHS_MATCH_FROM(0.00)[]; RCVD_TLS_ALL(0.00)[]; RCVD_COUNT_TWO(0.00)[2] X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 03 Apr 2020 01:56:17 -0000 Folks/Hiroki, I've implemented the upcoming revision of RFC4941 (https://tools.ietf.org/html/draft-ietf-6man-rfc4941bis-08) for FreeBSD. The main changes are this: * Reduce the Valid Lifetime from 1 week to 2 days. This effectively limits the number of concurrent temporary addresses per prefix to 2 * Use different interface-ids for each temporary address, to prevent correlation of network activity among temporary addresses corresponding to different prefixes. P.S.: The patch is also available here: ---- cut here ---- diff --git sys/netinet6/in6_ifattach.c sys/netinet6/in6_ifattach.c index 91ef544d8b2..c093b53974a 100644 --- sys/netinet6/in6_ifattach.c +++ sys/netinet6/in6_ifattach.c @@ -87,7 +87,6 @@ VNET_DECLARE(struct inpcbinfo, ripcbinfo); #define V_ripcbinfo VNET(ripcbinfo) static int get_rand_ifid(struct ifnet *, struct in6_addr *); -static int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *); static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *); static int in6_ifattach_loopback(struct ifnet *); @@ -152,84 +151,6 @@ get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) return 0; } -static int -generate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret) -{ - MD5_CTX ctxt; - u_int8_t seed[16], digest[16], nullbuf[8]; - u_int32_t val32; - - /* If there's no history, start with a random seed. */ - bzero(nullbuf, sizeof(nullbuf)); - if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { - int i; - - for (i = 0; i < 2; i++) { - val32 = arc4random(); - bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); - } - } else - bcopy(seed0, seed, 8); - - /* copy the right-most 64-bits of the given address */ - /* XXX assumption on the size of IFID */ - bcopy(seed1, &seed[8], 8); - - if (0) { /* for debugging purposes only */ - int i; - - printf("generate_tmp_ifid: new randomized ID from: "); - for (i = 0; i < 16; i++) - printf("%02x", seed[i]); - printf(" "); - } - - /* generate 16 bytes of pseudo-random value. */ - bzero(&ctxt, sizeof(ctxt)); - MD5Init(&ctxt); - MD5Update(&ctxt, seed, sizeof(seed)); - MD5Final(digest, &ctxt); - - /* - * RFC 3041 3.2.1. (3) - * Take the left-most 64-bits of the MD5 digest and set bit 6 (the - * left-most bit is numbered 0) to zero. - */ - bcopy(digest, ret, 8); - ret[0] &= ~EUI64_UBIT; - - /* - * XXX: we'd like to ensure that the generated value is not zero - * for simplicity. If the caclculated digest happens to be zero, - * use a random non-zero value as the last resort. - */ - if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { - nd6log((LOG_INFO, - "generate_tmp_ifid: computed MD5 value is zero.\n")); - - val32 = arc4random(); - val32 = 1 + (val32 % (0xffffffff - 1)); - } - - /* - * RFC 3041 3.2.1. (4) - * Take the rightmost 64-bits of the MD5 digest and save them in - * stable storage as the history value to be used in the next - * iteration of the algorithm. - */ - bcopy(&digest[8], seed0, 8); - - if (0) { /* for debugging purposes only */ - int i; - - printf("to: "); - for (i = 0; i < 16; i++) - printf("%02x", digest[i]); - printf("\n"); - } - - return 0; -} /* * Get interface identifier for the specified interface. @@ -798,58 +719,15 @@ in6_ifdetach_destroy(struct ifnet *ifp) _in6_ifdetach(ifp, 0); } -int -in6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf, - const u_int8_t *baseid, int generate) -{ - u_int8_t nullbuf[8]; - struct nd_ifinfo *ndi = ND_IFINFO(ifp); - - bzero(nullbuf, sizeof(nullbuf)); - if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { - /* we've never created a random ID. Create a new one. */ - generate = 1; - } - - if (generate) { - bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); - - /* generate_tmp_ifid will update seedn and buf */ - (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, - ndi->randomid); - } - bcopy(ndi->randomid, retbuf, 8); - - return (0); -} - void in6_tmpaddrtimer(void *arg) { CURVNET_SET((struct vnet *) arg); - struct nd_ifinfo *ndi; - u_int8_t nullbuf[8]; - struct ifnet *ifp; callout_reset(&V_in6_tmpaddrtimer_ch, (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor - V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet); - bzero(nullbuf, sizeof(nullbuf)); - CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { - if (ifp->if_afdata[AF_INET6] == NULL) - continue; - ndi = ND_IFINFO(ifp); - if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { - /* - * We've been generating a random ID on this interface. - * Create a new one. - */ - (void)generate_tmp_ifid(ndi->randomseed0, - ndi->randomseed1, ndi->randomid); - } - } - CURVNET_RESTORE(); } diff --git sys/netinet6/in6_ifattach.h sys/netinet6/in6_ifattach.h index 1e038fa8319..b9983200447 100644 --- sys/netinet6/in6_ifattach.h +++ sys/netinet6/in6_ifattach.h @@ -40,7 +40,6 @@ void in6_ifattach(struct ifnet *, struct ifnet *); void in6_ifattach_destroy(void); void in6_ifdetach(struct ifnet *); void in6_ifdetach_destroy(struct ifnet *); -int in6_get_tmpifid(struct ifnet *, u_int8_t *, const u_int8_t *, int); void in6_tmpaddrtimer(void *); int in6_get_hw_ifid(struct ifnet *, struct in6_addr *); int in6_nigroup(struct ifnet *, const char *, int, struct in6_addr *); diff --git sys/netinet6/nd6.h sys/netinet6/nd6.h index 857657f6e20..c88f37288a2 100644 --- sys/netinet6/nd6.h +++ sys/netinet6/nd6.h @@ -185,7 +185,7 @@ struct in6_ndifreq { #define RETRANS_TIMER 1000 /* msec */ #define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */ #define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */ -#define DEF_TEMP_VALID_LIFETIME 604800 /* 1 week */ +#define DEF_TEMP_VALID_LIFETIME 172800 /* 2 days */ #define DEF_TEMP_PREFERRED_LIFETIME 86400 /* 1 day */ #define TEMPADDR_REGEN_ADVANCE 5 /* sec */ #define MAX_TEMP_DESYNC_FACTOR 600 /* 10 min */ diff --git sys/netinet6/nd6_rtr.c sys/netinet6/nd6_rtr.c index d678a53233e..179238257bb 100644 --- sys/netinet6/nd6_rtr.c +++ sys/netinet6/nd6_rtr.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -77,6 +78,7 @@ static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *, struct mbuf *, int); static int nd6_prefix_onlink(struct nd_prefix *); +static int in6_get_tmp_ifid(struct in6_aliasreq *); TAILQ_HEAD(nd6_drhead, nd_defrouter); VNET_DEFINE_STATIC(struct nd6_drhead, nd6_defrouter); @@ -2248,6 +2250,51 @@ nd6_prefix_offlink(struct nd_prefix *pr) return (error); } +/* + * Get a randomized interface identifier for a temporary address + * , Section 3.3.1. + */ +static int +in6_get_tmp_ifid(struct in6_aliasreq *ifra) +{ + struct in6_addr *addr; + + if(!is_random_seeded()){ + return 1; + } + + addr = &(ifra->ifra_addr.sin6_addr); +regen: + ifra->ifra_addr.sin6_addr.s6_addr32[2] |= + (arc4random() & ~(ifra->ifra_prefixmask.sin6_addr.s6_addr32[2])); + ifra->ifra_addr.sin6_addr.s6_addr32[3] |= + (arc4random() & ~(ifra->ifra_prefixmask.sin6_addr.s6_addr32[3])); + + /* + * check if generated address is not inappropriate: + * + * - Reserved IPv6 Interface Identifers + * (http://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xhtml) + */ + + /* Subnet-router anycast: 0000:0000:0000:0000 */ + if (!(addr->s6_addr32[2] | addr->s6_addr32[3])) + goto regen; + + /* IANA Ethernet block: 0200:5EFF:FE00:0000-0200:5EFF:FE00:5212 + Proxy Mobile IPv6: 0200:5EFF:FE00:5213 + IANA Ethernet block: 0200:5EFF:FE00:5214-0200:5EFF:FEFF:FFFF + */ + if (ntohl(addr->s6_addr32[2]) == 0x02005eff && (ntohl(addr->s6_addr32[3]) & 0Xff000000) == 0xfe000000) + goto regen; + + /* Reserved subnet anycast addresses */ + if (ntohl(addr->s6_addr32[2]) == 0xfdffffff && ntohl(addr->s6_addr32[3]) >= 0Xffffff80) + goto regen; + + return 0; +} + /* * ia0 - corresponding public address */ @@ -2260,7 +2307,6 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) int error; int trylimit = 3; /* XXX: adhoc value */ int updateflags; - u_int32_t randid[2]; time_t vltime0, pltime0; in6_prepare_ifra(&ifra, &ia0->ia_addr.sin6_addr, @@ -2272,16 +2318,11 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) &ifra.ifra_prefixmask.sin6_addr); again: - if (in6_get_tmpifid(ifp, (u_int8_t *)randid, - (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { + if (in6_get_tmp_ifid(&ifra) != 0) { nd6log((LOG_NOTICE, "%s: failed to find a good random IFID\n", __func__)); return (EINVAL); } - ifra.ifra_addr.sin6_addr.s6_addr32[2] |= - (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); - ifra.ifra_addr.sin6_addr.s6_addr32[3] |= - (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); /* * in6_get_tmpifid() quite likely provided a unique interface ID. @@ -2289,7 +2330,6 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) * there may be a time lag between generation of the ID and generation * of the address. So, we'll do one more sanity check. */ - if (in6_localip(&ifra.ifra_addr.sin6_addr) != 0) { if (trylimit-- > 0) { forcegen = 1; ---- cut here ---- Thanks! Cheers, -- Fernando Gont e-mail: fernando@gont.com.ar || fgont@si6networks.com PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1