diff options
-rw-r--r-- | sbin/ifconfig/ifconfig.8 | 33 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 12 | ||||
-rw-r--r-- | sys/net/if.h | 7 | ||||
-rw-r--r-- | sys/netinet6/in6.h | 3 | ||||
-rw-r--r-- | sys/netinet6/in6_ifattach.c | 28 | ||||
-rw-r--r-- | sys/netinet6/in6_var.h | 3 | ||||
-rw-r--r-- | sys/netinet6/nd6.h | 7 | ||||
-rw-r--r-- | sys/netinet6/nd6_rtr.c | 67 |
8 files changed, 135 insertions, 25 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 52efd5a2038..003fb9ba4ac 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ifconfig.8,v 1.193 2010/04/02 21:16:24 deraadt Exp $ +.\" $OpenBSD: ifconfig.8,v 1.194 2010/04/06 14:12:10 stsp Exp $ .\" $NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $ .\" $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $ .\" @@ -31,7 +31,7 @@ .\" .\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94 .\" -.Dd $Mdocdate: April 2 2010 $ +.Dd $Mdocdate: April 6 2010 $ .Dt IFCONFIG 8 .Os .Sh NAME @@ -1103,6 +1103,7 @@ authentication. .Bk -words .Ar inet6-interface .Op Oo Fl Oc Cm anycast +.Op Oo Fl Oc Cm autoconfprivacy .Op Cm eui64 .Op Cm pltime Ar n .Op Oo Fl Oc Cm tentative @@ -1115,6 +1116,34 @@ The options are as follows: Set the IPv6 anycast address bit. .It Fl anycast Clear the IPv6 anycast address bit. +.It Cm autoconfprivacy +Enable privacy extensions for stateless IPv6 address autoconfiguration +(RFC 4941) on the interface. +The purpose of these extensions is to prevent tracking of individual +devices which connect to the IPv6 internet from different networks +using stateless autoconfiguration. +The interface identifier often remains constant and provides the lower +64 bits of an autoconfigured IPv6 address, facilitating tracking of +individual devices (and hence, potentially, users of these devices) +over long periods of time (weeks to months to years). +When these extensions are active, random interface identifiers are used +for autoconfigured addresses. +Autoconfigured addresses are also made temporary, which means that they +will automatically be replaced regularly. +Temporary addresses are deprecated after 24 hours. +Once a temporary address has been deprecated, a new temporary address +will be configured upon reception of a router advertisement indicating +that the prefix is still valid. +Deprecated addresses will not be used for new connections as long as a +non-deprecated address remains available. +Temporary addresses become invalid after one week, at which time they +will be removed from the interface. +Address lifetime extension through router advertisements is ignored +for temporary addresses. +.It Fl autoconfprivacy +Disable IPv6 autoconf privacy extensions on the interface. +Currently configured addresses will not be removed until they become +invalid. .It Cm eui64 Fill the interface index .Pq the lowermost 64th bit of an IPv6 address diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 7dcc488e362..b3ba114f908 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ifconfig.c,v 1.230 2010/04/03 03:13:01 deraadt Exp $ */ +/* $OpenBSD: ifconfig.c,v 1.231 2010/04/06 14:12:10 stsp Exp $ */ /* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */ /* @@ -338,6 +338,8 @@ const struct cmd { { "pltime", NEXTARG, 0, setia6pltime }, { "vltime", NEXTARG, 0, setia6vltime }, { "eui64", 0, 0, setia6eui64 }, + { "autoconfprivacy", IFXF_INET6_PRIVACY, 0, setifxflags }, + { "-autoconfprivacy", -IFXF_INET6_PRIVACY, 0, setifxflags }, #endif /*INET6*/ #ifndef SMALL { "rtlabel", NEXTARG, 0, setifrtlabel }, @@ -1189,6 +1191,12 @@ setifxflags(const char *vname, int value) { struct ifreq my_ifr; + if ((value == IFXF_INET6_PRIVACY || value == -IFXF_INET6_PRIVACY) + && afp->af_af != AF_INET6) { + errx(1, "autoconfprivacy needs AF inet6, current AF is `%s'", + afp->af_name); + } + bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); if (ioctl(s, SIOCGIFXFLAGS, (caddr_t)&my_ifr) < 0) @@ -2981,6 +2989,8 @@ in6_alias(struct in6_ifreq *creq) printf(" deprecated"); if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF) printf(" autoconf"); + if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PRIVACY) + printf(" autoconfprivacy"); } if (scopeid) diff --git a/sys/net/if.h b/sys/net/if.h index 8425dc0fd80..d467bbaa20e 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if.h,v 1.113 2010/01/13 02:26:49 henning Exp $ */ +/* $OpenBSD: if.h,v 1.114 2010/04/06 14:12:10 stsp Exp $ */ /* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */ /* @@ -323,8 +323,9 @@ struct ifnet { /* and the entries */ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\ IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI) -#define IFXF_TXREADY 0x1 /* interface is ready to tx */ -#define IFXF_NOINET6 0x2 /* don't do inet6 */ +#define IFXF_TXREADY 0x1 /* interface is ready to tx */ +#define IFXF_NOINET6 0x2 /* don't do inet6 */ +#define IFXF_INET6_PRIVACY 0x4 /* autoconf privacy extension */ #define IFXF_CANTCHANGE \ (IFXF_TXREADY) diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index c50b86e0547..336bf2e1d49 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.h,v 1.48 2009/11/05 20:50:14 michele Exp $ */ +/* $OpenBSD: in6.h,v 1.49 2010/04/06 14:12:10 stsp Exp $ */ /* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */ /* @@ -784,6 +784,7 @@ int in6_addrscope(struct in6_addr *); struct in6_ifaddr *in6_ifawithscope(struct ifnet *, struct in6_addr *); struct in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *); extern void in6_if_up(struct ifnet *); +void in6_get_rand_ifid(struct ifnet *, struct in6_addr *); #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index c24a1bb9c0f..be61bddc831 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_ifattach.c,v 1.50 2010/02/08 12:04:35 jsing Exp $ */ +/* $OpenBSD: in6_ifattach.c,v 1.51 2010/04/06 14:12:10 stsp Exp $ */ /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */ /* @@ -58,11 +58,13 @@ #include <netinet6/ip6_mroute.h> #endif +#include <dev/rndvar.h> + unsigned long in6_maxmtu = 0; int ip6_auto_linklocal = 1; /* enable by default */ -int get_rand_ifid(struct ifnet *, struct in6_addr *); +int get_last_resort_ifid(struct ifnet *, struct in6_addr *); int get_hw_ifid(struct ifnet *, struct in6_addr *); int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); int in6_ifattach_loopback(struct ifnet *); @@ -88,7 +90,7 @@ int in6_ifattach_loopback(struct ifnet *); * in6 - upper 64bits are preserved */ int -get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) +get_last_resort_ifid(struct ifnet *ifp, struct in6_addr *in6) { MD5_CTX ctxt; u_int8_t digest[16]; @@ -119,6 +121,24 @@ get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) } /* + * Generate a random interface identifier. + * + * in6 - upper 64bits are preserved + */ +void +in6_get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) +{ + arc4random_buf(&in6->s6_addr32[2], 8); + + /* make sure to set "u" bit to local, and "g" bit to individual. */ + in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ + in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ + + /* convert EUI64 into IPv6 interface identifier */ + EUI64_TO_IFID(in6); +} + +/* * Get interface identifier for the specified interface. * XXX assumes single sockaddr_dl (AF_LINK address) per an interface * @@ -280,7 +300,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, struct in6_addr *in6) } /* last resort: get from random number source */ - if (get_rand_ifid(ifp, in6) == 0) { + if (get_last_resort_ifid(ifp, in6) == 0) { nd6log((LOG_DEBUG, "%s: interface identifier generated by random number\n", ifp0->if_xname)); diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index b55993a1d35..82df23171d4 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_var.h,v 1.30 2008/10/01 21:17:06 claudio Exp $ */ +/* $OpenBSD: in6_var.h,v 1.31 2010/04/06 14:12:10 stsp Exp $ */ /* $KAME: in6_var.h,v 1.55 2001/02/16 12:49:45 itojun Exp $ */ /* @@ -438,6 +438,7 @@ struct in6_rrenumreq { * (used only at first SIOC* call) */ #define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */ +#define IN6_IFF_PRIVACY 0x80 /* RFC 4941 temporary address */ /* do not input/output */ #define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED) diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 45d45054784..6eed9551610 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6.h,v 1.26 2008/06/11 06:30:36 mcbride Exp $ */ +/* $OpenBSD: nd6.h,v 1.27 2010/04/06 14:12:10 stsp Exp $ */ /* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */ /* @@ -222,6 +222,11 @@ struct in6_ndifreq { #define ND6_INFINITE_LIFETIME 0xffffffff +/* contants for RFC 4941 autoconf privacy extension */ +#define ND6_PRIV_MAX_DESYNC_FACTOR 600 /* 10 minutes */ +#define ND6_PRIV_VALID_LIFETIME 604800 /* 1 week */ +#define ND6_PRIV_PREFERRED_LIFETIME 86400 /* 1 day */ + #ifdef _KERNEL /* node constants */ #define MAX_REACHABLE_TIME 3600000 /* msec */ diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index d706afa184c..c882331c078 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6_rtr.c,v 1.51 2010/02/08 11:56:09 jsing Exp $ */ +/* $OpenBSD: nd6_rtr.c,v 1.52 2010/04/06 14:12:10 stsp Exp $ */ /* $KAME: nd6_rtr.c,v 1.97 2001/02/07 11:09:13 itojun Exp $ */ /* @@ -57,6 +57,8 @@ #include <netinet6/nd6.h> #include <netinet/icmp6.h> +#include <dev/rndvar.h> + #define SDL(s) ((struct sockaddr_dl *)s) int rtpref(struct nd_defrouter *); @@ -1044,6 +1046,7 @@ prelist_update(struct nd_prefix *new, struct nd_defrouter *dr, struct mbuf *m) struct nd_prefix *pr; int s = splsoftnet(); int error = 0; + int tempaddr_preferred = 0; int auth; struct in6_addrlifetime lt6_tmp; @@ -1210,6 +1213,18 @@ prelist_update(struct nd_prefix *new, struct nd_defrouter *dr, struct mbuf *m) * with the Subject "StoredLifetime in RFC 2462". */ lt6_tmp = ifa6->ia6_lifetime; + + /* RFC 4941 temporary addresses (privacy extension). */ + if (ifa6->ia6_flags & IN6_IFF_PRIVACY) { + /* Do we still have a non-deprecated address? */ + if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0) + tempaddr_preferred = 1; + /* Don't extend lifetime for temporary addresses. */ + if (new->ndpr_vltime >= lt6_tmp.ia6t_vltime) + continue; + if (new->ndpr_pltime >= lt6_tmp.ia6t_pltime) + continue; + } if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) storedlifetime = ND6_INFINITE_LIFETIME; else if (time_second - ifa6->ia6_updatetime > @@ -1254,9 +1269,14 @@ prelist_update(struct nd_prefix *new, struct nd_defrouter *dr, struct mbuf *m) ifa6->ia6_lifetime = lt6_tmp; ifa6->ia6_updatetime = time_second; } - if (ia6_match == NULL && new->ndpr_vltime) { + + if ((ia6_match == NULL || + (((ia6_match->ia6_flags & IN6_IFF_PRIVACY) || + (ifp->if_xflags & IFXF_INET6_PRIVACY)) && !tempaddr_preferred)) && + new->ndpr_vltime) { /* - * No address matched and the valid lifetime is non-zero. + * No address matched, or there is no preferred RFC 4941 + * temporary address. And the valid prefix lifetime is non-zero. * Create a new address. */ if ((ia6 = in6_ifadd(new)) != NULL) { @@ -1683,7 +1703,7 @@ in6_ifadd(struct nd_prefix *pr) struct in6_aliasreq ifra; struct in6_ifaddr *ia, *ib; int error, s, plen0; - struct in6_addr mask; + struct in6_addr mask, rand_ifid; int prefixlen = pr->ndpr_plen; in6_prefixlen2mask(&mask, prefixlen); @@ -1750,14 +1770,29 @@ in6_ifadd(struct nd_prefix *pr) ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; /* interface ID */ - ifra.ifra_addr.sin6_addr.s6_addr32[0] |= - (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); - ifra.ifra_addr.sin6_addr.s6_addr32[1] |= - (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); - ifra.ifra_addr.sin6_addr.s6_addr32[2] |= - (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); - ifra.ifra_addr.sin6_addr.s6_addr32[3] |= - (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); + if (ifp->if_xflags & IFXF_INET6_PRIVACY) { + ifra.ifra_flags |= IN6_IFF_PRIVACY; + bcopy(&pr->ndpr_prefix.sin6_addr, &rand_ifid, + sizeof(rand_ifid)); + in6_get_rand_ifid(ifp, &rand_ifid); + ifra.ifra_addr.sin6_addr.s6_addr32[0] |= + (rand_ifid.s6_addr32[0] & ~mask.s6_addr32[0]); + ifra.ifra_addr.sin6_addr.s6_addr32[1] |= + (rand_ifid.s6_addr32[1] & ~mask.s6_addr32[1]); + ifra.ifra_addr.sin6_addr.s6_addr32[2] |= + (rand_ifid.s6_addr32[2] & ~mask.s6_addr32[2]); + ifra.ifra_addr.sin6_addr.s6_addr32[3] |= + (rand_ifid.s6_addr32[3] & ~mask.s6_addr32[3]); + } else { + ifra.ifra_addr.sin6_addr.s6_addr32[0] |= + (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); + ifra.ifra_addr.sin6_addr.s6_addr32[1] |= + (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); + ifra.ifra_addr.sin6_addr.s6_addr32[2] |= + (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); + ifra.ifra_addr.sin6_addr.s6_addr32[3] |= + (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); + } /* new prefix mask. */ ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); @@ -1773,6 +1808,14 @@ in6_ifadd(struct nd_prefix *pr) ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; + if (ifp->if_xflags & IFXF_INET6_PRIVACY) { + if (ifra.ifra_lifetime.ia6t_vltime > ND6_PRIV_VALID_LIFETIME) + ifra.ifra_lifetime.ia6t_vltime = ND6_PRIV_VALID_LIFETIME; + if (ifra.ifra_lifetime.ia6t_pltime > ND6_PRIV_PREFERRED_LIFETIME) + ifra.ifra_lifetime.ia6t_pltime = ND6_PRIV_PREFERRED_LIFETIME + - (arc4random() % ND6_PRIV_MAX_DESYNC_FACTOR); + } + /* XXX: scope zone ID? */ ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ |