ipv6: RFC7217 stable privacy addresses implementation
Subsystems (5)
v2 cover ipv6: RFC7217 stable privacy addresses implementation
Hi all,
this is an implementation of basic support for RFC7217 stable privacy addresses. Please review and consider for net-next.
Bye and thanks,
Hannes
v2:
* Correct references to RFC 7212 -> RFC 7217 in documentation patch (thanks, Eric!)
Hannes Frederic Sowa (8):
lib: EXPORT_SYMBOL sha_init
ipv6: introduce secret_stable to ipv6_devconf
ipv6: generation of stable privacy addresses for link-local and
autoconf
ipv6: introduce IFA_F_STABLE_PRIVACY flag
ipv6: collapse state_lock and lock
ipv6: do retries on stable privacy addresses
ipv6: introduce idgen_delay and idgen_retries knobs
ipv6: add documentation for stable_secret, idgen_delay and
idgen_retries knobs
Documentation/networking/ip-sysctl.txt | 25 +++ include/linux/ipv6.h | 4 + include/net/if_inet6.h | 4 +- include/net/netns/ipv6.h | 2 + include/uapi/linux/if_addr.h | 1 + include/uapi/linux/if_link.h | 1 + include/uapi/linux/ipv6.h | 1 + lib/sha1.c | 1 + net/ipv6/addrconf.c | 293 ++++++++++++++++++++++++++++++--- net/ipv6/af_inet6.c | 2 + net/ipv6/sysctl_net_ipv6.c | 16 ++ 11 files changed, 321 insertions(+), 29 deletions(-)
Signature · 1 line
2.1.0
PATCH v2 1/8 lib: EXPORT_SYMBOL sha_init
We need this symbol later on in ipv6.ko, thus export it via EXPORT_SYMBOL like sha_transform already is.
--- lib/sha1.c | 1 + 1 file changed, 1 insertion(+)
lib/sha1.c +1 -0
@@ -198,3 +198,4 @@ void sha_init(__u32 *buf) buf[3 ] =0x10325476 ; buf[4 ] =0xc3d2e1f0 ; } +EXPORT_SYMBOL (sha_init);
Signature · 1 line
2.1.0
PATCH v2 2/8 ipv6: introduce secret_stable to ipv6_devconf
In reply to Hannes Frederic SowaThis patch implements the procfs logic for the stable_address knob:
The secret is formatted as an ipv6 address and will be stored per interface and per namespace. We track initialized flag and return EIO errors until the secret is set.
We don't inherit the secret to newly created namespaces.
--- include/linux/ipv6.h | 4 +++ include/uapi/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+)
include/linux/ipv6.h +4 -0
@@ -53,6 +53,10 @@ struct ipv6_devconf {__s32 ndisc_notify;__s32 suppress_frag_ndisc;__s32 accept_ra_mtu; +struct ipv6_stable_secret { +bool initialized; +struct in6_addr secret; + } stable_secret;void *sysctl; };
include/uapi/linux/ipv6.h +1 -0
@@ -170,6 +170,7 @@ enum {DEVCONF_ACCEPT_RA_FROM_LOCAL ,DEVCONF_USE_OPTIMISTIC ,DEVCONF_ACCEPT_RA_MTU , +DEVCONF_STABLE_SECRET , DEVCONF_MAX };
net/ipv6/addrconf.c +68 -0
116 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH v2 3/8 ipv6: generation of stable privacy addresses for link-local and autoconf
In reply to Hannes Frederic SowaThis patch implements the stable privacy address generation for link-local and autoconf addresses as specified in RFC7217.
RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key)
is the RID (random identifier). As the hash function F we chose one round of sha1. Prefix will be either the link-local prefix or the router advertised one. As Net_Iface we use the MAC address of the device. DAD_Counter and secret_key are implemented as specified.
We don't use Network_ID, as it couples the code too closely to other subsystems. It is specified as optional in the RFC.
As Net_Iface we only use the MAC address: we simply have no stable identifier in the kernel we could possibly use: because this code might run very early, we cannot depend on names, as they might be changed by user space early on during the boot process.
A new address generation mode is introduced, IN6_ADDR_GEN_MODE_STABLE_PRIVACY. With iproute2 one can switch back to none or eui64 address configuration mode although the stable_secret is already set.
We refuse writes to ipv6/conf/all/stable_secret but only allow ipv6/conf/default/stable_secret and the interface specific file to be written to. The default stable_secret is used as the parameter for the namespace, the interface specific can overwrite the secret, e.g. when switching a network configuration from one system to another while inheriting the secret.
--- include/uapi/linux/if_link.h | 1 + net/ipv6/addrconf.c | 130 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 4 deletions(-)
include/uapi/linux/if_link.h +1 -0
@@ -216,6 +216,7 @@ enum {enum in6_addr_gen_mode {IN6_ADDR_GEN_MODE_EUI64 ,IN6_ADDR_GEN_MODE_NONE , +IN6_ADDR_GEN_MODE_STABLE_PRIVACY , };/* Bridge section */
net/ipv6/addrconf.c +126 -4
172 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH v2 4/8 ipv6: introduce IFA_F_STABLE_PRIVACY flag
In reply to Hannes Frederic SowaWe need to mark appropriate addresses so we can do retries in case their DAD failed.
--- include/uapi/linux/if_addr.h | 1 + net/ipv6/addrconf.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-)
include/uapi/linux/if_addr.h +1 -0
@@ -51,6 +51,7 @@ enum {#define IFA_F_MANAGETEMPADDR 0x100#define IFA_F_NOPREFIXROUTE 0x200#define IFA_F_MCAUTOJOIN 0x400 +#define IFA_F_STABLE_PRIVACY 0x800struct ifa_cacheinfo {__u32 ifa_prefered;
net/ipv6/addrconf.c +8 -6
@@ -2199,6 +2199,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)__u32 valid_lft;__u32 prefered_lft;int addr_type; +u32 addr_flags =0 ;struct inet6_dev *in6_dev;struct net *net =dev_net (dev);
@@ -2309,6 +2310,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) IN6_ADDR_GEN_MODE_STABLE_PRIVACY && !ipv6_generate_stable_address(&addr, 0, in6_dev)) { + addr_flags |=IFA_F_STABLE_PRIVACY ; goto ok; } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) {
@@ -2328,7 +2330,6 @@ ok:if (ifp ==NULL && valid_lft) {int max_addresses = in6_dev->cnf.max_addresses; -u32 addr_flags =0 ;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (in6_dev->cnf.optimistic_dad &&
@@ -2807,10 +2808,11 @@ static void init_loopback(struct net_device *dev) } } -static void addrconf_add_linklocal (struct inet6_dev *idev,const struct in6_addr *addr) +static void addrconf_add_linklocal (struct inet6_dev *idev, +const struct in6_addr *addr,u32 flags) {struct inet6_ifaddr *ifp; -u32 addr_flags =IFA_F_PERMANENT ; +u32 addr_flags = flags |IFA_F_PERMANENT ;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (idev->cnf.optimistic_dad &&
@@ -2818,7 +2820,6 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr addr_flags |=IFA_F_OPTIMISTIC ;#endif - ifp =ipv6_add_addr (idev, addr,NULL ,64 ,IFA_LINK , addr_flags,INFINITY_LIFE_TIME ,INFINITY_LIFE_TIME );if (!IS_ERR (ifp)) {
@@ -2916,7 +2917,8 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)if (idev->addr_gen_mode ==IN6_ADDR_GEN_MODE_STABLE_PRIVACY ) {if (!ipv6_generate_stable_address (&addr,0 , idev)) -addrconf_add_linklocal (idev, &addr); +addrconf_add_linklocal (idev, &addr, +IFA_F_STABLE_PRIVACY );else if (prefix_route)addrconf_prefix_route (&addr,64 , idev->dev,0 ,0 ); }else if (idev->addr_gen_mode ==IN6_ADDR_GEN_MODE_EUI64 ) {
@@ -2925,7 +2927,7 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)* couldn't generate one. */ if (ipv6_generate_eui64 (addr.s6_addr +8 , idev->dev) ==0 ) -addrconf_add_linklocal (idev, &addr); +addrconf_add_linklocal (idev, &addr,0 );else if (prefix_route)addrconf_prefix_route (&addr,64 , idev->dev,0 ,0 ); }
Signature · 1 line
2.1.0
PATCH v2 5/8 ipv6: collapse state_lock and lock
In reply to Hannes Frederic Sowa--- include/net/if_inet6.h | 3 +-- net/ipv6/addrconf.c | 31 +++++++++++++++---------------- 2 files changed, 16 insertions(+), 18 deletions(-)
include/net/if_inet6.h +1 -2
@@ -41,13 +41,12 @@ enum {struct inet6_ifaddr {struct in6_addr addr;__u32 prefix_len; - +/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ __u32 valid_lft;__u32 prefered_lft;atomic_t refcnt;spinlock_t lock; -spinlock_t state_lock;int state;
net/ipv6/addrconf.c +15 -16
@@ -873,7 +873,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ifa->peer_addr = *peer_addr;spin_lock_init (&ifa->lock); -spin_lock_init (&ifa->state_lock);INIT_DELAYED_WORK (&ifa->dad_work, addrconf_dad_work);INIT_HLIST_NODE (&ifa->addr_lst); ifa->scope = scope;
@@ -1016,10 +1015,10 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)ASSERT_RTNL (); -spin_lock_bh (&ifp->state_lock); +spin_lock_bh (&ifp->lock); state = ifp->state; ifp->state =INET6_IFADDR_STATE_DEAD ; -spin_unlock_bh (&ifp->state_lock); +spin_unlock_bh (&ifp->lock);if (state ==INET6_IFADDR_STATE_DEAD ) goto out;
@@ -1699,12 +1698,12 @@ static int addrconf_dad_end(struct inet6_ifaddr *ifp) {int err = -ENOENT ; -spin_lock_bh (&ifp->state_lock); +spin_lock_bh (&ifp->lock);if (ifp->state ==INET6_IFADDR_STATE_DAD ) { ifp->state =INET6_IFADDR_STATE_POSTDAD ; err =0 ; } -spin_unlock_bh (&ifp->state_lock); +spin_unlock_bh (&ifp->lock);return err; }
@@ -1737,10 +1736,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) } } -spin_lock_bh (&ifp->state_lock); +spin_lock_bh (&ifp->lock);/* transition from _POSTDAD to _ERRDAD */ ifp->state =INET6_IFADDR_STATE_ERRDAD ; -spin_unlock_bh (&ifp->state_lock); +spin_unlock_bh (&ifp->lock);addrconf_mod_dad_work (ifp,0 ); }
@@ -2369,7 +2368,7 @@ ok:u32 stored_lft;/* update lifetime (RFC2462 5.5.3 e) */ -spin_lock (&ifp->lock); +spin_lock_bh (&ifp->lock); now = jiffies;if (ifp->valid_lft > (now - ifp->tstamp) /HZ ) stored_lft = ifp->valid_lft - (now - ifp->tstamp) /HZ ;
@@ -2399,12 +2398,12 @@ ok: ifp->tstamp = now; flags = ifp->flags; ifp->flags &= ~IFA_F_DEPRECATED ; -spin_unlock (&ifp->lock); +spin_unlock_bh (&ifp->lock);if (!(flags&IFA_F_TENTATIVE ))ipv6_ifa_notify (0 , ifp); }else -spin_unlock (&ifp->lock); +spin_unlock_bh (&ifp->lock);manage_tempaddrs (in6_dev, ifp, valid_lft, prefered_lft, create, now);
@@ -3265,10 +3264,10 @@ restart:write_unlock_bh (&idev->lock); -spin_lock_bh (&ifa->state_lock); +spin_lock_bh (&ifa->lock); state = ifa->state; ifa->state =INET6_IFADDR_STATE_DEAD ; -spin_unlock_bh (&ifa->state_lock); +spin_unlock_bh (&ifa->lock);if (state !=INET6_IFADDR_STATE_DEAD ) {__ipv6_ifa_notify (RTM_DELADDR , ifa);
@@ -3426,12 +3425,12 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp) {bool begin_dad = false; -spin_lock_bh (&ifp->state_lock); +spin_lock_bh (&ifp->lock);if (ifp->state !=INET6_IFADDR_STATE_DEAD ) { ifp->state =INET6_IFADDR_STATE_PREDAD ; begin_dad = true; } -spin_unlock_bh (&ifp->state_lock); +spin_unlock_bh (&ifp->lock);if (begin_dad)addrconf_mod_dad_work (ifp,0 );
@@ -3453,7 +3452,7 @@ static void addrconf_dad_work(struct work_struct *w)rtnl_lock (); -spin_lock_bh (&ifp->state_lock); +spin_lock_bh (&ifp->lock);if (ifp->state ==INET6_IFADDR_STATE_PREDAD ) { action =DAD_BEGIN ; ifp->state =INET6_IFADDR_STATE_DAD ;
@@ -3461,7 +3460,7 @@ static void addrconf_dad_work(struct work_struct *w) action =DAD_ABORT ; ifp->state =INET6_IFADDR_STATE_POSTDAD ; } -spin_unlock_bh (&ifp->state_lock); +spin_unlock_bh (&ifp->lock);if (action ==DAD_BEGIN ) {addrconf_dad_begin (ifp);
Signature · 1 line
2.1.0
PATCH v2 6/8 ipv6: do retries on stable privacy addresses
In reply to Hannes Frederic SowaIf a DAD conflict is detected, we want to retry privacy stable address generation up to idgen_retries (= 3) times with a delay of idgen_delay (= 1 second). Add the logic to addrconf_dad_failure.
By design, we don't clean up dad failed permanent addresses.
--- include/net/if_inet6.h | 1 + net/ipv6/addrconf.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-)
include/net/if_inet6.h +1 -0
@@ -52,6 +52,7 @@ struct inet6_ifaddr {__u32 flags;__u8 dad_probes; +__u8 stable_privacy_retry;__u16 scope;
net/ipv6/addrconf.c +54 -3
76 lines not on this page · raw message
Signature · 1 line
2.1.0
PATCH v2 7/8 ipv6: introduce idgen_delay and idgen_retries knobs
In reply to Hannes Frederic SowaThis is specified by RFC 7217.
--- include/net/netns/ipv6.h | 2 ++ net/ipv6/addrconf.c | 11 ++++------- net/ipv6/af_inet6.c | 2 ++ net/ipv6/sysctl_net_ipv6.c | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 7 deletions(-)
include/net/netns/ipv6.h +2 -0
@@ -32,6 +32,8 @@ struct netns_sysctl_ipv6 {int icmpv6_time;int anycast_src_echo_reply;int fwmark_reflect; +int idgen_retries; +int idgen_delay; };struct netns_ipv6 {
net/ipv6/addrconf.c +4 -7
@@ -1712,6 +1712,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) {struct in6_addr addr;struct inet6_dev *idev = ifp->idev; +struct net *net =dev_net (ifp->idev->dev);if (addrconf_dad_end (ifp)) {in6_ifa_put (ifp);
@@ -1730,11 +1731,9 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)struct inet6_ifaddr *ifp2;u32 valid_lft, preferred_lft;int pfxlen = ifp->prefix_len; -const unsigned int idgen_retries =3 ; -const unsigned int idgen_delay =1 *HZ ;int retries = ifp->stable_privacy_retry +1 ; -if (retries > idgen_retries) { +if (retries > net->ipv6.sysctl.idgen_retries) {net_info_ratelimited ("%s: privacy stable address generation failed because of DAD conflicts!\n" , ifp->idev->dev->name); goto errdad;
@@ -1769,7 +1768,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) ifp2->state =INET6_IFADDR_STATE_PREDAD ;spin_unlock_bh (&ifp2->lock); -addrconf_mod_dad_work (ifp2, idgen_delay); +addrconf_mod_dad_work (ifp2, net->ipv6.sysctl.idgen_delay);in6_ifa_put (ifp2); lock_errdad:spin_lock_bh (&ifp->lock);
@@ -2899,8 +2898,6 @@ static int ipv6_generate_stable_address(struct in6_addr *address,u8 dad_count, const struct inet6_dev *idev) { -static const int idgen_retries =3 ; - static DEFINE_SPINLOCK(lock);static __u32 digest[SHA_DIGEST_WORDS ];static __u32 workspace[SHA_WORKSPACE_WORDS ];
@@ -2950,7 +2947,7 @@ retry:if (ipv6_reserved_interfaceid (temp)) { dad_count++; -if (dad_count > idgen_retries) +if (dad_count >dev_net (idev->dev)->ipv6.sysctl.idgen_retries)return -1 ; goto retry; }
net/ipv6/af_inet6.c +2 -0
@@ -766,6 +766,8 @@ static int __net_init inet6_net_init(struct net *net) net->ipv6.sysctl.icmpv6_time =1 *HZ ; net->ipv6.sysctl.flowlabel_consistency =1 ; net->ipv6.sysctl.auto_flowlabels =0 ; + net->ipv6.sysctl.idgen_retries =3 ; + net->ipv6.sysctl.idgen_delay =1 *HZ ;atomic_set (&net->ipv6.fib6_sernum,1 ); err =ipv6_init_mibs (net);
net/ipv6/sysctl_net_ipv6.c +16 -0
@@ -54,6 +54,20 @@ static struct ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "idgen_retries", + .data = &init_net.ipv6.sysctl.idgen_retries, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "idgen_delay", + .data = &init_net.ipv6.sysctl.idgen_delay, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, { } };
@@ -93,6 +107,8 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) ipv6_table[2 ].data = &net->ipv6.sysctl.flowlabel_consistency; ipv6_table[3 ].data = &net->ipv6.sysctl.auto_flowlabels; ipv6_table[4 ].data = &net->ipv6.sysctl.fwmark_reflect; + ipv6_table[5 ].data = &net->ipv6.sysctl.idgen_retries; + ipv6_table[6 ].data = &net->ipv6.sysctl.idgen_delay; ipv6_route_table =ipv6_route_sysctl_init (net);if (!ipv6_route_table)
Signature · 1 line
2.1.0
PATCH v2 8/8 ipv6: add documentation for stable_secret, idgen_delay and idgen_retries knobs
In reply to Hannes Frederic Sowa--- Documentation/networking/ip-sysctl.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
Documentation/networking/ip-sysctl.txt +25 -0
@@ -1220,6 +1220,17 @@ anycast_src_echo_reply - BOOLEAN FALSE: disabled Default: FALSE +idgen_delay - INTEGER + Controls the delay in seconds after which time to retry + privacy stable address generation if a DAD conflict is + detected. + Default: 1 (as specified in RFC7217) + +idgen_retries - INTEGER + Controls the number of retries to generate a stable privacy + address if a DAD conflict is detected. + Default: 3 (as specified in RFC7217) + mld_qrv - INTEGER Controls the MLD query robustness variable (see RFC3810 9.1). Default: 2 (as specified by RFC3810 9.1)
@@ -1540,6 +1551,20 @@ use_optimistic - BOOLEAN 0: disabled (default) 1: enabled +stable_secret - IPv6 address + This IPv6 address will be used as a secret to generate IPv6 + addresses for link-local addresses and autoconfigured + ones. All addresses generated after setting this secret will + be stable privacy ones by default. This can be changed via the + addrgenmode ip-link. conf/default/stable_secret is used as the + secret for the namespace, the interface specific ones can + overwrite that. Writes to conf/all/stable_secret are refused. + + It is recommended to generate this secret during installation + of a system and keep it stable after that. + + By default the stable secret is unset. + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets.
Signature · 1 line
2.1.0
From: Hannes Frederic Sowa <[email protected]>
Date: Mon, 23 Mar 2015 23:35:58 +0100
Quoted 5 lines
this is an implementation of basic support for RFC7217 stable privacy addresses. Please review and consider for net-next.
v2:
* Correct references to RFC 7212 -> RFC 7217 in documentation patch (thanks, Eric!)
Applied, thanks!