Line 0
Link Here
|
|
|
1 |
--- net/base/network_interfaces_freebsd.cc.orig 2017-07-04 23:05:54.591928000 +0200 |
2 |
+++ net/base/network_interfaces_freebsd.cc 2017-07-04 23:07:28.844964000 +0200 |
3 |
@@ -0,0 +1,239 @@ |
4 |
+// Copyright (c) 2014 The Chromium Authors. All rights reserved. |
5 |
+// Use of this source code is governed by a BSD-style license that can be |
6 |
+// found in the LICENSE file. |
7 |
+ |
8 |
+#include "net/base/network_interfaces_freebsd.h" |
9 |
+ |
10 |
+#include <ifaddrs.h> |
11 |
+#include <net/if.h> |
12 |
+#include <netinet/in.h> |
13 |
+#include <sys/types.h> |
14 |
+#include <net/if_media.h> |
15 |
+#include <netinet/in_var.h> |
16 |
+#include <netinet6/in6_var.h> |
17 |
+#include <sys/ioctl.h> |
18 |
+ |
19 |
+#include <memory> |
20 |
+#include <set> |
21 |
+ |
22 |
+#include "base/files/file_path.h" |
23 |
+#include "base/logging.h" |
24 |
+#include "base/strings/string_number_conversions.h" |
25 |
+#include "base/strings/string_tokenizer.h" |
26 |
+#include "base/strings/string_util.h" |
27 |
+#include "base/threading/thread_restrictions.h" |
28 |
+#include "net/base/escape.h" |
29 |
+#include "net/base/ip_endpoint.h" |
30 |
+#include "net/base/net_errors.h" |
31 |
+#include "net/base/network_interfaces_posix.h" |
32 |
+#include "url/gurl.h" |
33 |
+ |
34 |
+namespace net { |
35 |
+ |
36 |
+namespace { |
37 |
+ |
38 |
+// FreeBSD implementation of IPAttributesGetterFreeBSD which calls ioctl on socket to |
39 |
+// retrieve IP attributes. |
40 |
+class IPAttributesGetterFreeBSDImpl : public internal::IPAttributesGetterFreeBSD { |
41 |
+ public: |
42 |
+ IPAttributesGetterFreeBSDImpl(); |
43 |
+ ~IPAttributesGetterFreeBSDImpl() override; |
44 |
+ bool IsInitialized() const override; |
45 |
+ bool GetIPAttributes(const char* ifname, |
46 |
+ const sockaddr* sock_addr, |
47 |
+ int* native_attributes) override; |
48 |
+ |
49 |
+ private: |
50 |
+ int ioctl_socket_; |
51 |
+}; |
52 |
+ |
53 |
+IPAttributesGetterFreeBSDImpl::IPAttributesGetterFreeBSDImpl() |
54 |
+ : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) { |
55 |
+ DCHECK_GE(ioctl_socket_, 0); |
56 |
+} |
57 |
+ |
58 |
+bool IPAttributesGetterFreeBSDImpl::IsInitialized() const { |
59 |
+ return ioctl_socket_ >= 0; |
60 |
+} |
61 |
+ |
62 |
+IPAttributesGetterFreeBSDImpl::~IPAttributesGetterFreeBSDImpl() { |
63 |
+ if (ioctl_socket_ >= 0) { |
64 |
+ close(ioctl_socket_); |
65 |
+ } |
66 |
+} |
67 |
+ |
68 |
+bool IPAttributesGetterFreeBSDImpl::GetIPAttributes(const char* ifname, |
69 |
+ const sockaddr* sock_addr, |
70 |
+ int* native_attributes) { |
71 |
+ struct in6_ifreq ifr = {}; |
72 |
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); |
73 |
+ memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len); |
74 |
+ int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr); |
75 |
+ if (rv >= 0) { |
76 |
+ *native_attributes = ifr.ifr_ifru.ifru_flags; |
77 |
+ } |
78 |
+ return (rv >= 0); |
79 |
+} |
80 |
+ |
81 |
+// When returning true, the platform native IPv6 address attributes were |
82 |
+// successfully converted to net IP address attributes. Otherwise, returning |
83 |
+// false and the caller should drop the IP address which can't be used by the |
84 |
+// application layer. |
85 |
+bool TryConvertNativeToNetIPAttributes(int native_attributes, |
86 |
+ int* net_attributes) { |
87 |
+ // For FreeBSD, we disallow addresses with attributes IN6_IFF_ANYCASE, |
88 |
+ // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are |
89 |
+ // still progressing through duplicated address detection (DAD) or are not |
90 |
+ // suitable to be used in an one-to-one communication and shouldn't be used |
91 |
+ // by the application layer. |
92 |
+ if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED | |
93 |
+ IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) { |
94 |
+ return false; |
95 |
+ } |
96 |
+ |
97 |
+ if (native_attributes & IN6_IFF_DEPRECATED) { |
98 |
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED; |
99 |
+ } |
100 |
+ |
101 |
+ return true; |
102 |
+} |
103 |
+ |
104 |
+NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType( |
105 |
+ int addr_family, |
106 |
+ const std::string& interface_name) { |
107 |
+ NetworkChangeNotifier::ConnectionType type = |
108 |
+ NetworkChangeNotifier::CONNECTION_UNKNOWN; |
109 |
+ |
110 |
+ struct ifmediareq ifmr = {}; |
111 |
+ strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1); |
112 |
+ |
113 |
+ int s = socket(addr_family, SOCK_DGRAM, 0); |
114 |
+ if (s == -1) { |
115 |
+ return type; |
116 |
+ } |
117 |
+ |
118 |
+ if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) { |
119 |
+ if (ifmr.ifm_current & IFM_IEEE80211) { |
120 |
+ type = NetworkChangeNotifier::CONNECTION_WIFI; |
121 |
+ } else if (ifmr.ifm_current & IFM_ETHER) { |
122 |
+ type = NetworkChangeNotifier::CONNECTION_ETHERNET; |
123 |
+ } |
124 |
+ } |
125 |
+ close(s); |
126 |
+ return type; |
127 |
+} |
128 |
+ |
129 |
+} // namespace |
130 |
+ |
131 |
+namespace internal { |
132 |
+ |
133 |
+bool GetNetworkListImpl(NetworkInterfaceList* networks, |
134 |
+ int policy, |
135 |
+ const ifaddrs* interfaces, |
136 |
+ IPAttributesGetterFreeBSD* ip_attributes_getter) { |
137 |
+ // Enumerate the addresses assigned to network interfaces which are up. |
138 |
+ for (const ifaddrs* interface = interfaces; interface != NULL; |
139 |
+ interface = interface->ifa_next) { |
140 |
+ // Skip loopback interfaces, and ones which are down. |
141 |
+ if (!(IFF_RUNNING & interface->ifa_flags)) |
142 |
+ continue; |
143 |
+ if (IFF_LOOPBACK & interface->ifa_flags) |
144 |
+ continue; |
145 |
+ // Skip interfaces with no address configured. |
146 |
+ struct sockaddr* addr = interface->ifa_addr; |
147 |
+ if (!addr) |
148 |
+ continue; |
149 |
+ |
150 |
+ // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses |
151 |
+ // configured on non-loopback interfaces. |
152 |
+ if (IsLoopbackOrUnspecifiedAddress(addr)) |
153 |
+ continue; |
154 |
+ |
155 |
+ const std::string& name = interface->ifa_name; |
156 |
+ // Filter out VMware interfaces, typically named vmnet1 and vmnet8. |
157 |
+ if (ShouldIgnoreInterface(name, policy)) { |
158 |
+ continue; |
159 |
+ } |
160 |
+ |
161 |
+ NetworkChangeNotifier::ConnectionType connection_type = |
162 |
+ NetworkChangeNotifier::CONNECTION_UNKNOWN; |
163 |
+ |
164 |
+ int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; |
165 |
+ |
166 |
+ // Retrieve native ip attributes and convert to net version if a getter is |
167 |
+ // given. |
168 |
+ if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) { |
169 |
+ int native_attributes = 0; |
170 |
+ if (addr->sa_family == AF_INET6 && |
171 |
+ ip_attributes_getter->GetIPAttributes( |
172 |
+ interface->ifa_name, interface->ifa_addr, &native_attributes)) { |
173 |
+ if (!TryConvertNativeToNetIPAttributes(native_attributes, |
174 |
+ &ip_attributes)) { |
175 |
+ continue; |
176 |
+ } |
177 |
+ } |
178 |
+ } |
179 |
+ |
180 |
+ connection_type = GetNetworkInterfaceType(addr->sa_family, name); |
181 |
+ |
182 |
+ IPEndPoint address; |
183 |
+ |
184 |
+ int addr_size = 0; |
185 |
+ if (addr->sa_family == AF_INET6) { |
186 |
+ addr_size = sizeof(sockaddr_in6); |
187 |
+ } else if (addr->sa_family == AF_INET) { |
188 |
+ addr_size = sizeof(sockaddr_in); |
189 |
+ } |
190 |
+ |
191 |
+ if (address.FromSockAddr(addr, addr_size)) { |
192 |
+ uint8_t prefix_length = 0; |
193 |
+ if (interface->ifa_netmask) { |
194 |
+ // If not otherwise set, assume the same sa_family as ifa_addr. |
195 |
+ if (interface->ifa_netmask->sa_family == 0) { |
196 |
+ interface->ifa_netmask->sa_family = addr->sa_family; |
197 |
+ } |
198 |
+ IPEndPoint netmask; |
199 |
+ if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) { |
200 |
+ prefix_length = MaskPrefixLength(netmask.address()); |
201 |
+ } |
202 |
+ } |
203 |
+ networks->push_back(NetworkInterface( |
204 |
+ name, name, if_nametoindex(name.c_str()), connection_type, |
205 |
+ address.address(), prefix_length, ip_attributes)); |
206 |
+ } |
207 |
+ } |
208 |
+ |
209 |
+ return true; |
210 |
+} |
211 |
+ |
212 |
+} // namespace internal |
213 |
+ |
214 |
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) { |
215 |
+ if (networks == NULL) |
216 |
+ return false; |
217 |
+ |
218 |
+ // getifaddrs() may require IO operations. |
219 |
+ base::ThreadRestrictions::AssertIOAllowed(); |
220 |
+ |
221 |
+ ifaddrs* interfaces; |
222 |
+ if (getifaddrs(&interfaces) < 0) { |
223 |
+ PLOG(ERROR) << "getifaddrs"; |
224 |
+ return false; |
225 |
+ } |
226 |
+ |
227 |
+ std::unique_ptr<internal::IPAttributesGetterFreeBSD> ip_attributes_getter; |
228 |
+ |
229 |
+ ip_attributes_getter.reset(new IPAttributesGetterFreeBSDImpl()); |
230 |
+ |
231 |
+ bool result = internal::GetNetworkListImpl(networks, policy, interfaces, |
232 |
+ ip_attributes_getter.get()); |
233 |
+ freeifaddrs(interfaces); |
234 |
+ return result; |
235 |
+} |
236 |
+ |
237 |
+std::string GetWifiSSID() { |
238 |
+ NOTIMPLEMENTED(); |
239 |
+ return ""; |
240 |
+} |
241 |
+ |
242 |
+} // namespace net |