Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Thu, 31 Oct 2002 02:19:04 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Thu, 31 Oct 2002 02:19:04 -0500 Received: from netcore.fi ([193.94.160.1]:8206 "EHLO netcore.fi") by vger.kernel.org with ESMTP id ; Thu, 31 Oct 2002 02:18:47 -0500 Date: Thu, 31 Oct 2002 09:25:01 +0200 (EET) From: Pekka Savola To: YOSHIFUJI Hideaki / =?iso-2022-jp?B?GyRCNUhGIzFRTEAbKEI=?= cc: linux-kernel@vger.kernel.org, , , , Subject: Re: [PATCH] IPv6: Privacy Extensions for Stateless Address Autoconfiguration in IPv6 In-Reply-To: <20021031.124459.66300488.yoshfuji@linux-ipv6.org> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=ISO-8859-1 Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 26366 Lines: 854 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] 吉藤英明 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 > Credit: YOSHIFUJI Hideaki / USAGI Project > ------------------------------------------------------------------- > 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 > YOSHIFUJI Hideaki / USAGI Project > 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 > #include > > +#ifdef CONFIG_IPV6_PRIVACY > +#include > +#include > +#include > +#endif > + > #include > > #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); > + > + /* > + * : > + * 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; iaddrconf_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/