Skip site navigation (1)Skip section navigation (2)
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>