OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/network_change_notifier_netlink_linux.h" | 5 #include "net/base/network_change_notifier_netlink_linux.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 // socket.h is needed to define types for the linux kernel header netlink.h | 8 // socket.h is needed to define types for the linux kernel header netlink.h |
9 // so it needs to come before netlink.h. | 9 // so it needs to come before netlink.h. |
10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
11 #include <linux/netlink.h> | 11 #include <linux/netlink.h> |
12 #include <linux/rtnetlink.h> | 12 #include <linux/rtnetlink.h> |
13 #include <string.h> | 13 #include <string.h> |
14 #include <unistd.h> | 14 #include <unistd.h> |
15 | 15 |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 // Return true on success, false on failure. | 20 // Return true on success, false on failure. |
21 // Too small a function to bother putting in a library? | 21 // Too small a function to bother putting in a library? |
22 bool SetNonBlocking(int fd) { | 22 bool SetNonBlocking(int fd) { |
23 int flags = fcntl(fd, F_GETFL, 0); | 23 int flags = fcntl(fd, F_GETFL, 0); |
24 if (-1 == flags) | 24 if (-1 == flags) |
25 return false; | 25 return false; |
26 return fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0 ? true : false; | 26 return fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0 ? true : false; |
27 } | 27 } |
28 | 28 |
| 29 bool IsIPv6Update(const struct nlmsghdr* netlink_message_header) { |
| 30 const struct ifaddrmsg* address_message = |
| 31 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header)); |
| 32 return address_message->ifa_family == AF_INET6; |
| 33 } |
| 34 |
| 35 bool IsDuplicateIPv6AddressUpdate( |
| 36 const struct nlmsghdr* netlink_message_header) { |
| 37 const struct ifaddrmsg* address_message = |
| 38 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header)); |
| 39 int address_message_length = IFA_PAYLOAD(netlink_message_header); |
| 40 const struct rtattr* route_attribute = |
| 41 reinterpret_cast<struct rtattr*>(IFA_RTA(address_message)); |
| 42 DCHECK_EQ(address_message->ifa_family, AF_INET6); |
| 43 |
| 44 // Look for a cacheinfo attribute, and ignore new address broadcasts |
| 45 // where the updated time stamp is newer than the created time stamp. |
| 46 while (RTA_OK(route_attribute, address_message_length)) { |
| 47 if (route_attribute->rta_type == IFA_CACHEINFO) { |
| 48 struct ifa_cacheinfo* cache_info = |
| 49 reinterpret_cast<struct ifa_cacheinfo*>(RTA_DATA(route_attribute)); |
| 50 if (cache_info->cstamp != cache_info->tstamp) |
| 51 return true; |
| 52 } |
| 53 route_attribute = RTA_NEXT(route_attribute, address_message_length); |
| 54 } |
| 55 return false; |
| 56 } |
| 57 |
29 } // namespace | 58 } // namespace |
30 | 59 |
31 int InitializeNetlinkSocket() { | 60 int InitializeNetlinkSocket() { |
32 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | 61 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
33 if (sock < 0) { | 62 if (sock < 0) { |
34 PLOG(ERROR) << "Error creating netlink socket"; | 63 PLOG(ERROR) << "Error creating netlink socket"; |
35 return -1; | 64 return -1; |
36 } | 65 } |
37 | 66 |
38 if (!SetNonBlocking(sock)) { | 67 if (!SetNonBlocking(sock)) { |
39 PLOG(ERROR) << "Failed to set netlink socket to non-blocking mode."; | 68 PLOG(ERROR) << "Failed to set netlink socket to non-blocking mode."; |
40 if (close(sock) != 0) | 69 if (close(sock) != 0) |
41 PLOG(ERROR) << "Failed to close socket"; | 70 PLOG(ERROR) << "Failed to close socket"; |
42 return -1; | 71 return -1; |
43 } | 72 } |
44 | 73 |
45 struct sockaddr_nl local_addr; | 74 struct sockaddr_nl local_addr; |
46 memset(&local_addr, 0, sizeof(local_addr)); | 75 memset(&local_addr, 0, sizeof(local_addr)); |
47 local_addr.nl_family = AF_NETLINK; | 76 local_addr.nl_family = AF_NETLINK; |
48 local_addr.nl_pid = getpid(); | 77 local_addr.nl_pid = getpid(); |
49 local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_NOTIFY; | 78 local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | |
| 79 RTMGRP_NOTIFY; |
50 int ret = bind(sock, reinterpret_cast<struct sockaddr*>(&local_addr), | 80 int ret = bind(sock, reinterpret_cast<struct sockaddr*>(&local_addr), |
51 sizeof(local_addr)); | 81 sizeof(local_addr)); |
52 if (ret < 0) { | 82 if (ret < 0) { |
53 PLOG(ERROR) << "Error binding netlink socket"; | 83 PLOG(ERROR) << "Error binding netlink socket"; |
54 if (close(sock) != 0) | 84 if (close(sock) != 0) |
55 PLOG(ERROR) << "Failed to close socket"; | 85 PLOG(ERROR) << "Failed to close socket"; |
56 return -1; | 86 return -1; |
57 } | 87 } |
58 | 88 |
59 return sock; | 89 return sock; |
(...skipping 12 matching lines...) Expand all Loading... |
72 << "This is a monitoring netlink socket. It should never be done."; | 102 << "This is a monitoring netlink socket. It should never be done."; |
73 return false; | 103 return false; |
74 case NLMSG_ERROR: | 104 case NLMSG_ERROR: |
75 LOG(ERROR) << "Unexpected netlink error."; | 105 LOG(ERROR) << "Unexpected netlink error."; |
76 return false; | 106 return false; |
77 // During IP address changes, we will see all these messages. Only fire | 107 // During IP address changes, we will see all these messages. Only fire |
78 // the notification when we get a new address or remove an address. We | 108 // the notification when we get a new address or remove an address. We |
79 // may still end up notifying observers more than strictly necessary, but | 109 // may still end up notifying observers more than strictly necessary, but |
80 // if the primary interface goes down and back up, then this is necessary. | 110 // if the primary interface goes down and back up, then this is necessary. |
81 case RTM_NEWADDR: | 111 case RTM_NEWADDR: |
| 112 if (IsIPv6Update(netlink_message_header) && |
| 113 IsDuplicateIPv6AddressUpdate(netlink_message_header)) |
| 114 return false; |
| 115 return true; |
82 case RTM_DELADDR: | 116 case RTM_DELADDR: |
83 return true; | 117 return true; |
84 case RTM_NEWLINK: | 118 case RTM_NEWLINK: |
85 case RTM_DELLINK: | 119 case RTM_DELLINK: |
86 return false; | 120 return false; |
87 default: | 121 default: |
88 LOG(DFATAL) << "Received unexpected netlink message type: " | 122 LOG(DFATAL) << "Received unexpected netlink message type: " |
89 << netlink_message_type; | 123 << netlink_message_type; |
90 return false; | 124 return false; |
91 } | 125 } |
92 } | 126 } |
93 | 127 |
94 return false; | 128 return false; |
95 } | 129 } |
OLD | NEW |