Index: net/base/network_change_notifier_netlink_linux.cc |
diff --git a/net/base/network_change_notifier_netlink_linux.cc b/net/base/network_change_notifier_netlink_linux.cc |
index 5f71f45a96d217562ad99383b5578cf1eba9b196..493e17ae2c8eb8ac8d7a1d101eedbbe4d9b1f65e 100644 |
--- a/net/base/network_change_notifier_netlink_linux.cc |
+++ b/net/base/network_change_notifier_netlink_linux.cc |
@@ -26,6 +26,35 @@ bool SetNonBlocking(int fd) { |
return fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0 ? true : false; |
} |
+bool IsIPv6Update(const struct nlmsghdr* netlink_message_header) { |
+ const struct ifaddrmsg* address_message = |
+ reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header)); |
+ return address_message->ifa_family == AF_INET6; |
+} |
+ |
+bool IsDuplicateIPv6AddressUpdate( |
+ const struct nlmsghdr* netlink_message_header) { |
+ const struct ifaddrmsg* address_message = |
+ reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header)); |
+ int address_message_length = IFA_PAYLOAD(netlink_message_header); |
+ const struct rtattr* route_attribute = |
+ reinterpret_cast<struct rtattr*>(IFA_RTA(address_message)); |
+ DCHECK_EQ(address_message->ifa_family, AF_INET6); |
+ |
+ // Look for a cacheinfo attribute, and ignore new address broadcasts |
+ // where the updated time stamp is newer than the created time stamp. |
+ while (RTA_OK(route_attribute, address_message_length)) { |
+ if (route_attribute->rta_type == IFA_CACHEINFO) { |
+ struct ifa_cacheinfo* cache_info = |
+ reinterpret_cast<struct ifa_cacheinfo*>(RTA_DATA(route_attribute)); |
+ if (cache_info->cstamp != cache_info->tstamp) |
+ return true; |
+ } |
+ route_attribute = RTA_NEXT(route_attribute, address_message_length); |
+ } |
+ return false; |
+} |
+ |
} // namespace |
int InitializeNetlinkSocket() { |
@@ -46,7 +75,8 @@ int InitializeNetlinkSocket() { |
memset(&local_addr, 0, sizeof(local_addr)); |
local_addr.nl_family = AF_NETLINK; |
local_addr.nl_pid = getpid(); |
- local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_NOTIFY; |
+ local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | |
+ RTMGRP_NOTIFY; |
int ret = bind(sock, reinterpret_cast<struct sockaddr*>(&local_addr), |
sizeof(local_addr)); |
if (ret < 0) { |
@@ -79,6 +109,10 @@ bool HandleNetlinkMessage(char* buf, size_t len) { |
// may still end up notifying observers more than strictly necessary, but |
// if the primary interface goes down and back up, then this is necessary. |
case RTM_NEWADDR: |
+ if (IsIPv6Update(netlink_message_header) && |
+ IsDuplicateIPv6AddressUpdate(netlink_message_header)) |
+ return false; |
+ return true; |
case RTM_DELADDR: |
return true; |
case RTM_NEWLINK: |