diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2010-04-06 14:12:11 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2010-04-06 14:12:11 +0000 |
commit | bda25d7c59718889fb1f1811744126e675edb2bb (patch) | |
tree | 1cc22039fc2575ca3495e34023ca3f25f1aefaa7 /sys/netinet6 | |
parent | 63114f2f6b5cca92cb2e9808403730c1e3acd928 (diff) |
Simple implementation of RFC4941, "Privacy Extensions for Stateless
Address Autoconfiguration in IPv6". For those among us who are paranoid
about broadcasting their MAC address to the IPv6 internet.
Man page help from jmc, testing by weerd, arc4random API hints from djm.
ok deraadt, claudio
Diffstat (limited to 'sys/netinet6')
-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 |
5 files changed, 89 insertions, 19 deletions
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 */ |