Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 6 Apr 2020 13:09:19 -0300
From:      Fernando Gont <fernando@gont.com.ar>
To:        FreeBSD Net <freebsd-net@freebsd.org>
Subject:   Re: [PATCH] Implement the upcoming RFC4941bis (IPv6 SLAAC temporary addresses/privacy extensions)
Message-ID:  <ded7af9d-96e5-c9e6-6f4d-b4c92a31eb61@gont.com.ar>
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
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@gont.com.ar || fgont@si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1






Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?ded7af9d-96e5-c9e6-6f4d-b4c92a31eb61>