2002-10-31 03:39:02

by YOSHIFUJI Hideaki

[permalink] [raw]
Subject: [PATCH] IPv6: Privacy Extensions for Stateless Address Autoconfiguration in IPv6

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 <[email protected]>
Credit: YOSHIFUJI Hideaki / USAGI Project <[email protected]>
-------------------------------------------------------------------
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 <[email protected]>
YOSHIFUJI Hideaki / USAGI Project <[email protected]>
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;
}


2002-10-31 03:48:53

by YOSHIFUJI Hideaki

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

In article <[email protected]> (at Thu, 31 Oct 2002 12:44:59 +0900 (JST)), YOSHIFUJI Hideaki / 吉藤英明 <[email protected]> says:

> Credit: YOSHIFUJI Hideaki / USAGI Project <[email protected]>

Oops, I've forgot to credit myself in the source.
Please apply on top of the patch.

Index: net/ipv6/addrconf.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/addrconf.c,v
retrieving revision 1.1.1.4.6.1
retrieving revision 1.1.1.4.6.2
diff -u -r1.1.1.4.6.1 -r1.1.1.4.6.2
--- net/ipv6/addrconf.c 30 Oct 2002 18:15:04 -0000 1.1.1.4.6.1
+++ net/ipv6/addrconf.c 31 Oct 2002 03:50:36 -0000 1.1.1.4.6.2
@@ -28,6 +28,8 @@
* packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer.
+ * YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
+ * support.
*/

#include <linux/config.h>

--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2002-10-31 07:19:04

by Pekka Savola

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

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 <[email protected]>
> Credit: YOSHIFUJI Hideaki / USAGI Project <[email protected]>
> -------------------------------------------------------------------
> 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 <[email protected]>
> YOSHIFUJI Hideaki / USAGI Project <[email protected]>
> 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

2002-10-31 07:26:06

by YOSHIFUJI Hideaki

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

In article <[email protected]> (at Thu, 31 Oct 2002 09:25:01 +0200 (EET)), Pekka Savola <[email protected]> says:

> 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.

Temporary addresses are generated (on most links) but not used by default
(latter is done by source address selection) by my patch.
Set sysctl net.ipv6.conf.ethXX.use_tempaddr > 1 to use it by default.

(I have per-application setsockopt interface but it is not included
because patch for source address selection is not accepted at this moment.)

--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2002-10-31 07:37:27

by Pekka Savola

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

On Thu, 31 Oct 2002, YOSHIFUJI Hideaki / [iso-2022-jp] 吉藤英明 wrote:
> In article <[email protected]> (at Thu, 31 Oct 2002 09:25:01 +0200 (EET)), Pekka Savola <[email protected]> says:
>
> > 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.
>
> Temporary addresses are generated (on most links) but not used by default
> (latter is done by source address selection) by my patch.
> Set sysctl net.ipv6.conf.ethXX.use_tempaddr > 1 to use it by default.
>
> (I have per-application setsockopt interface but it is not included
> because patch for source address selection is not accepted at this moment.)

Generating and re-generating new temporary addresses seems to be a useless
work and just new addresses unless they're being used at least by some
applications.

--
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

2002-10-31 07:43:24

by YOSHIFUJI Hideaki

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

In article <[email protected]> (at Thu, 31 Oct 2002 09:43:40 +0200 (EET)), Pekka Savola <[email protected]> says:

> Generating and re-generating new temporary addresses seems to be a useless
> work and just new addresses unless they're being used at least by some
> applications.

set default to 0 (don't use it) for now is ok?

--yoshfuji

2002-10-31 08:17:55

by Pekka Savola

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

On Thu, 31 Oct 2002, YOSHIFUJI Hideaki / [iso-2022-jp] 吉藤英明 wrote:
> In article <[email protected]> (at Thu, 31 Oct 2002 09:43:40 +0200 (EET)), Pekka Savola <[email protected]> says:
>
> > Generating and re-generating new temporary addresses seems to be a useless
> > work and just new addresses unless they're being used at least by some
> > applications.
>
> set default to 0 (don't use it) for now is ok?

Sure, ok for me. (I'm assuming we'll be able to change the default at
some point when more knowledge and experience is gained but we're talking
about at least a year or two here, I think).

(This is why I never perceived privacy addresses as a critical work item
at the moment -- e.g. multicast routing might be more interesting.)

I don't know how Dave and Alexey feel, of course.

--
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

2002-11-01 08:43:19

by YOSHIFUJI Hideaki

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

In article <[email protected]> (at Thu, 31 Oct 2002 10:24:11 +0200 (EET)), Pekka Savola <[email protected]> says:

> > set default to 0 (don't use it) for now is ok?
>
> Sure, ok for me. (I'm assuming we'll be able to change the default at
> some point when more knowledge and experience is gained but we're talking
> about at least a year or two here, I think).

Ok, here's revised one.

- sync with linux-2.5.45.
- change default value for use_tempaddr sysctl to 0
(don't generate and use temprary addresses by default)

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.8.2
diff -u -r1.1.1.3 -r1.1.1.3.8.2
--- Documentation/networking/ip-sysctl.txt 30 Oct 2002 09:43:01 -0000 1.1.1.3
+++ Documentation/networking/ip-sysctl.txt 1 Nov 2002 08:29:09 -0000 1.1.1.3.8.2
@@ -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: 0 (for most devices)
+ -1 (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 <[email protected]>
YOSHIFUJI Hideaki / USAGI Project <[email protected]>
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.8.1
diff -u -r1.1.1.2 -r1.1.1.2.8.1
--- include/linux/rtnetlink.h 30 Oct 2002 09:43:04 -0000 1.1.1.2
+++ include/linux/rtnetlink.h 1 Nov 2002 08:15:13 -0000 1.1.1.2.8.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.8.1
diff -u -r1.1.1.3 -r1.1.1.3.8.1
--- include/linux/sysctl.h 30 Oct 2002 09:43:03 -0000 1.1.1.3
+++ include/linux/sysctl.h 1 Nov 2002 08:15:13 -0000 1.1.1.3.8.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.10.1
diff -u -r1.1.1.2 -r1.1.1.2.10.1
--- include/net/addrconf.h 19 Oct 2002 05:51:09 -0000 1.1.1.2
+++ include/net/addrconf.h 1 Nov 2002 08:15:13 -0000 1.1.1.2.10.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.18.1
diff -u -r1.1.1.1 -r1.1.1.1.18.1
--- include/net/if_inet6.h 7 Oct 2002 10:22:46 -0000 1.1.1.1
+++ include/net/if_inet6.h 1 Nov 2002 08:15:13 -0000 1.1.1.1.18.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/Kconfig
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Kconfig,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.3
diff -u -r1.1.1.1 -r1.1.1.1.2.3
--- net/ipv6/Kconfig 31 Oct 2002 04:02:51 -0000 1.1.1.1
+++ net/ipv6/Kconfig 1 Nov 2002 08:36:47 -0000 1.1.1.1.2.3
@@ -1,5 +1,21 @@
#
# IPv6 configuration
#
+config IPV6_PRIVACY
+ bool "IPv6: Privacy Extensions (RFC 3041) support"
+ depends on IPV6
+ ---help---
+ 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 do not generate temporary addresses.
+ To use temporary addresses, do
+
+ echo 2 >/proc/sys/net/ipv6/conf/all/use_tempaddr
+
+ See <file:Documentation/networking/ip-sysctl.txt> for details.
+
source "net/ipv6/netfilter/Kconfig"

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.8.2
diff -u -r1.1.1.4 -r1.1.1.4.8.2
--- net/ipv6/addrconf.c 30 Oct 2002 09:43:18 -0000 1.1.1.4
+++ net/ipv6/addrconf.c 1 Nov 2002 08:29:09 -0000 1.1.1.4.8.2
@@ -28,6 +28,8 @@
* packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer.
+ * YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
+ * support.
*/

#include <linux/config.h>
@@ -62,6 +64,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 +91,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 +137,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 = 0,
+ .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 +158,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 = 0,
+ .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 +304,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 +446,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 +479,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 +501,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 +539,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 +637,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 +663,7 @@
struct inet6_dev *idev;
struct rt6_info *rt;
int err;
+ int hiscore = -1, score;

rt = (struct rt6_info *) dst;
if (rt)
@@ -497,17 +693,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 +736,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 +767,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 +862,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 +942,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 +1215,7 @@
struct inet6_ifaddr * ifp;
struct in6_addr addr;
int plen;
+ int create = 0;

plen = pinfo->prefix_len >> 3;

@@ -924,6 +1251,7 @@
return;
}

+ create = 1;
addrconf_dad_start(ifp);
}

@@ -934,6 +1262,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 +1277,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 +2277,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 +2324,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 +2364,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;
}


--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2003-02-24 06:37:30

by David Miller

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

From: YOSHIFUJI Hideaki / 吉藤英明 <[email protected]>
Date: Fri, 01 Nov 2002 17:48:32 +0900 (JST)

Ok, here's revised one.

- sync with linux-2.5.45.
- change default value for use_tempaddr sysctl to 0
(don't generate and use temprary addresses by default)

It is applied.

Hmmm, some thinking is needed in order to backport this to
2.4.x due to lack of crypto library. I guess USAGI 2.4.x
version of this patch uses crypto library from USAGI 2.4.x ipsec?

2003-02-24 06:48:49

by YOSHIFUJI Hideaki

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

In article <[email protected]> (at Sun, 23 Feb 2003 22:31:14 -0800 (PST)), "David S. Miller" <[email protected]> says:

> Hmmm, some thinking is needed in order to backport this to
> 2.4.x due to lack of crypto library. I guess USAGI 2.4.x
> version of this patch uses crypto library from USAGI 2.4.x ipsec?

MD5 code in linux-2.4.x patch what I sent you was taken from
Colin Plumb's public domain implementation.
(USAGI itself uses KAME implementation.)

--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2003-02-24 06:59:06

by David Miller

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

From: YOSHIFUJI Hideaki / 吉藤英明 <[email protected]>
Date: Mon, 24 Feb 2003 15:58:52 +0900 (JST)

MD5 code in linux-2.4.x patch what I sent you was taken from
Colin Plumb's public domain implementation.
(USAGI itself uses KAME implementation.)

Please send me the 2.4.x version of the privacy
extension patch so that I may have a look.

Thank you.

2003-02-25 15:31:48

by YOSHIFUJI Hideaki

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

Hi,

In article <[email protected]> (at Sun, 23 Feb 2003 22:31:14 -0800 (PST)), "David S. Miller" <[email protected]> says:

> From: YOSHIFUJI Hideaki / 吉藤英明 <[email protected]>
> Date: Fri, 01 Nov 2002 17:48:32 +0900 (JST)
>
> Ok, here's revised one.
>
> - sync with linux-2.5.45.
> - change default value for use_tempaddr sysctl to 0
> (don't generate and use temprary addresses by default)
>
> It is applied.

Thanks.

Well, I've found a bug that a temporary addresses were not
re-generated properly. Here's the patch for linux-2.5.63.
(Patch I've sent for linux-2.4.x contains this change.)

Thanks in advance.

Index: net/ipv6/addrconf.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/addrconf.c,v
retrieving revision 1.1.1.6
retrieving revision 1.1.1.6.2.1
diff -u -r1.1.1.6 -r1.1.1.6.2.1
--- net/ipv6/addrconf.c 25 Feb 2003 05:33:26 -0000 1.1.1.6
+++ net/ipv6/addrconf.c 25 Feb 2003 07:30:32 -0000 1.1.1.6.2.1
@@ -2015,6 +2015,9 @@
write_lock(&addrconf_hash_lock);
for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
unsigned long age;
+#ifdef CONFIG_IPV6_PRIVACY
+ unsigned long regen_advance;
+#endif

if (ifp->flags & IFA_F_PERMANENT)
continue;
@@ -2022,6 +2025,12 @@
spin_lock(&ifp->lock);
age = (now - ifp->tstamp) / HZ;

+#ifdef CONFIG_IPV6_PRIVACY
+ regen_advance = ifp->idev->cnf.regen_max_retry *
+ ifp->idev->cnf.dad_transmits *
+ ifp->idev->nd_parms->retrans_time / HZ;
+#endif
+
if (age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
in6_ifa_hold(ifp);
@@ -2050,6 +2059,28 @@
in6_ifa_put(ifp);
goto restart;
}
+#ifdef CONFIG_IPV6_PRIVACY
+ } else if ((ifp->flags&IFA_F_TEMPORARY) &&
+ !(ifp->flags&IFA_F_TENTATIVE)) {
+ if (age >= ifp->prefered_lft - regen_advance) {
+ struct inet6_ifaddr *ifpub = ifp->ifpub;
+ if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+ next = ifp->tstamp + ifp->prefered_lft * HZ;
+ if (!ifp->regen_count && ifpub) {
+ ifp->regen_count++;
+ in6_ifa_hold(ifp);
+ in6_ifa_hold(ifpub);
+ spin_unlock(&ifp->lock);
+ write_unlock(&addrconf_hash_lock);
+ ipv6_create_tempaddr(ifpub, ifp);
+ in6_ifa_put(ifpub);
+ in6_ifa_put(ifp);
+ goto restart;
+ }
+ } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
+ next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
+ spin_unlock(&ifp->lock);
+#endif
} else {
/* ifp->prefered_lft <= ifp->valid_lft */
if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))

--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2003-02-25 15:44:30

by YOSHIFUJI Hideaki

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

Hi,

In article <[email protected]> (at Sun, 23 Feb 2003 22:52:51 -0800 (PST)), "David S. Miller" <[email protected]> says:

> MD5 code in linux-2.4.x patch what I sent you was taken from
> Colin Plumb's public domain implementation.
> (USAGI itself uses KAME implementation.)
>
> Please send me the 2.4.x version of the privacy
> extension patch so that I may have a look.

Here's the patch for linux-2.4.21-pre4.
Thanks.

Index: Documentation/Configure.help
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/Documentation/Configure.help,v
retrieving revision 1.1.1.4
retrieving revision 1.1.1.4.2.1
diff -u -r1.1.1.4 -r1.1.1.4.2.1
--- Documentation/Configure.help 24 Feb 2003 09:48:53 -0000 1.1.1.4
+++ Documentation/Configure.help 24 Feb 2003 10:40:59 -0000 1.1.1.4.2.1
@@ -5627,6 +5627,19 @@

It is safe to say N here for now.

+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
+
Kernel httpd acceleration
CONFIG_KHTTPD
The kernel httpd acceleration daemon (kHTTPd) is a (limited) web
Index: Documentation/networking/ip-sysctl.txt
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/Documentation/networking/ip-sysctl.txt,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -u -r1.1.1.2 -r1.1.1.2.2.1
--- Documentation/networking/ip-sysctl.txt 24 Feb 2003 09:48:56 -0000 1.1.1.2
+++ Documentation/networking/ip-sysctl.txt 24 Feb 2003 10:40:59 -0000 1.1.1.2.2.1
@@ -613,6 +613,36 @@
routers are present.
Default: 3

+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
+
icmp/*:
ratelimit - INTEGER
Limit the maximal rates for sending ICMPv6 packets.
Index: include/linux/md5.h
===================================================================
RCS file: include/linux/md5.h
diff -N include/linux/md5.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ include/linux/md5.h 24 Feb 2003 10:40:59 -0000 1.1.6.1
@@ -0,0 +1,23 @@
+/*
+ * md5.h - for lib/md5.c
+ *
+ * $USAGI: md5.h,v 1.1.6.1 2003/02/24 10:40:59 yoshfuji Exp $
+ */
+
+#ifndef _LINUX_MD5_H
+#define _LINUX_MD5_H
+
+typedef struct MD5Context {
+ __u32 buf[4];
+ __u32 bits[2];
+ __u8 in[64];
+} MD5_CTX;
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context,
+ __u8 const *buf, unsigned int len);
+void MD5Final(__u8 digest[16],
+ struct MD5Context *context);
+void MD5Transform(__u32 buf[4], __u32 const in[16]);
+
+#endif /* !_LINUX_MD5_H */
Index: include/linux/rtnetlink.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/include/linux/rtnetlink.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.30.1
diff -u -r1.1.1.2 -r1.1.1.2.30.1
--- include/linux/rtnetlink.h 9 Oct 2002 01:35:37 -0000 1.1.1.2
+++ include/linux/rtnetlink.h 24 Feb 2003 10:40:59 -0000 1.1.1.2.30.1
@@ -315,6 +315,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/linux24/include/linux/sysctl.h,v
retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.2.1
diff -u -r1.1.1.3 -r1.1.1.3.2.1
--- include/linux/sysctl.h 24 Feb 2003 09:47:45 -0000 1.1.1.3
+++ include/linux/sysctl.h 24 Feb 2003 10:40:59 -0000 1.1.1.3.2.1
@@ -375,7 +375,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/linux24/include/net/addrconf.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.2.1
diff -u -r1.1.1.2 -r1.1.1.2.2.1
--- include/net/addrconf.h 24 Feb 2003 09:47:49 -0000 1.1.1.2
+++ include/net/addrconf.h 24 Feb 2003 10:40:59 -0000 1.1.1.2.2.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/linux24/include/net/if_inet6.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.54.1
diff -u -r1.1.1.1 -r1.1.1.1.54.1
--- include/net/if_inet6.h 20 Aug 2002 09:46:45 -0000 1.1.1.1
+++ include/net/if_inet6.h 24 Feb 2003 10:40:59 -0000 1.1.1.1.54.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: lib/Config.in
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/lib/Config.in,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.26.1
diff -u -r1.1.1.1 -r1.1.1.1.26.1
--- lib/Config.in 9 Oct 2002 01:35:37 -0000 1.1.1.1
+++ lib/Config.in 24 Feb 2003 10:40:59 -0000 1.1.1.1.26.1
@@ -5,6 +5,19 @@
comment 'Library routines'

#
+# MD5 digest
+#
+if [ "$CONFIG_IPV6_PRIVACY" = "y" ]; then
+ if [ "$CONFIG_IPV6" = "y" ]; then
+ define_tristate CONFIG_MD5 y
+ else
+ define_tristate CONFIG_MD5 m
+ fi
+else
+ tristate 'MD5 digest support' CONFIG_MD5
+fi
+
+#
# Do we need the compression support?
#
if [ "$CONFIG_CRAMFS" = "y" -o \
Index: lib/Makefile
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/lib/Makefile,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.30.1
diff -u -r1.1.1.2 -r1.1.1.2.30.1
--- lib/Makefile 9 Oct 2002 01:35:37 -0000 1.1.1.2
+++ lib/Makefile 24 Feb 2003 10:40:59 -0000 1.1.1.2.30.1
@@ -20,6 +20,11 @@
obj-y += dec_and_lock.o
endif

+obj-$(CONFIG_MD5) += md5.o
+ifeq ($(CONFIG_MD5),y)
+ export-objs += md5.o
+endif
+
subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate

Index: lib/md5.c
===================================================================
RCS file: lib/md5.c
diff -N lib/md5.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/md5.c 24 Feb 2003 10:40:59 -0000 1.1.6.1
@@ -0,0 +1,252 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Modified for Linux kernel by YOSHIFUJI Hideaki / USAGI Project.
+ * $USAGI: md5.c,v 1.1.6.1 2003/02/24 10:40:59 yoshfuji Exp $
+ */
+#include <asm/byteorder.h>
+#include <linux/module.h>
+#include <linux/string.h> /* for memcpy() */
+#include <linux/md5.h>
+
+#ifndef __LITTLE_ENDIAN
+#define byteReverse(buf, len) do { } while(0)
+#else
+static inline void byteReverse(u32 *p, int longs)
+{
+ do {
+ *p = cpu_to_le32p(p);
+ p++;
+ } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, u8 const *buf, unsigned int len)
+{
+ unsigned int t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ u8 *p = (u8 *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse((u32*)ctx->in, 16);
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse((u32*)ctx->in, 16);
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(u8 digest[16], struct MD5Context *ctx)
+{
+ u32 count;
+ u8 *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ * always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse((u32*)ctx->in, 16);
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse((u32*)ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((u32 *) ctx->in)[14] = ctx->bits[0];
+ ((u32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+ byteReverse(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(__u32 buf[4], __u32 const in[16])
+{
+ register u32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#ifdef CONFIG_MD5
+EXPORT_SYMBOL(MD5Init);
+EXPORT_SYMBOL(MD5Update);
+EXPORT_SYMBOL(MD5Final);
+EXPORT_SYMBOL(MD5Transform);
+#endif
+
Index: net/ipv6/Config.in
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/Config.in,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.50.1
diff -u -r1.1.1.1 -r1.1.1.1.50.1
--- net/ipv6/Config.in 20 Aug 2002 09:47:02 -0000 1.1.1.1
+++ net/ipv6/Config.in 24 Feb 2003 10:40:59 -0000 1.1.1.1.50.1
@@ -5,6 +5,8 @@
#bool ' IPv6: flow policy support' CONFIG_RT6_POLICY
#bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL

+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/linux24/net/ipv6/addrconf.c,v
retrieving revision 1.1.1.4
retrieving revision 1.1.1.4.2.3
diff -u -r1.1.1.4 -r1.1.1.4.2.3
--- net/ipv6/addrconf.c 24 Feb 2003 09:47:55 -0000 1.1.1.4
+++ net/ipv6/addrconf.c 25 Feb 2003 07:45:16 -0000 1.1.1.4.2.3
@@ -28,6 +28,8 @@
* packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer.
+ * YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
+ * support.
*/

#include <linux/config.h>
@@ -62,6 +64,11 @@
#include <linux/if_tunnel.h>
#include <linux/rtnetlink.h>

+#ifdef CONFIG_IPV6_PRIVACY
+#include <linux/random.h>
+#include <linux/md5.h>
+#endif
+
#include <asm/uaccess.h>

#define IPV6_MAX_ADDRESSES 16
@@ -83,6 +90,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 +136,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 +157,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 +303,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 +445,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 +478,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 +500,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 +538,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 +636,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 +662,7 @@
struct inet6_dev *idev;
struct rt6_info *rt;
int err;
+ int hiscore = -1, score;

rt = (struct rt6_info *) dst;
if (rt)
@@ -497,17 +692,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 +735,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 +766,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 +861,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 +941,91 @@
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];
+ MD5_CTX ctx;
+
+ 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:
+ MD5Init(&ctx);
+ MD5Update(&ctx, idev->entropy, 8);
+ MD5Update(&ctx, eui64, 8);
+ MD5Final(digest, &ctx);
+ 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 +1197,7 @@
struct inet6_ifaddr * ifp;
struct in6_addr addr;
int plen;
+ int create = 0;

plen = pinfo->prefix_len >> 3;

@@ -924,6 +1233,7 @@
return;
}

+ create = 1;
addrconf_dad_start(ifp);
}

@@ -934,6 +1244,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 +1259,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);
}
@@ -1643,6 +1992,9 @@
write_lock(&addrconf_hash_lock);
for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
unsigned long age;
+#ifdef CONFIG_IPV6_PRIVACY
+ unsigned long regen_advance;
+#endif

if (ifp->flags & IFA_F_PERMANENT)
continue;
@@ -1650,6 +2002,12 @@
spin_lock(&ifp->lock);
age = (now - ifp->tstamp) / HZ;

+#ifdef CONFIG_IPV6_PRIVACY
+ regen_advance = ifp->idev->cnf.regen_max_retry *
+ ifp->idev->cnf.dad_transmits *
+ ifp->idev->nd_parms->retrans_time / HZ;
+#endif
+
if (age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
in6_ifa_hold(ifp);
@@ -1678,6 +2036,28 @@
in6_ifa_put(ifp);
goto restart;
}
+#ifdef CONFIG_IPV6_PRIVACY
+ } else if ((ifp->flags&IFA_F_TEMPORARY) &&
+ !(ifp->flags&IFA_F_TENTATIVE)) {
+ if (age >= ifp->prefered_lft - regen_advance) {
+ struct inet6_ifaddr *ifpub = ifp->ifpub;
+ if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+ next = ifp->tstamp + ifp->prefered_lft * HZ;
+ if (!ifp->regen_count && ifpub) {
+ ifp->regen_count++;
+ in6_ifa_hold(ifp);
+ in6_ifa_hold(ifpub);
+ spin_unlock(&ifp->lock);
+ write_unlock(&addrconf_hash_lock);
+ ipv6_create_tempaddr(ifpub, ifp);
+ in6_ifa_put(ifpub);
+ in6_ifa_put(ifp);
+ goto restart;
+ }
+ } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
+ next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
+ spin_unlock(&ifp->lock);
+#endif
} else {
/* ifp->prefered_lft <= ifp->valid_lft */
if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
@@ -1910,7 +2290,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 +2337,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 +2377,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;
}

--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2003-02-25 15:56:24

by Christoph Hellwig

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

On Wed, Feb 26, 2003 at 12:36:25AM +0900, YOSHIFUJI Hideaki / ?$B5HF#1QL@?(B wrote:
> +#
> +if [ "$CONFIG_IPV6_PRIVACY" = "y" ]; then
> + if [ "$CONFIG_IPV6" = "y" ]; then
> + define_tristate CONFIG_MD5 y
> + else
> + define_tristate CONFIG_MD5 m
> + fi
> +else
> + tristate 'MD5 digest support' CONFIG_MD5
> +fi

Config.in files use three-space indents.

> +obj-$(CONFIG_MD5) += md5.o
> +ifeq ($(CONFIG_MD5),y)
> + export-objs += md5.o
> +endif

this is wrong, objects are added to export-objs unconditional.

> +
> +#ifdef CONFIG_MD5
> +EXPORT_SYMBOL(MD5Init);
> +EXPORT_SYMBOL(MD5Update);
> +EXPORT_SYMBOL(MD5Final);
> +EXPORT_SYMBOL(MD5Transform);
> +#endif

Please remove the ifdef, it doesn't make any sense.


Also I really wonder whether we want to add just md5.c to 2.4 or
backport the cryptoapi core with md5 as the only algorithm so far..

2003-02-25 17:40:18

by YOSHIFUJI Hideaki

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

Hello.

In article <[email protected]> (at Tue, 25 Feb 2003 16:06:34 +0000), Christoph Hellwig <[email protected]> says:

> Config.in files use three-space indents.
:
> > +ifeq ($(CONFIG_MD5),y)
> > + export-objs += md5.o
> > +endif
>
> this is wrong, objects are added to export-objs unconditional.
>
> > +
> > +#ifdef CONFIG_MD5
:
> > +EXPORT_SYMBOL(MD5Transform);
> > +#endif
>
> Please remove the ifdef, it doesn't make any sense.

Thanks for comments. How about this? (only lib part)

Index: lib/Config.in
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/lib/Config.in,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.26.2
diff -u -r1.1.1.1 -r1.1.1.1.26.2
--- lib/Config.in 9 Oct 2002 01:35:37 -0000 1.1.1.1
+++ lib/Config.in 25 Feb 2003 17:18:27 -0000 1.1.1.1.26.2
@@ -5,6 +5,19 @@
comment 'Library routines'

#
+# MD5 digest
+#
+if [ "$CONFIG_IPV6_PRIVACY" = "y" ]; then
+ if [ "$CONFIG_IPV6" = "y" ]; then
+ define_tristate CONFIG_MD5 y
+ else
+ define_tristate CONFIG_MD5 m
+ fi
+else
+ tristate 'MD5 digest support' CONFIG_MD5
+fi
+
+#
# Do we need the compression support?
#
if [ "$CONFIG_CRAMFS" = "y" -o \
Index: lib/Makefile
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/lib/Makefile,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.30.2
diff -u -r1.1.1.2 -r1.1.1.2.30.2
--- lib/Makefile 9 Oct 2002 01:35:37 -0000 1.1.1.2
+++ lib/Makefile 25 Feb 2003 17:18:27 -0000 1.1.1.2.30.2
@@ -8,7 +8,7 @@

L_TARGET := lib.a

-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o rbtree.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o rbtree.o md5.o

obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
bust_spinlocks.o rbtree.o dump_stack.o
@@ -19,6 +19,8 @@
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
obj-y += dec_and_lock.o
endif
+
+obj-$(CONFIG_MD5) += md5.o

subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
Index: lib/md5.c
===================================================================
RCS file: lib/md5.c
diff -N lib/md5.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/md5.c 25 Feb 2003 17:18:27 -0000 1.1.6.2
@@ -0,0 +1,250 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Modified for Linux kernel by YOSHIFUJI Hideaki / USAGI Project.
+ * $USAGI: md5.c,v 1.1.6.2 2003/02/25 17:18:27 yoshfuji Exp $
+ */
+#include <asm/byteorder.h>
+#include <linux/module.h>
+#include <linux/string.h> /* for memcpy() */
+#include <linux/md5.h>
+
+#ifndef __LITTLE_ENDIAN
+#define byteReverse(buf, len) do { } while(0)
+#else
+static inline void byteReverse(u32 *p, int longs)
+{
+ do {
+ *p = cpu_to_le32p(p);
+ p++;
+ } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, u8 const *buf, unsigned int len)
+{
+ unsigned int t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ u8 *p = (u8 *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse((u32*)ctx->in, 16);
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse((u32*)ctx->in, 16);
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(u8 digest[16], struct MD5Context *ctx)
+{
+ u32 count;
+ u8 *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ * always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse((u32*)ctx->in, 16);
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse((u32*)ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((u32 *) ctx->in)[14] = ctx->bits[0];
+ ((u32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (u32 *) ctx->in);
+ byteReverse(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(__u32 buf[4], __u32 const in[16])
+{
+ register u32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+EXPORT_SYMBOL(MD5Init);
+EXPORT_SYMBOL(MD5Update);
+EXPORT_SYMBOL(MD5Final);
+EXPORT_SYMBOL(MD5Transform);
+

--
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA

2003-02-25 17:41:43

by Christoph Hellwig

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

On Wed, Feb 26, 2003 at 02:47:50AM +0900, YOSHIFUJI Hideaki / ?$B5HF#1QL@?(B wrote:
> Thanks for comments. How about this? (only lib part)

This one looks fine.

2003-02-26 08:27:21

by James Morris

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

On Tue, 25 Feb 2003, Christoph Hellwig wrote:

> Also I really wonder whether we want to add just md5.c to 2.4 or
> backport the cryptoapi core with md5 as the only algorithm so far..

Any backport of new cryptoapi is likely to be some way off (after 2.6
stabilizes), so the md5 module submitted for 2.4 is required for the time
being.


- James
--
James Morris
<[email protected]>


2003-02-26 08:56:34

by David Miller

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

From: James Morris <[email protected]>
Date: Wed, 26 Feb 2003 19:33:18 +1100 (EST)

On Tue, 25 Feb 2003, Christoph Hellwig wrote:

> Also I really wonder whether we want to add just md5.c to 2.4 or
> backport the cryptoapi core with md5 as the only algorithm so far..

Any backport of new cryptoapi is likely to be some way off (after 2.6
stabilizes), so the md5 module submitted for 2.4 is required for the time
being.

This could be accelerated.

2003-03-03 09:01:50

by David Miller

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

From: YOSHIFUJI Hideaki / 吉藤英明 <[email protected]>
Date: Wed, 26 Feb 2003 00:41:55 +0900 (JST)

Well, I've found a bug that a temporary addresses were not
re-generated properly. Here's the patch for linux-2.5.63.

Fix applied, thanks.