Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: net/base/network_change_notifier_netlink_linux.cc

Issue 2881027: [Linux] Listen to and correctly handle IPv6 address change announcements. (Closed)
Patch Set: rebase Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698