Re: [PATCH] IPv6: Privacy Extensions for Stateless Address Autoconfiguration in IPv6

From: Pekka Savola (pekkas@netcore.fi)
Date: Thu Oct 31 2002 - 02:25:01 EST


I belive privacy extensions can be harmful for especially long-lived
applications and lead to a false sense of security: they should not be
enabled (by any definition of enabled) by default.

http://www.ietf.org/internet-drafts/draft-dupont-ipv6-rfc3041harmful-01.txt

give some reasoning not to depend on them for privacy.

On Thu, 31 Oct 2002, YOSHIFUJI Hideaki / [iso-2022-jp] $B5HF#1QL@(B wrote:

> Hello!
>
> Nodes use IPv6 stateless address autoconfiguration to generate addresses.
> They are formed by combining network prefixes with an interface identifier.
> On interfaces such as ethernet, interface identifier is derived from
> static embedded IEEE Identifies. and eavesdroppers and other information
> collectors may identify the address is actually correspond to the same
> node.
> Privacy Extensions (RFC3041) is designed to make it difficult for
> eavesdroppers and other information collectors to identify actually
> correspond to the same node by changing the interface identifier
> periodically.
>
> This patch is against linux-2.5.44+bk2 snapshot.
>
> Thanks in advance.
>
> -------------------------------------------------------------------
> Patch-Name: Privacy Extensions for Stateless Address Autoconfiguration in IPv6
> Patch-Id: FIX_2_5_44+bk2_ADDRCONF_PRIVACY-20021031
> Patch-Author: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> -------------------------------------------------------------------
> Index: Documentation/networking/ip-sysctl.txt
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/Documentation/networking/ip-sysctl.txt,v
> retrieving revision 1.1.1.3
> retrieving revision 1.1.1.3.6.1
> diff -u -r1.1.1.3 -r1.1.1.3.6.1
> --- Documentation/networking/ip-sysctl.txt 30 Oct 2002 09:43:01 -0000 1.1.1.3
> +++ Documentation/networking/ip-sysctl.txt 30 Oct 2002 18:15:04 -0000 1.1.1.3.6.1
> @@ -611,6 +611,37 @@
> 0 to disable any limiting, otherwise the maximal rate in jiffies(1)
> Default: 100
>
> +use_tempaddr - INTEGER
> + Preference for Privacy Extensions (RFC3041).
> + <= 0 : disable Privacy Extensions
> + == 1 : enable Privacy Extensions, but prefer public
> + addresses over temporary addresses.
> + > 1 : enable Privacy Extensions and prefer temporary
> + addresses over public addresses.
> + Default: 1 (for most devices)
> + 0 (for point-to-point devices and loopback devices)
> +
> +temp_valid_lft - INTEGER
> + valid lifetime (in seconds) for temporary addresses.
> + Default: 604800 (7 days)
> +
> +temp_prefered_lft - INTEGER
> + Preferred lifetime (in seconds) for temorary addresses.
> + Default: 86400 (1 day)
> +
> +max_desync_factor - INTEGER
> + Maximum value for DESYNC_FACTOR, which is a random value
> + that ensures that clients don't synchronize with each
> + other and generage new addresses at exactly the same time.
> + value is in seconds.
> + Default: 600
> +
> +regen_max_retry - INTEGER
> + Number of attempts before give up attempting to generate
> + valid temporary addresses.
> + Default: 5
> +
> +
> IPv6 Update by:
> Pekka Savola <pekkas@netcore.fi>
> YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
> Index: include/linux/rtnetlink.h
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/include/linux/rtnetlink.h,v
> retrieving revision 1.1.1.2
> retrieving revision 1.1.1.2.6.1
> diff -u -r1.1.1.2 -r1.1.1.2.6.1
> --- include/linux/rtnetlink.h 30 Oct 2002 09:43:04 -0000 1.1.1.2
> +++ include/linux/rtnetlink.h 30 Oct 2002 18:15:04 -0000 1.1.1.2.6.1
> @@ -335,6 +335,7 @@
> /* ifa_flags */
>
> #define IFA_F_SECONDARY 0x01
> +#define IFA_F_TEMPORARY IFA_F_SECONDARY
>
> #define IFA_F_DEPRECATED 0x20
> #define IFA_F_TENTATIVE 0x40
> Index: include/linux/sysctl.h
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/include/linux/sysctl.h,v
> retrieving revision 1.1.1.3
> retrieving revision 1.1.1.3.6.1
> diff -u -r1.1.1.3 -r1.1.1.3.6.1
> --- include/linux/sysctl.h 30 Oct 2002 09:43:03 -0000 1.1.1.3
> +++ include/linux/sysctl.h 30 Oct 2002 18:15:04 -0000 1.1.1.3.6.1
> @@ -384,7 +384,12 @@
> NET_IPV6_DAD_TRANSMITS=7,
> NET_IPV6_RTR_SOLICITS=8,
> NET_IPV6_RTR_SOLICIT_INTERVAL=9,
> - NET_IPV6_RTR_SOLICIT_DELAY=10
> + NET_IPV6_RTR_SOLICIT_DELAY=10,
> + NET_IPV6_USE_TEMPADDR=11,
> + NET_IPV6_TEMP_VALID_LFT=12,
> + NET_IPV6_TEMP_PREFERED_LFT=13,
> + NET_IPV6_REGEN_MAX_RETRY=14,
> + NET_IPV6_MAX_DESYNC_FACTOR=15
> };
>
> /* /proc/sys/net/ipv6/icmp */
> Index: include/net/addrconf.h
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/addrconf.h,v
> retrieving revision 1.1.1.2
> retrieving revision 1.1.1.2.8.1
> diff -u -r1.1.1.2 -r1.1.1.2.8.1
> --- include/net/addrconf.h 19 Oct 2002 05:51:09 -0000 1.1.1.2
> +++ include/net/addrconf.h 30 Oct 2002 18:15:04 -0000 1.1.1.2.8.1
> @@ -6,6 +6,11 @@
> #define MAX_RTR_SOLICITATIONS 3
> #define RTR_SOLICITATION_INTERVAL (4*HZ)
>
> +#define TEMP_VALID_LIFETIME (7*86400)
> +#define TEMP_PREFERRED_LIFETIME (86400)
> +#define REGEN_MAX_RETRY (5)
> +#define MAX_DESYNC_FACTOR (600)
> +
> #define ADDR_CHECK_FREQUENCY (120*HZ)
>
> struct prefix_info {
> Index: include/net/if_inet6.h
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/if_inet6.h,v
> retrieving revision 1.1.1.1
> retrieving revision 1.1.1.1.16.1
> diff -u -r1.1.1.1 -r1.1.1.1.16.1
> --- include/net/if_inet6.h 7 Oct 2002 10:22:46 -0000 1.1.1.1
> +++ include/net/if_inet6.h 30 Oct 2002 18:15:04 -0000 1.1.1.1.16.1
> @@ -43,6 +43,12 @@
> struct inet6_ifaddr *lst_next; /* next addr in addr_lst */
> struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
>
> +#ifdef CONFIG_IPV6_PRIVACY
> + struct inet6_ifaddr *tmp_next; /* next addr in tempaddr_lst */
> + struct inet6_ifaddr *ifpub;
> + int regen_count;
> +#endif
> +
> int dead;
> };
>
> @@ -86,7 +92,13 @@
> int rtr_solicits;
> int rtr_solicit_interval;
> int rtr_solicit_delay;
> -
> +#ifdef CONFIG_IPV6_PRIVACY
> + int use_tempaddr;
> + int temp_valid_lft;
> + int temp_prefered_lft;
> + int regen_max_retry;
> + int max_desync_factor;
> +#endif
> void *sysctl;
> };
>
> @@ -100,6 +112,13 @@
> atomic_t refcnt;
> __u32 if_flags;
> int dead;
> +
> +#ifdef CONFIG_IPV6_PRIVACY
> + u8 rndid[8];
> + u8 entropy[8];
> + struct timer_list regen_timer;
> + struct inet6_ifaddr *tempaddr_list;
> +#endif
>
> struct neigh_parms *nd_parms;
> struct inet6_dev *next;
> Index: net/ipv6/Config.help
> ===================================================================
> RCS file: net/ipv6/Config.help
> diff -N net/ipv6/Config.help
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ net/ipv6/Config.help 30 Oct 2002 18:15:04 -0000 1.1.12.1
> @@ -0,0 +1,12 @@
> +IPv6: Privacy Extensions (RFC 3041) support
> +CONFIG_IPV6_PRIVACY
> + Privacy Extensions for Stateless Address Autoconfiguration in IPv6
> + support. With this option, additional periodically-alter
> + pseudo-random global-scope unicast address(es) will assigned to
> + your interface(s).
> +
> + By default, kernel generates temporary addresses but it won't use
> + them unless application explicitly bind them. To prefer temporary
> + address, do
> +
> + echo 2 >/proc/sys/net/ipv6/conf/all/use_tempaddr
> Index: net/ipv6/Config.in
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Config.in,v
> retrieving revision 1.1.1.2
> retrieving revision 1.1.1.2.10.1
> diff -u -r1.1.1.2 -r1.1.1.2.10.1
> --- net/ipv6/Config.in 16 Oct 2002 04:23:08 -0000 1.1.1.2
> +++ net/ipv6/Config.in 30 Oct 2002 18:15:04 -0000 1.1.1.2.10.1
> @@ -2,6 +2,8 @@
> # IPv6 configuration
> #
>
> +bool ' IPv6: Privacy Extentions (RFC 3041) support' CONFIG_IPV6_PRIVACY
> +
> if [ "$CONFIG_NETFILTER" != "n" ]; then
> source net/ipv6/netfilter/Config.in
> fi
> Index: net/ipv6/addrconf.c
> ===================================================================
> RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/addrconf.c,v
> retrieving revision 1.1.1.4
> retrieving revision 1.1.1.4.6.1
> diff -u -r1.1.1.4 -r1.1.1.4.6.1
> --- net/ipv6/addrconf.c 30 Oct 2002 09:43:18 -0000 1.1.1.4
> +++ net/ipv6/addrconf.c 30 Oct 2002 18:15:04 -0000 1.1.1.4.6.1
> @@ -62,6 +62,12 @@
> #include <linux/if_tunnel.h>
> #include <linux/rtnetlink.h>
>
> +#ifdef CONFIG_IPV6_PRIVACY
> +#include <linux/random.h>
> +#include <linux/crypto.h>
> +#include <asm/scatterlist.h>
> +#endif
> +
> #include <asm/uaccess.h>
>
> #define IPV6_MAX_ADDRESSES 16
> @@ -83,6 +89,16 @@
> int inet6_dev_count;
> int inet6_ifa_count;
>
> +#ifdef CONFIG_IPV6_PRIVACY
> +static int __ipv6_regen_rndid(struct inet6_dev *idev);
> +static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
> +static void ipv6_regen_rndid(unsigned long data);
> +
> +static int desync_factor = MAX_DESYNC_FACTOR * HZ;
> +#endif
> +
> +int ipv6_count_addresses(struct inet6_dev *idev);
> +
> /*
> * Configured unicast address hash table
> */
> @@ -119,6 +135,13 @@
> MAX_RTR_SOLICITATIONS, /* router solicits */
> RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
> MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */
> +#ifdef CONFIG_IPV6_PRIVACY
> + .use_tempaddr = 1,
> + .temp_valid_lft = TEMP_VALID_LIFETIME,
> + .temp_prefered_lft = TEMP_PREFERRED_LIFETIME,
> + .regen_max_retry = REGEN_MAX_RETRY,
> + .max_desync_factor = MAX_DESYNC_FACTOR,
> +#endif
> };
>
> static struct ipv6_devconf ipv6_devconf_dflt =
> @@ -133,6 +156,13 @@
> MAX_RTR_SOLICITATIONS, /* router solicits */
> RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
> MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */
> +#ifdef CONFIG_IPV6_PRIVACY
> + .use_tempaddr = 1,
> + .temp_valid_lft = TEMP_VALID_LIFETIME,
> + .temp_prefered_lft = TEMP_PREFERRED_LIFETIME,
> + .regen_max_retry = REGEN_MAX_RETRY,
> + .max_desync_factor = MAX_DESYNC_FACTOR,
> +#endif
> };
>
> int ipv6_addr_type(struct in6_addr *addr)
> @@ -272,6 +302,24 @@
> /* We refer to the device */
> dev_hold(dev);
>
> +#ifdef CONFIG_IPV6_PRIVACY
> + get_random_bytes(ndev->rndid, sizeof(ndev->rndid));
> + get_random_bytes(ndev->entropy, sizeof(ndev->entropy));
> + init_timer(&ndev->regen_timer);
> + ndev->regen_timer.function = ipv6_regen_rndid;
> + ndev->regen_timer.data = (unsigned long) ndev;
> + if ((dev->flags&IFF_LOOPBACK) ||
> + dev->type == ARPHRD_TUNNEL ||
> + dev->type == ARPHRD_SIT) {
> + printk(KERN_INFO
> + "Disabled Privacy Extensions on device %p(%s)\n",
> + dev, dev->name);
> + ndev->cnf.use_tempaddr = -1;
> + } else {
> + __ipv6_regen_rndid(ndev);
> + }
> +#endif
> +
> write_lock_bh(&addrconf_lock);
> dev->ip6_ptr = ndev;
> /* One reference from device */
> @@ -396,6 +444,18 @@
> /* Add to inet6_dev unicast addr list. */
> ifa->if_next = idev->addr_list;
> idev->addr_list = ifa;
> +
> +#ifdef CONFIG_IPV6_PRIVACY
> + ifa->regen_count = 0;
> + if (ifa->flags&IFA_F_TEMPORARY) {
> + ifa->tmp_next = idev->tempaddr_list;
> + idev->tempaddr_list = ifa;
> + in6_ifa_hold(ifa);
> + } else {
> + ifa->tmp_next = NULL;
> + }
> +#endif
> +
> in6_ifa_hold(ifa);
> write_unlock_bh(&idev->lock);
> read_unlock(&addrconf_lock);
> @@ -417,6 +477,15 @@
>
> ifp->dead = 1;
>
> +#ifdef CONFIG_IPV6_PRIVACY
> + spin_lock_bh(&ifp->lock);
> + if (ifp->ifpub) {
> + __in6_ifa_put(ifp->ifpub);
> + ifp->ifpub = NULL;
> + }
> + spin_unlock_bh(&ifp->lock);
> +#endif
> +
> write_lock_bh(&addrconf_hash_lock);
> for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL;
> ifap = &ifa->lst_next) {
> @@ -430,6 +499,24 @@
> write_unlock_bh(&addrconf_hash_lock);
>
> write_lock_bh(&idev->lock);
> +#ifdef CONFIG_IPV6_PRIVACY
> + if (ifp->flags&IFA_F_TEMPORARY) {
> + for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL;
> + ifap = &ifa->tmp_next) {
> + if (ifa == ifp) {
> + *ifap = ifa->tmp_next;
> + if (ifp->ifpub) {
> + __in6_ifa_put(ifp->ifpub);
> + ifp->ifpub = NULL;
> + }
> + __in6_ifa_put(ifp);
> + ifa->tmp_next = NULL;
> + break;
> + }
> + }
> + }
> +#endif
> +
> for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;
> ifap = &ifa->if_next) {
> if (ifa == ifp) {
> @@ -450,6 +537,96 @@
> in6_ifa_put(ifp);
> }
>
> +#ifdef CONFIG_IPV6_PRIVACY
> +static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift)
> +{
> + struct inet6_dev *idev;
> + struct in6_addr addr, *tmpaddr;
> + unsigned long tmp_prefered_lft, tmp_valid_lft;
> + int tmp_plen;
> + int ret = 0;
> +
> + 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:
> + spin_lock_bh(&ifp->lock);
> + in6_ifa_hold(ifp);
> + idev = ifp->idev;
> + in6_dev_hold(idev);
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + write_lock(&idev->lock);
> + if (idev->cnf.use_tempaddr <= 0) {
> + write_unlock(&idev->lock);
> + spin_unlock_bh(&ifp->lock);
> + printk(KERN_INFO
> + "ipv6_create_tempaddr(): use_tempaddr is disabled.\n");
> + in6_dev_put(idev);
> + in6_ifa_put(ifp);
> + ret = -1;
> + goto out;
> + }
> + if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
> + idev->cnf.use_tempaddr = -1; /*XXX*/
> + write_unlock(&idev->lock);
> + spin_unlock_bh(&ifp->lock);
> + printk(KERN_WARNING
> + "ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n");
> + in6_dev_put(idev);
> + in6_ifa_put(ifp);
> + ret = -1;
> + goto out;
> + }
> + if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) {
> + write_unlock(&idev->lock);
> + spin_unlock_bh(&ifp->lock);
> + printk(KERN_WARNING
> + "ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n");
> + in6_dev_put(idev);
> + in6_ifa_put(ifp);
> + ret = -1;
> + goto out;
> + }
> + memcpy(&addr.s6_addr[8], idev->rndid, 8);
> + tmp_valid_lft = min_t(__u32,
> + ifp->valid_lft,
> + idev->cnf.temp_valid_lft);
> + tmp_prefered_lft = min_t(__u32,
> + ifp->prefered_lft,
> + idev->cnf.temp_prefered_lft - desync_factor / HZ);
> + tmp_plen = ifp->prefix_len;
> + write_unlock(&idev->lock);
> + spin_unlock_bh(&ifp->lock);
> + ift = ipv6_count_addresses(idev) < IPV6_MAX_ADDRESSES ?
> + ipv6_add_addr(idev, &addr, tmp_plen,
> + ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : 0;
> + if (!ift) {
> + in6_dev_put(idev);
> + in6_ifa_put(ifp);
> + printk(KERN_INFO
> + "ipv6_create_tempaddr(): retry temporary address regeneration.\n");
> + tmpaddr = &addr;
> + goto retry;
> + }
> + spin_lock_bh(&ift->lock);
> + ift->ifpub = ifp;
> + ift->valid_lft = tmp_valid_lft;
> + ift->prefered_lft = tmp_prefered_lft;
> + ift->tstamp = ifp->tstamp;
> + spin_unlock_bh(&ift->lock);
> + addrconf_dad_start(ift);
> + in6_ifa_put(ift);
> + in6_dev_put(idev);
> +out:
> + return ret;
> +}
> +#endif
> +
> /*
> * Choose an apropriate source address
> * should do:
> @@ -458,6 +635,22 @@
> * an address of the attached interface
> * iii) don't use deprecated addresses
> */
> +static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref)
> +{
> + int pref;
> + pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;
> +#ifdef CONFIG_IPV6_PRIVACY
> + pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;
> +#endif
> + return pref;
> +}
> +
> +#ifdef CONFIG_IPV6_PRIVACY
> +#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3)
> +#else
> +#define IPV6_GET_SADDR_MAXSCORE(score) (score)
> +#endif
> +
> int ipv6_get_saddr(struct dst_entry *dst,
> struct in6_addr *daddr, struct in6_addr *saddr)
> {
> @@ -468,6 +661,7 @@
> struct inet6_dev *idev;
> struct rt6_info *rt;
> int err;
> + int hiscore = -1, score;
>
> rt = (struct rt6_info *) dst;
> if (rt)
> @@ -497,17 +691,27 @@
> read_lock_bh(&idev->lock);
> for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
> if (ifp->scope == scope) {
> - if (!(ifp->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {
> - in6_ifa_hold(ifp);
> + if (ifp->flags&IFA_F_TENTATIVE)
> + continue;
> +#ifdef CONFIG_IPV6_PRIVACY
> + score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
> +#else
> + score = ipv6_saddr_pref(ifp, 0);
> +#endif
> + if (score <= hiscore)
> + continue;
> +
> + if (match)
> + in6_ifa_put(match);
> + match = ifp;
> + hiscore = score;
> + in6_ifa_hold(ifp);
> +
> + if (IPV6_GET_SADDR_MAXSCORE(score)) {
> read_unlock_bh(&idev->lock);
> read_unlock(&addrconf_lock);
> goto out;
> }
> -
> - if (!match && !(ifp->flags & IFA_F_TENTATIVE)) {
> - match = ifp;
> - in6_ifa_hold(ifp);
> - }
> }
> }
> read_unlock_bh(&idev->lock);
> @@ -530,16 +734,26 @@
> read_lock_bh(&idev->lock);
> for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
> if (ifp->scope == scope) {
> - if (!(ifp->flags&(IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {
> - in6_ifa_hold(ifp);
> + if (ifp->flags&IFA_F_TENTATIVE)
> + continue;
> +#ifdef CONFIG_IPV6_PRIVACY
> + score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
> +#else
> + score = ipv6_saddr_pref(ifp, 0);
> +#endif
> + if (score <= hiscore)
> + continue;
> +
> + if (match)
> + in6_ifa_put(match);
> + match = ifp;
> + hiscore = score;
> + in6_ifa_hold(ifp);
> +
> + if (IPV6_GET_SADDR_MAXSCORE(score)) {
> read_unlock_bh(&idev->lock);
> goto out_unlock_base;
> }
> -
> - if (!match && !(ifp->flags&IFA_F_TENTATIVE)) {
> - match = ifp;
> - in6_ifa_hold(ifp);
> - }
> }
> }
> read_unlock_bh(&idev->lock);
> @@ -551,19 +765,12 @@
> read_unlock(&dev_base_lock);
>
> out:
> - if (ifp == NULL) {
> - ifp = match;
> - match = NULL;
> - }
> -
> err = -EADDRNOTAVAIL;
> - if (ifp) {
> - ipv6_addr_copy(saddr, &ifp->addr);
> + if (match) {
> + ipv6_addr_copy(saddr, &match->addr);
> err = 0;
> - in6_ifa_put(ifp);
> - }
> - if (match)
> in6_ifa_put(match);
> + }
>
> return err;
> }
> @@ -653,6 +860,21 @@
> ifp->flags |= IFA_F_TENTATIVE;
> spin_unlock_bh(&ifp->lock);
> in6_ifa_put(ifp);
> +#ifdef CONFIG_IPV6_PRIVACY
> + } else if (ifp->flags&IFA_F_TEMPORARY) {
> + struct inet6_ifaddr *ifpub;
> + spin_lock_bh(&ifp->lock);
> + ifpub = ifp->ifpub;
> + if (ifpub) {
> + in6_ifa_hold(ifpub);
> + spin_unlock_bh(&ifp->lock);
> + ipv6_create_tempaddr(ifpub, ifp);
> + in6_ifa_put(ifpub);
> + } else {
> + spin_unlock_bh(&ifp->lock);
> + }
> + ipv6_del_addr(ifp);
> +#endif
> } else
> ipv6_del_addr(ifp);
> }
> @@ -718,6 +940,108 @@
> return err;
> }
>
> +#ifdef CONFIG_IPV6_PRIVACY
> +/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
> +static int __ipv6_regen_rndid(struct inet6_dev *idev)
> +{
> + struct net_device *dev;
> + u8 eui64[8];
> + u8 digest[16];
> + struct crypto_tfm *tfm;
> + struct scatterlist sg[2];
> +
> + sg[0].page = virt_to_page(idev->entropy);
> + sg[0].offset = ((long) idev->entropy & ~PAGE_MASK);
> + sg[0].length = 8;
> + sg[1].page = virt_to_page(eui64);
> + sg[1].offset = ((long) eui64 & ~PAGE_MASK);
> + sg[1].length = 8;
> +
> + if (!del_timer(&idev->regen_timer))
> + in6_dev_hold(idev);
> +
> + dev = idev->dev;
> +
> + if (ipv6_generate_eui64(eui64, dev)) {
> + printk(KERN_INFO
> + "__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",
> + idev);
> + get_random_bytes(eui64, sizeof(eui64));
> + }
> +regen:
> + tfm = crypto_alloc_tfm("md5", 0);
> + if (tfm == NULL) {
> + if (net_ratelimit())
> + printk(KERN_WARNING
> + "failed to load transform for md5\n");
> + in6_dev_put(idev);
> + return -1;
> + }
> + crypto_digest_init(tfm);
> + crypto_digest_update(tfm, sg, 2);
> + crypto_digest_final(tfm, digest);
> + crypto_free_tfm(tfm);
> +
> + memcpy(idev->rndid, &digest[0], 8);
> + idev->rndid[0] &= ~0x02;
> + memcpy(idev->entropy, &digest[8], 8);
> +
> + /*
> + * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
> + * check if generated address is not inappropriate
> + *
> + * - Reserved subnet anycast (RFC 2526)
> + * 11111101 11....11 1xxxxxxx
> + * - ISATAP (draft-ietf-ngtrans-isatap-01.txt) 4.3
> + * 00-00-5E-FE-xx-xx-xx-xx
> + * - value 0
> + * - 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]) &&
> + (idev->rndid[7]&0x80))
> + goto regen;
> + if ((idev->rndid[0]|idev->rndid[1]) == 0) {
> + if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe)
> + goto regen;
> + if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00)
> + goto regen;
> + }
> +
> + if (time_before(idev->regen_timer.expires, jiffies)) {
> + idev->regen_timer.expires = 0;
> + printk(KERN_WARNING
> + "__ipv6_regen_rndid(): too short regeneration interval; timer diabled for %s.\n",
> + idev->dev->name);
> + in6_dev_put(idev);
> + return -1;
> + }
> +
> + add_timer(&idev->regen_timer);
> + return 0;
> +}
> +
> +static void ipv6_regen_rndid(unsigned long data)
> +{
> + struct inet6_dev *idev = (struct inet6_dev *) data;
> +
> + read_lock_bh(&addrconf_lock);
> + write_lock_bh(&idev->lock);
> + if (!idev->dead)
> + __ipv6_regen_rndid(idev);
> + write_unlock_bh(&idev->lock);
> + read_unlock_bh(&addrconf_lock);
> +}
> +
> +static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {
> + int ret = 0;
> +
> + if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0)
> + ret = __ipv6_regen_rndid(idev);
> + return ret;
> +}
> +#endif
> +
> /*
> * Add prefix route.
> */
> @@ -889,6 +1213,7 @@
> struct inet6_ifaddr * ifp;
> struct in6_addr addr;
> int plen;
> + int create = 0;
>
> plen = pinfo->prefix_len >> 3;
>
> @@ -924,6 +1249,7 @@
> return;
> }
>
> + create = 1;
> addrconf_dad_start(ifp);
> }
>
> @@ -934,6 +1260,9 @@
>
> if (ifp) {
> int flags;
> +#ifdef CONFIG_IPV6_PRIVACY
> + struct inet6_ifaddr *ift;
> +#endif
>
> spin_lock(&ifp->lock);
> ifp->valid_lft = valid_lft;
> @@ -946,6 +1275,42 @@
> if (!(flags&IFA_F_TENTATIVE))
> ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ?
> 0 : RTM_NEWADDR, ifp);
> +
> +#ifdef CONFIG_IPV6_PRIVACY
> + read_lock_bh(&in6_dev->lock);
> + /* update all temporary addresses in the list */
> + for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) {
> + /*
> + * When adjusting the lifetimes of an existing
> + * temporary address, only lower the lifetimes.
> + * Implementations must not increase the
> + * lifetimes of an existing temporary address
> + * when processing a Prefix Information Option.
> + */
> + spin_lock(&ift->lock);
> + flags = ift->flags;
> + if (ift->valid_lft > valid_lft &&
> + ift->valid_lft - valid_lft > (jiffies - ift->tstamp) / HZ)
> + ift->valid_lft = valid_lft + (jiffies - ift->tstamp) / HZ;
> + if (ift->prefered_lft > prefered_lft &&
> + ift->prefered_lft - prefered_lft > (jiffies - ift->tstamp) / HZ)
> + ift->prefered_lft = prefered_lft + (jiffies - ift->tstamp) / HZ;
> + spin_unlock(&ift->lock);
> + if (!(flags&IFA_F_TENTATIVE))
> + ipv6_ifa_notify(0, ift);
> + }
> +
> + if (create && in6_dev->cnf.use_tempaddr > 0) {
> + /*
> + * When a new public address is created as described in [ADDRCONF],
> + * also create a new temporary address.
> + */
> + read_unlock_bh(&in6_dev->lock);
> + ipv6_create_tempaddr(ifp, NULL);
> + } else {
> + read_unlock_bh(&in6_dev->lock);
> + }
> +#endif
> in6_ifa_put(ifp);
> addrconf_verify(0);
> }
> @@ -1910,7 +2275,7 @@
> static struct addrconf_sysctl_table
> {
> struct ctl_table_header *sysctl_header;
> - ctl_table addrconf_vars[11];
> + ctl_table addrconf_vars[16];
> ctl_table addrconf_dev[2];
> ctl_table addrconf_conf_dir[2];
> ctl_table addrconf_proto_dir[2];
> @@ -1957,6 +2322,28 @@
> &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
> &proc_dointvec_jiffies},
>
> +#ifdef CONFIG_IPV6_PRIVACY
> + {NET_IPV6_USE_TEMPADDR, "use_tempaddr",
> + &ipv6_devconf.use_tempaddr, sizeof(int), 0644, NULL,
> + &proc_dointvec},
> +
> + {NET_IPV6_TEMP_VALID_LFT, "temp_valid_lft",
> + &ipv6_devconf.temp_valid_lft, sizeof(int), 0644, NULL,
> + &proc_dointvec},
> +
> + {NET_IPV6_TEMP_PREFERED_LFT, "temp_prefered_lft",
> + &ipv6_devconf.temp_prefered_lft, sizeof(int), 0644, NULL,
> + &proc_dointvec},
> +
> + {NET_IPV6_REGEN_MAX_RETRY, "regen_max_retry",
> + &ipv6_devconf.regen_max_retry, sizeof(int), 0644, NULL,
> + &proc_dointvec},
> +
> + {NET_IPV6_MAX_DESYNC_FACTOR, "max_desync_factor",
> + &ipv6_devconf.max_desync_factor, sizeof(int), 0644, NULL,
> + &proc_dointvec},
> +#endif
> +
> {0}},
>
> {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, addrconf_sysctl.addrconf_vars},{0}},
> @@ -1975,7 +2362,7 @@
> if (t == NULL)
> return;
> memcpy(t, &addrconf_sysctl, sizeof(*t));
> - for (i=0; i<sizeof(t->addrconf_vars)/sizeof(t->addrconf_vars[0])-1; i++) {
> + for (i=0; t->addrconf_vars[i].data; i++) {
> t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
> t->addrconf_vars[i].de = NULL;
> }
>
>

-- 
Pekka Savola                 "Tell me of difficulties surmounted,
Netcore Oy                   not those you stumble over and fall"
Systems. Networks. Security.  -- Robert Jordan: A Crown of Swords

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Oct 31 2002 - 22:00:52 EST