aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-12-06 03:45:22 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-06 16:34:43 -0500
commit53bd674915379d91e0e505332c89741b34eab05c (patch)
tree5543216230b9a84c7d89c068a79067ec5f244488
parent479840ffdbe4242e8a25349218c8e0859223aa35 (diff)
ipv6 addrconf: introduce IFA_F_MANAGETEMPADDR to tell kernel to manage temporary addresses
Creating an address with this flag set will result in kernel taking care of temporary addresses in the same way as if the address was created by kernel itself (after RA receive). This allows userspace applications implementing the autoconfiguration (NetworkManager for example) to implement ipv6 addresses privacy. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Thomas Haller <thaller@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_addr.h1
-rw-r--r--net/ipv6/addrconf.c171
2 files changed, 100 insertions, 72 deletions
diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
index 8ab0c2cc9b73..cfed10be7529 100644
--- a/include/uapi/linux/if_addr.h
+++ b/include/uapi/linux/if_addr.h
@@ -48,6 +48,7 @@ enum {
48#define IFA_F_DEPRECATED 0x20 48#define IFA_F_DEPRECATED 0x20
49#define IFA_F_TENTATIVE 0x40 49#define IFA_F_TENTATIVE 0x40
50#define IFA_F_PERMANENT 0x80 50#define IFA_F_PERMANENT 0x80
51#define IFA_F_MANAGETEMPADDR 0x100
51 52
52struct ifa_cacheinfo { 53struct ifa_cacheinfo {
53 __u32 ifa_prefered; 54 __u32 ifa_prefered;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 334a7e114e1d..5087cc5cb810 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1024,7 +1024,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
1024 u32 addr_flags; 1024 u32 addr_flags;
1025 unsigned long now = jiffies; 1025 unsigned long now = jiffies;
1026 1026
1027 write_lock(&idev->lock); 1027 write_lock_bh(&idev->lock);
1028 if (ift) { 1028 if (ift) {
1029 spin_lock_bh(&ift->lock); 1029 spin_lock_bh(&ift->lock);
1030 memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); 1030 memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);
@@ -1036,7 +1036,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
1036retry: 1036retry:
1037 in6_dev_hold(idev); 1037 in6_dev_hold(idev);
1038 if (idev->cnf.use_tempaddr <= 0) { 1038 if (idev->cnf.use_tempaddr <= 0) {
1039 write_unlock(&idev->lock); 1039 write_unlock_bh(&idev->lock);
1040 pr_info("%s: use_tempaddr is disabled\n", __func__); 1040 pr_info("%s: use_tempaddr is disabled\n", __func__);
1041 in6_dev_put(idev); 1041 in6_dev_put(idev);
1042 ret = -1; 1042 ret = -1;
@@ -1046,7 +1046,7 @@ retry:
1046 if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { 1046 if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
1047 idev->cnf.use_tempaddr = -1; /*XXX*/ 1047 idev->cnf.use_tempaddr = -1; /*XXX*/
1048 spin_unlock_bh(&ifp->lock); 1048 spin_unlock_bh(&ifp->lock);
1049 write_unlock(&idev->lock); 1049 write_unlock_bh(&idev->lock);
1050 pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", 1050 pr_warn("%s: regeneration time exceeded - disabled temporary address support\n",
1051 __func__); 1051 __func__);
1052 in6_dev_put(idev); 1052 in6_dev_put(idev);
@@ -1072,7 +1072,7 @@ retry:
1072 regen_advance = idev->cnf.regen_max_retry * 1072 regen_advance = idev->cnf.regen_max_retry *
1073 idev->cnf.dad_transmits * 1073 idev->cnf.dad_transmits *
1074 idev->nd_parms->retrans_time / HZ; 1074 idev->nd_parms->retrans_time / HZ;
1075 write_unlock(&idev->lock); 1075 write_unlock_bh(&idev->lock);
1076 1076
1077 /* A temporary address is created only if this calculated Preferred 1077 /* A temporary address is created only if this calculated Preferred
1078 * Lifetime is greater than REGEN_ADVANCE time units. In particular, 1078 * Lifetime is greater than REGEN_ADVANCE time units. In particular,
@@ -1099,7 +1099,7 @@ retry:
1099 in6_dev_put(idev); 1099 in6_dev_put(idev);
1100 pr_info("%s: retry temporary address regeneration\n", __func__); 1100 pr_info("%s: retry temporary address regeneration\n", __func__);
1101 tmpaddr = &addr; 1101 tmpaddr = &addr;
1102 write_lock(&idev->lock); 1102 write_lock_bh(&idev->lock);
1103 goto retry; 1103 goto retry;
1104 } 1104 }
1105 1105
@@ -2016,6 +2016,73 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
2016 return idev; 2016 return idev;
2017} 2017}
2018 2018
2019static void manage_tempaddrs(struct inet6_dev *idev,
2020 struct inet6_ifaddr *ifp,
2021 __u32 valid_lft, __u32 prefered_lft,
2022 bool create, unsigned long now)
2023{
2024 u32 flags;
2025 struct inet6_ifaddr *ift;
2026
2027 read_lock_bh(&idev->lock);
2028 /* update all temporary addresses in the list */
2029 list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) {
2030 int age, max_valid, max_prefered;
2031
2032 if (ifp != ift->ifpub)
2033 continue;
2034
2035 /* RFC 4941 section 3.3:
2036 * If a received option will extend the lifetime of a public
2037 * address, the lifetimes of temporary addresses should
2038 * be extended, subject to the overall constraint that no
2039 * temporary addresses should ever remain "valid" or "preferred"
2040 * for a time longer than (TEMP_VALID_LIFETIME) or
2041 * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively.
2042 */
2043 age = (now - ift->cstamp) / HZ;
2044 max_valid = idev->cnf.temp_valid_lft - age;
2045 if (max_valid < 0)
2046 max_valid = 0;
2047
2048 max_prefered = idev->cnf.temp_prefered_lft -
2049 idev->cnf.max_desync_factor - age;
2050 if (max_prefered < 0)
2051 max_prefered = 0;
2052
2053 if (valid_lft > max_valid)
2054 valid_lft = max_valid;
2055
2056 if (prefered_lft > max_prefered)
2057 prefered_lft = max_prefered;
2058
2059 spin_lock(&ift->lock);
2060 flags = ift->flags;
2061 ift->valid_lft = valid_lft;
2062 ift->prefered_lft = prefered_lft;
2063 ift->tstamp = now;
2064 if (prefered_lft > 0)
2065 ift->flags &= ~IFA_F_DEPRECATED;
2066
2067 spin_unlock(&ift->lock);
2068 if (!(flags&IFA_F_TENTATIVE))
2069 ipv6_ifa_notify(0, ift);
2070 }
2071
2072 if ((create || list_empty(&idev->tempaddr_list)) &&
2073 idev->cnf.use_tempaddr > 0) {
2074 /* When a new public address is created as described
2075 * in [ADDRCONF], also create a new temporary address.
2076 * Also create a temporary address if it's enabled but
2077 * no temporary address currently exists.
2078 */
2079 read_unlock_bh(&idev->lock);
2080 ipv6_create_tempaddr(ifp, NULL);
2081 } else {
2082 read_unlock_bh(&idev->lock);
2083 }
2084}
2085
2019void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) 2086void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
2020{ 2087{
2021 struct prefix_info *pinfo; 2088 struct prefix_info *pinfo;
@@ -2170,6 +2237,7 @@ ok:
2170 return; 2237 return;
2171 } 2238 }
2172 2239
2240 ifp->flags |= IFA_F_MANAGETEMPADDR;
2173 update_lft = 0; 2241 update_lft = 0;
2174 create = 1; 2242 create = 1;
2175 ifp->cstamp = jiffies; 2243 ifp->cstamp = jiffies;
@@ -2180,7 +2248,6 @@ ok:
2180 if (ifp) { 2248 if (ifp) {
2181 u32 flags; 2249 u32 flags;
2182 unsigned long now; 2250 unsigned long now;
2183 struct inet6_ifaddr *ift;
2184 u32 stored_lft; 2251 u32 stored_lft;
2185 2252
2186 /* update lifetime (RFC2462 5.5.3 e) */ 2253 /* update lifetime (RFC2462 5.5.3 e) */
@@ -2221,70 +2288,8 @@ ok:
2221 } else 2288 } else
2222 spin_unlock(&ifp->lock); 2289 spin_unlock(&ifp->lock);
2223 2290
2224 read_lock_bh(&in6_dev->lock); 2291 manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft,
2225 /* update all temporary addresses in the list */ 2292 create, now);
2226 list_for_each_entry(ift, &in6_dev->tempaddr_list,
2227 tmp_list) {
2228 int age, max_valid, max_prefered;
2229
2230 if (ifp != ift->ifpub)
2231 continue;
2232
2233 /*
2234 * RFC 4941 section 3.3:
2235 * If a received option will extend the lifetime
2236 * of a public address, the lifetimes of
2237 * temporary addresses should be extended,
2238 * subject to the overall constraint that no
2239 * temporary addresses should ever remain
2240 * "valid" or "preferred" for a time longer than
2241 * (TEMP_VALID_LIFETIME) or
2242 * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR),
2243 * respectively.
2244 */
2245 age = (now - ift->cstamp) / HZ;
2246 max_valid = in6_dev->cnf.temp_valid_lft - age;
2247 if (max_valid < 0)
2248 max_valid = 0;
2249
2250 max_prefered = in6_dev->cnf.temp_prefered_lft -
2251 in6_dev->cnf.max_desync_factor -
2252 age;
2253 if (max_prefered < 0)
2254 max_prefered = 0;
2255
2256 if (valid_lft > max_valid)
2257 valid_lft = max_valid;
2258
2259 if (prefered_lft > max_prefered)
2260 prefered_lft = max_prefered;
2261
2262 spin_lock(&ift->lock);
2263 flags = ift->flags;
2264 ift->valid_lft = valid_lft;
2265 ift->prefered_lft = prefered_lft;
2266 ift->tstamp = now;
2267 if (prefered_lft > 0)
2268 ift->flags &= ~IFA_F_DEPRECATED;
2269
2270 spin_unlock(&ift->lock);
2271 if (!(flags&IFA_F_TENTATIVE))
2272 ipv6_ifa_notify(0, ift);
2273 }
2274
2275 if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) {
2276 /*
2277 * When a new public address is created as
2278 * described in [ADDRCONF], also create a new
2279 * temporary address. Also create a temporary
2280 * address if it's enabled but no temporary
2281 * address currently exists.
2282 */
2283 read_unlock_bh(&in6_dev->lock);
2284 ipv6_create_tempaddr(ifp, NULL);
2285 } else {
2286 read_unlock_bh(&in6_dev->lock);
2287 }
2288 2293
2289 in6_ifa_put(ifp); 2294 in6_ifa_put(ifp);
2290 addrconf_verify(0); 2295 addrconf_verify(0);
@@ -2386,6 +2391,9 @@ static int inet6_addr_add(struct net *net, int ifindex,
2386 if (!valid_lft || prefered_lft > valid_lft) 2391 if (!valid_lft || prefered_lft > valid_lft)
2387 return -EINVAL; 2392 return -EINVAL;
2388 2393
2394 if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64)
2395 return -EINVAL;
2396
2389 dev = __dev_get_by_index(net, ifindex); 2397 dev = __dev_get_by_index(net, ifindex);
2390 if (!dev) 2398 if (!dev)
2391 return -ENODEV; 2399 return -ENODEV;
@@ -2426,6 +2434,9 @@ static int inet6_addr_add(struct net *net, int ifindex,
2426 * manually configured addresses 2434 * manually configured addresses
2427 */ 2435 */
2428 addrconf_dad_start(ifp); 2436 addrconf_dad_start(ifp);
2437 if (ifa_flags & IFA_F_MANAGETEMPADDR)
2438 manage_tempaddrs(idev, ifp, valid_lft, prefered_lft,
2439 true, jiffies);
2429 in6_ifa_put(ifp); 2440 in6_ifa_put(ifp);
2430 addrconf_verify(0); 2441 addrconf_verify(0);
2431 return 0; 2442 return 0;
@@ -3603,10 +3614,15 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
3603 u32 flags; 3614 u32 flags;
3604 clock_t expires; 3615 clock_t expires;
3605 unsigned long timeout; 3616 unsigned long timeout;
3617 bool was_managetempaddr;
3606 3618
3607 if (!valid_lft || (prefered_lft > valid_lft)) 3619 if (!valid_lft || (prefered_lft > valid_lft))
3608 return -EINVAL; 3620 return -EINVAL;
3609 3621
3622 if (ifa_flags & IFA_F_MANAGETEMPADDR &&
3623 (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64))
3624 return -EINVAL;
3625
3610 timeout = addrconf_timeout_fixup(valid_lft, HZ); 3626 timeout = addrconf_timeout_fixup(valid_lft, HZ);
3611 if (addrconf_finite_timeout(timeout)) { 3627 if (addrconf_finite_timeout(timeout)) {
3612 expires = jiffies_to_clock_t(timeout * HZ); 3628 expires = jiffies_to_clock_t(timeout * HZ);
@@ -3626,7 +3642,10 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
3626 } 3642 }
3627 3643
3628 spin_lock_bh(&ifp->lock); 3644 spin_lock_bh(&ifp->lock);
3629 ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; 3645 was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
3646 ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD |
3647 IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR);
3648 ifp->flags |= ifa_flags;
3630 ifp->tstamp = jiffies; 3649 ifp->tstamp = jiffies;
3631 ifp->valid_lft = valid_lft; 3650 ifp->valid_lft = valid_lft;
3632 ifp->prefered_lft = prefered_lft; 3651 ifp->prefered_lft = prefered_lft;
@@ -3637,6 +3656,14 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
3637 3656
3638 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, 3657 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
3639 expires, flags); 3658 expires, flags);
3659
3660 if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) {
3661 if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR))
3662 valid_lft = prefered_lft = 0;
3663 manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft,
3664 !was_managetempaddr, jiffies);
3665 }
3666
3640 addrconf_verify(0); 3667 addrconf_verify(0);
3641 3668
3642 return 0; 3669 return 0;
@@ -3682,7 +3709,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3682 ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; 3709 ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
3683 3710
3684 /* We ignore other flags so far. */ 3711 /* We ignore other flags so far. */
3685 ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS; 3712 ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR;
3686 3713
3687 ifa = ipv6_get_ifaddr(net, pfx, dev, 1); 3714 ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
3688 if (ifa == NULL) { 3715 if (ifa == NULL) {