Commit 969c5464 authored by Fernando Gont's avatar Fernando Gont Committed by David S. Miller
Browse files

ipv6: Implement draft-ietf-6man-rfc4941bis

Implement the upcoming rev of RFC4941 (IPv6 temporary addresses):
https://tools.ietf.org/html/draft-ietf-6man-rfc4941bis-09



* Reduces the default Valid Lifetime to 2 days
  The number of extra addresses employed when Valid Lifetime was
  7 days exacerbated the stress caused on network
  elements/devices. Additionally, the motivation for temporary
  addresses is indeed privacy and reduced exposure. With a
  default Valid Lifetime of 7 days, an address that becomes
  revealed by active communication is reachable and exposed for
  one whole week. The only use case for a Valid Lifetime of 7
  days could be some application that is expecting to have long
  lived connections. But if you want to have a long lived
  connections, you shouldn't be using a temporary address in the
  first place. Additionally, in the era of mobile devices, general
  applications should nevertheless be prepared and robust to
  address changes (e.g. nodes swap wifi <-> 4G, etc.)

* Employs different IIDs for different prefixes
  To avoid network activity correlation among addresses configured
  for different prefixes

* Uses a simpler algorithm for IID generation
  No need to store "history" anywhere

Signed-off-by: default avatarFernando Gont <fgont@si6networks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a7defa75
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2065,7 +2065,7 @@ use_tempaddr - INTEGER
temp_valid_lft - INTEGER
	valid lifetime (in seconds) for temporary addresses.

	Default: 604800 (7 days)
	Default: 172800 (2 days)

temp_prefered_lft - INTEGER
	Preferred lifetime (in seconds) for temporary addresses.
+0 −1
Original line number Diff line number Diff line
@@ -190,7 +190,6 @@ struct inet6_dev {
	int			dead;

	u32			desync_factor;
	u8			rndid[8];
	struct list_head	tempaddr_list;

	struct in6_addr		token;
+39 −52
Original line number Diff line number Diff line
@@ -135,8 +135,7 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
}
#endif

static void ipv6_regen_rndid(struct inet6_dev *idev);
static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
static void ipv6_gen_rnd_iid(struct in6_addr *addr);

static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
static int ipv6_count_addresses(const struct inet6_dev *idev);
@@ -432,8 +431,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
	    dev->type == ARPHRD_SIT ||
	    dev->type == ARPHRD_NONE) {
		ndev->cnf.use_tempaddr = -1;
	} else
		ipv6_regen_rndid(ndev);
	}

	ndev->token = in6addr_any;

@@ -1306,29 +1304,21 @@ out:
	in6_ifa_put(ifp);
}

static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp,
				struct inet6_ifaddr *ift,
				bool block)
static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
{
	struct inet6_dev *idev = ifp->idev;
	struct in6_addr addr, *tmpaddr;
	unsigned long tmp_tstamp, age;
	unsigned long regen_advance;
	struct ifa6_config cfg;
	int ret = 0;
	unsigned long now = jiffies;
	long max_desync_factor;
	s32 cnf_temp_preferred_lft;
	struct inet6_ifaddr *ift;
	struct ifa6_config cfg;
	long max_desync_factor;
	struct in6_addr addr;
	int ret = 0;

	write_lock_bh(&idev->lock);
	if (ift) {
		spin_lock_bh(&ift->lock);
		memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);
		spin_unlock_bh(&ift->lock);
		tmpaddr = &addr;
	} else {
		tmpaddr = NULL;
	}

retry:
	in6_dev_hold(idev);
	if (idev->cnf.use_tempaddr <= 0) {
@@ -1351,8 +1341,8 @@ retry:
	}
	in6_ifa_hold(ifp);
	memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
	ipv6_try_regen_rndid(idev, tmpaddr);
	memcpy(&addr.s6_addr[8], idev->rndid, 8);
	ipv6_gen_rnd_iid(&addr);

	age = (now - ifp->tstamp) / HZ;

	regen_advance = idev->cnf.regen_max_retry *
@@ -1417,7 +1407,6 @@ retry:
		in6_ifa_put(ifp);
		in6_dev_put(idev);
		pr_info("%s: retry temporary address regeneration\n", __func__);
		tmpaddr = &addr;
		write_lock_bh(&idev->lock);
		goto retry;
	}
@@ -2032,7 +2021,7 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
		if (ifpub) {
			in6_ifa_hold(ifpub);
			spin_unlock_bh(&ifp->lock);
			ipv6_create_tempaddr(ifpub, ifp, true);
			ipv6_create_tempaddr(ifpub, true);
			in6_ifa_put(ifpub);
		} else {
			spin_unlock_bh(&ifp->lock);
@@ -2329,40 +2318,38 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
	return err;
}

/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
static void ipv6_regen_rndid(struct inet6_dev *idev)
/* Generation of a randomized Interface Identifier
 * draft-ietf-6man-rfc4941bis, Section 3.3.1
 */

static void ipv6_gen_rnd_iid(struct in6_addr *addr)
{
regen:
	get_random_bytes(idev->rndid, sizeof(idev->rndid));
	idev->rndid[0] &= ~0x02;
	get_random_bytes(&addr->s6_addr[8], 8);

	/*
	 * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
	 * check if generated address is not inappropriate
	/* <draft-ietf-6man-rfc4941bis-08.txt>, Section 3.3.1:
	 * check if generated address is not inappropriate:
	 *
	 *  - Reserved subnet anycast (RFC 2526)
	 *	11111101 11....11 1xxxxxxx
	 *  - ISATAP (RFC4214) 6.1
	 *	00-00-5E-FE-xx-xx-xx-xx
	 *  - value 0
	 * - Reserved IPv6 Interface Identifers
	 * - XXX: already assigned to an address on the device
	 */
	if (idev->rndid[0] == 0xfd &&
	    (idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff &&
	    (idev->rndid[7]&0x80))
		goto regen;
	if ((idev->rndid[0]|idev->rndid[1]) == 0) {
		if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe)

	/* Subnet-router anycast: 0000:0000:0000:0000 */
	if (!(addr->s6_addr32[2] | addr->s6_addr32[3]))
		goto regen;
		if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00)

	/* 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;
	}
}

static void  ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr)
{
	if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0)
		ipv6_regen_rndid(idev);
	/* Reserved subnet anycast addresses */
	if (ntohl(addr->s6_addr32[2]) == 0xfdffffff &&
	    ntohl(addr->s6_addr32[3]) >= 0Xffffff80)
		goto regen;
}

/*
@@ -2544,7 +2531,7 @@ static void manage_tempaddrs(struct inet6_dev *idev,
		 * no temporary address currently exists.
		 */
		read_unlock_bh(&idev->lock);
		ipv6_create_tempaddr(ifp, NULL, false);
		ipv6_create_tempaddr(ifp, false);
	} else {
		read_unlock_bh(&idev->lock);
	}
@@ -4531,7 +4518,7 @@ restart:
						ifpub->regen_count = 0;
						spin_unlock(&ifpub->lock);
						rcu_read_unlock_bh();
						ipv6_create_tempaddr(ifpub, ifp, true);
						ipv6_create_tempaddr(ifpub, true);
						in6_ifa_put(ifpub);
						in6_ifa_put(ifp);
						rcu_read_lock_bh();