[PATCH] Implement the upcoming RFC4941bis (IPv6 SLAAC temporary addresses/privacy extensions)
Fernando Gont
fernando at gont.com.ar
Mon Apr 6 16:38:17 UTC 2020
Folks,
Any thoughts?
On 2/4/20 22:55, Fernando Gont wrote:
> 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 at gont.com.ar || fgont at si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
More information about the freebsd-net
mailing list