Date: Fri, 03 Apr 2020 09:31:55 +0000 From: "Bjoern A. Zeeb" <bzeeb-lists@lists.zabbadoz.net> To: "Fernando Gont" <fernando@gont.com.ar> Cc: "FreeBSD Net" <freebsd-net@freebsd.org>, "Hiroki Sato" <hrs@FreeBSD.org> Subject: Re: [PATCH] Implement the upcoming RFC4941bis (IPv6 SLAAC temporary addresses/privacy extensions) Message-ID: <2C7AA4FD-CA20-4B53-8305-E279ACC2C5F2@lists.zabbadoz.net> In-Reply-To: <93726ba6-6d96-2b45-81c5-6fd8a83f95a9@gont.com.ar> References: <93726ba6-6d96-2b45-81c5-6fd8a83f95a9@gont.com.ar>
next in thread | previous in thread | raw e-mail | index | archive | help
On 3 Apr 2020, at 1:55, Fernando Gont wrote: Hi Fernando, can you follow-up on https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=245103 with your more complete patch so this is properly tracked? I’ll be happy to deal with it the next days if no one else beats me to it. /bz > 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: > <https://www.gont.com.ar/code/fgont-patch-freebsd-rfc4941bis.txt> > > > ---- 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 <sys/sysctl.h> > #include <sys/syslog.h> > #include <sys/queue.h> > +#include <sys/random.h> > > #include <net/if.h> > #include <net/if_var.h> > @@ -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 > + * <draft-ietf-6man-rfc4941bis-08.txt>, 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 > > > > _______________________________________________ > freebsd-net@freebsd.org mailing list > https://lists.freebsd.org/mailman/listinfo/freebsd-net > To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?2C7AA4FD-CA20-4B53-8305-E279ACC2C5F2>