1 /*
2  *  Copyright 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "sdk/android/src/jni/android_network_monitor.h"
12 
13 #include <dlfcn.h>
14 #ifndef RTLD_NOLOAD
15 // This was added in Lollipop to dlfcn.h
16 #define RTLD_NOLOAD 4
17 #endif
18 
19 #include "rtc_base/bind.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/ip_address.h"
22 #include "rtc_base/logging.h"
23 #include "rtc_base/strings/string_builder.h"
24 #include "sdk/android/generated_base_jni/NetworkMonitorAutoDetect_jni.h"
25 #include "sdk/android/generated_base_jni/NetworkMonitor_jni.h"
26 #include "sdk/android/native_api/jni/java_types.h"
27 #include "sdk/android/src/jni/jni_helpers.h"
28 #include "system_wrappers/include/field_trial.h"
29 
30 namespace webrtc {
31 namespace jni {
32 
33 enum AndroidSdkVersion {
34   SDK_VERSION_LOLLIPOP = 21,
35   SDK_VERSION_MARSHMALLOW = 23
36 };
37 
GetNetworkTypeFromJava(JNIEnv * jni,const JavaRef<jobject> & j_network_type)38 static NetworkType GetNetworkTypeFromJava(
39     JNIEnv* jni,
40     const JavaRef<jobject>& j_network_type) {
41   std::string enum_name = GetJavaEnumName(jni, j_network_type);
42   if (enum_name == "CONNECTION_UNKNOWN") {
43     return NetworkType::NETWORK_UNKNOWN;
44   }
45   if (enum_name == "CONNECTION_ETHERNET") {
46     return NetworkType::NETWORK_ETHERNET;
47   }
48   if (enum_name == "CONNECTION_WIFI") {
49     return NetworkType::NETWORK_WIFI;
50   }
51   if (enum_name == "CONNECTION_4G") {
52     return NetworkType::NETWORK_4G;
53   }
54   if (enum_name == "CONNECTION_3G") {
55     return NetworkType::NETWORK_3G;
56   }
57   if (enum_name == "CONNECTION_2G") {
58     return NetworkType::NETWORK_2G;
59   }
60   if (enum_name == "CONNECTION_UNKNOWN_CELLULAR") {
61     return NetworkType::NETWORK_UNKNOWN_CELLULAR;
62   }
63   if (enum_name == "CONNECTION_BLUETOOTH") {
64     return NetworkType::NETWORK_BLUETOOTH;
65   }
66   if (enum_name == "CONNECTION_VPN") {
67     return NetworkType::NETWORK_VPN;
68   }
69   if (enum_name == "CONNECTION_NONE") {
70     return NetworkType::NETWORK_NONE;
71   }
72   RTC_NOTREACHED();
73   return NetworkType::NETWORK_UNKNOWN;
74 }
75 
AdapterTypeFromNetworkType(NetworkType network_type)76 static rtc::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) {
77   switch (network_type) {
78     case NETWORK_UNKNOWN:
79       return rtc::ADAPTER_TYPE_UNKNOWN;
80     case NETWORK_ETHERNET:
81       return rtc::ADAPTER_TYPE_ETHERNET;
82     case NETWORK_WIFI:
83       return rtc::ADAPTER_TYPE_WIFI;
84     case NETWORK_4G:
85     case NETWORK_3G:
86     case NETWORK_2G:
87     case NETWORK_UNKNOWN_CELLULAR:
88       return rtc::ADAPTER_TYPE_CELLULAR;
89     case NETWORK_VPN:
90     case NETWORK_BLUETOOTH:
91       // There is no corresponding mapping for bluetooth networks.
92       // Map it to VPN for now.
93       return rtc::ADAPTER_TYPE_VPN;
94     default:
95       RTC_NOTREACHED() << "Invalid network type " << network_type;
96       return rtc::ADAPTER_TYPE_UNKNOWN;
97   }
98 }
99 
JavaToNativeIpAddress(JNIEnv * jni,const JavaRef<jobject> & j_ip_address)100 static rtc::IPAddress JavaToNativeIpAddress(
101     JNIEnv* jni,
102     const JavaRef<jobject>& j_ip_address) {
103   std::vector<int8_t> address =
104       JavaToNativeByteArray(jni, Java_IPAddress_getAddress(jni, j_ip_address));
105   size_t address_length = address.size();
106   if (address_length == 4) {
107     // IP4
108     struct in_addr ip4_addr;
109     memcpy(&ip4_addr.s_addr, address.data(), 4);
110     return rtc::IPAddress(ip4_addr);
111   }
112   // IP6
113   RTC_CHECK(address_length == 16);
114   struct in6_addr ip6_addr;
115   memcpy(ip6_addr.s6_addr, address.data(), address_length);
116   return rtc::IPAddress(ip6_addr);
117 }
118 
GetNetworkInformationFromJava(JNIEnv * jni,const JavaRef<jobject> & j_network_info)119 static NetworkInformation GetNetworkInformationFromJava(
120     JNIEnv* jni,
121     const JavaRef<jobject>& j_network_info) {
122   NetworkInformation network_info;
123   network_info.interface_name = JavaToStdString(
124       jni, Java_NetworkInformation_getName(jni, j_network_info));
125   network_info.handle = static_cast<NetworkHandle>(
126       Java_NetworkInformation_getHandle(jni, j_network_info));
127   network_info.type = GetNetworkTypeFromJava(
128       jni, Java_NetworkInformation_getConnectionType(jni, j_network_info));
129   network_info.underlying_type_for_vpn = GetNetworkTypeFromJava(
130       jni, Java_NetworkInformation_getUnderlyingConnectionTypeForVpn(
131                jni, j_network_info));
132   ScopedJavaLocalRef<jobjectArray> j_ip_addresses =
133       Java_NetworkInformation_getIpAddresses(jni, j_network_info);
134   network_info.ip_addresses = JavaToNativeVector<rtc::IPAddress>(
135       jni, j_ip_addresses, &JavaToNativeIpAddress);
136   return network_info;
137 }
138 
AddressMatch(const rtc::IPAddress & ip1,const rtc::IPAddress & ip2)139 static bool AddressMatch(const rtc::IPAddress& ip1, const rtc::IPAddress& ip2) {
140   if (ip1.family() != ip2.family()) {
141     return false;
142   }
143   if (ip1.family() == AF_INET) {
144     return ip1.ipv4_address().s_addr == ip2.ipv4_address().s_addr;
145   }
146   if (ip1.family() == AF_INET6) {
147     // The last 64-bits of an ipv6 address are temporary address and it could
148     // change over time. So we only compare the first 64-bits.
149     return memcmp(ip1.ipv6_address().s6_addr, ip2.ipv6_address().s6_addr,
150                   sizeof(in6_addr) / 2) == 0;
151   }
152   return false;
153 }
154 
155 NetworkInformation::NetworkInformation() = default;
156 
157 NetworkInformation::NetworkInformation(const NetworkInformation&) = default;
158 
159 NetworkInformation::NetworkInformation(NetworkInformation&&) = default;
160 
161 NetworkInformation::~NetworkInformation() = default;
162 
163 NetworkInformation& NetworkInformation::operator=(const NetworkInformation&) =
164     default;
165 
166 NetworkInformation& NetworkInformation::operator=(NetworkInformation&&) =
167     default;
168 
ToString() const169 std::string NetworkInformation::ToString() const {
170   rtc::StringBuilder ss;
171   ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type "
172      << type;
173   if (type == NETWORK_VPN) {
174     ss << "; underlying_type_for_vpn " << underlying_type_for_vpn;
175   }
176   ss << "]";
177   return ss.Release();
178 }
179 
AndroidNetworkMonitor(JNIEnv * env,const JavaRef<jobject> & j_application_context)180 AndroidNetworkMonitor::AndroidNetworkMonitor(
181     JNIEnv* env,
182     const JavaRef<jobject>& j_application_context)
183     : android_sdk_int_(Java_NetworkMonitor_androidSdkInt(env)),
184       j_application_context_(env, j_application_context),
185       j_network_monitor_(env, Java_NetworkMonitor_getInstance(env)) {}
186 
187 AndroidNetworkMonitor::~AndroidNetworkMonitor() = default;
188 
Start()189 void AndroidNetworkMonitor::Start() {
190   RTC_CHECK(thread_checker_.IsCurrent());
191   if (started_) {
192     return;
193   }
194   started_ = true;
195   find_network_handle_without_ipv6_temporary_part_ =
196       webrtc::field_trial::IsEnabled(
197           "WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart");
198 
199   // This is kind of magic behavior, but doing this allows the SocketServer to
200   // use this as a NetworkBinder to bind sockets on a particular network when
201   // it creates sockets.
202   worker_thread()->socketserver()->set_network_binder(this);
203 
204   JNIEnv* env = AttachCurrentThreadIfNeeded();
205   Java_NetworkMonitor_startMonitoring(
206       env, j_network_monitor_, j_application_context_, jlongFromPointer(this));
207 }
208 
Stop()209 void AndroidNetworkMonitor::Stop() {
210   RTC_CHECK(thread_checker_.IsCurrent());
211   if (!started_) {
212     return;
213   }
214   started_ = false;
215   find_network_handle_without_ipv6_temporary_part_ = false;
216 
217   // Once the network monitor stops, it will clear all network information and
218   // it won't find the network handle to bind anyway.
219   if (worker_thread()->socketserver()->network_binder() == this) {
220     worker_thread()->socketserver()->set_network_binder(nullptr);
221   }
222 
223   JNIEnv* env = AttachCurrentThreadIfNeeded();
224   Java_NetworkMonitor_stopMonitoring(env, j_network_monitor_,
225                                      jlongFromPointer(this));
226 
227   network_handle_by_address_.clear();
228   network_info_by_handle_.clear();
229 }
230 
231 // The implementation is largely taken from UDPSocketPosix::BindToNetwork in
232 // https://cs.chromium.org/chromium/src/net/udp/udp_socket_posix.cc
BindSocketToNetwork(int socket_fd,const rtc::IPAddress & address)233 rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
234     int socket_fd,
235     const rtc::IPAddress& address) {
236   RTC_CHECK(thread_checker_.IsCurrent());
237 
238   // Android prior to Lollipop didn't have support for binding sockets to
239   // networks. This may also occur if there is no connectivity manager
240   // service.
241   JNIEnv* env = AttachCurrentThreadIfNeeded();
242   const bool network_binding_supported =
243       Java_NetworkMonitor_networkBindingSupported(env, j_network_monitor_);
244   if (!network_binding_supported) {
245     RTC_LOG(LS_WARNING)
246         << "BindSocketToNetwork is not supported on this platform "
247            "(Android SDK: "
248         << android_sdk_int_ << ")";
249     return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
250   }
251 
252   absl::optional<NetworkHandle> network_handle =
253       FindNetworkHandleFromAddress(address);
254   if (!network_handle) {
255     return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
256   }
257 
258   if (*network_handle == 0 /* NETWORK_UNSPECIFIED */) {
259     return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
260   }
261 
262   int rv = 0;
263   if (android_sdk_int_ >= SDK_VERSION_MARSHMALLOW) {
264     // See declaration of android_setsocknetwork() here:
265     // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/include/android/multinetwork.h#65
266     // Function cannot be called directly as it will cause app to fail to load
267     // on pre-marshmallow devices.
268     typedef int (*MarshmallowSetNetworkForSocket)(NetworkHandle net,
269                                                   int socket);
270     static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
271     // This is not thread-safe, but we are running this only on the worker
272     // thread.
273     if (!marshmallowSetNetworkForSocket) {
274       const std::string android_native_lib_path = "libandroid.so";
275       void* lib = dlopen(android_native_lib_path.c_str(), RTLD_NOW);
276       if (lib == nullptr) {
277         RTC_LOG(LS_ERROR) << "Library " << android_native_lib_path
278                           << " not found!";
279         return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
280       }
281       marshmallowSetNetworkForSocket =
282           reinterpret_cast<MarshmallowSetNetworkForSocket>(
283               dlsym(lib, "android_setsocknetwork"));
284     }
285     if (!marshmallowSetNetworkForSocket) {
286       RTC_LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
287       return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
288     }
289     rv = marshmallowSetNetworkForSocket(*network_handle, socket_fd);
290   } else {
291     // NOTE: This relies on Android implementation details, but it won't
292     // change because Lollipop is already released.
293     typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
294     static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
295     // This is not threadsafe, but we are running this only on the worker
296     // thread.
297     if (!lollipopSetNetworkForSocket) {
298       // Android's netd client library should always be loaded in our address
299       // space as it shims libc functions like connect().
300       const std::string net_library_path = "libnetd_client.so";
301       // Use RTLD_NOW to match Android's prior loading of the library:
302       // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37
303       // Use RTLD_NOLOAD to assert that the library is already loaded and
304       // avoid doing any disk IO.
305       void* lib = dlopen(net_library_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
306       if (lib == nullptr) {
307         RTC_LOG(LS_ERROR) << "Library " << net_library_path << " not found!";
308         return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
309       }
310       lollipopSetNetworkForSocket =
311           reinterpret_cast<LollipopSetNetworkForSocket>(
312               dlsym(lib, "setNetworkForSocket"));
313     }
314     if (!lollipopSetNetworkForSocket) {
315       RTC_LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
316       return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
317     }
318     rv = lollipopSetNetworkForSocket(*network_handle, socket_fd);
319   }
320 
321   // If |network| has since disconnected, |rv| will be ENONET. Surface this as
322   // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
323   // the less descriptive ERR_FAILED.
324   if (rv == 0) {
325     return rtc::NetworkBindingResult::SUCCESS;
326   }
327   if (rv == ENONET) {
328     return rtc::NetworkBindingResult::NETWORK_CHANGED;
329   }
330   return rtc::NetworkBindingResult::FAILURE;
331 }
332 
OnNetworkConnected(const NetworkInformation & network_info)333 void AndroidNetworkMonitor::OnNetworkConnected(
334     const NetworkInformation& network_info) {
335   worker_thread()->Invoke<void>(
336       RTC_FROM_HERE, rtc::Bind(&AndroidNetworkMonitor::OnNetworkConnected_w,
337                                this, network_info));
338   // Fire SignalNetworksChanged to update the list of networks.
339   OnNetworksChanged();
340 }
341 
OnNetworkConnected_w(const NetworkInformation & network_info)342 void AndroidNetworkMonitor::OnNetworkConnected_w(
343     const NetworkInformation& network_info) {
344   RTC_LOG(LS_INFO) << "Network connected: " << network_info.ToString();
345   adapter_type_by_name_[network_info.interface_name] =
346       AdapterTypeFromNetworkType(network_info.type);
347   if (network_info.type == NETWORK_VPN) {
348     vpn_underlying_adapter_type_by_name_[network_info.interface_name] =
349         AdapterTypeFromNetworkType(network_info.underlying_type_for_vpn);
350   }
351   network_info_by_handle_[network_info.handle] = network_info;
352   for (const rtc::IPAddress& address : network_info.ip_addresses) {
353     network_handle_by_address_[address] = network_info.handle;
354   }
355 }
356 
357 absl::optional<NetworkHandle>
FindNetworkHandleFromAddress(const rtc::IPAddress & ip_address) const358 AndroidNetworkMonitor::FindNetworkHandleFromAddress(
359     const rtc::IPAddress& ip_address) const {
360   RTC_LOG(LS_INFO) << "Find network handle.";
361   if (find_network_handle_without_ipv6_temporary_part_) {
362     for (auto const& iter : network_info_by_handle_) {
363       const std::vector<rtc::IPAddress>& addresses = iter.second.ip_addresses;
364       auto address_it = std::find_if(addresses.begin(), addresses.end(),
365                                      [ip_address](rtc::IPAddress address) {
366                                        return AddressMatch(ip_address, address);
367                                      });
368       if (address_it != addresses.end()) {
369         return absl::make_optional(iter.first);
370       }
371     }
372     return absl::nullopt;
373   } else {
374     auto iter = network_handle_by_address_.find(ip_address);
375     if (iter == network_handle_by_address_.end()) {
376       return absl::nullopt;
377     }
378     return absl::make_optional(iter->second);
379   }
380 }
381 
OnNetworkDisconnected(NetworkHandle handle)382 void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
383   RTC_LOG(LS_INFO) << "Network disconnected for handle " << handle;
384   worker_thread()->Invoke<void>(
385       RTC_FROM_HERE,
386       rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle));
387 }
388 
OnNetworkDisconnected_w(NetworkHandle handle)389 void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) {
390   auto iter = network_info_by_handle_.find(handle);
391   if (iter != network_info_by_handle_.end()) {
392     for (const rtc::IPAddress& address : iter->second.ip_addresses) {
393       network_handle_by_address_.erase(address);
394     }
395     network_info_by_handle_.erase(iter);
396   }
397 }
398 
SetNetworkInfos(const std::vector<NetworkInformation> & network_infos)399 void AndroidNetworkMonitor::SetNetworkInfos(
400     const std::vector<NetworkInformation>& network_infos) {
401   RTC_CHECK(thread_checker_.IsCurrent());
402   network_handle_by_address_.clear();
403   network_info_by_handle_.clear();
404   RTC_LOG(LS_INFO) << "Android network monitor found " << network_infos.size()
405                    << " networks";
406   for (NetworkInformation network : network_infos) {
407     OnNetworkConnected_w(network);
408   }
409 }
410 
GetAdapterType(const std::string & if_name)411 rtc::AdapterType AndroidNetworkMonitor::GetAdapterType(
412     const std::string& if_name) {
413   auto iter = adapter_type_by_name_.find(if_name);
414   rtc::AdapterType type = (iter == adapter_type_by_name_.end())
415                               ? rtc::ADAPTER_TYPE_UNKNOWN
416                               : iter->second;
417   if (type == rtc::ADAPTER_TYPE_UNKNOWN) {
418     RTC_LOG(LS_WARNING) << "Get an unknown type for the interface " << if_name;
419   }
420   return type;
421 }
422 
GetVpnUnderlyingAdapterType(const std::string & if_name)423 rtc::AdapterType AndroidNetworkMonitor::GetVpnUnderlyingAdapterType(
424     const std::string& if_name) {
425   auto iter = vpn_underlying_adapter_type_by_name_.find(if_name);
426   rtc::AdapterType type = (iter == vpn_underlying_adapter_type_by_name_.end())
427                               ? rtc::ADAPTER_TYPE_UNKNOWN
428                               : iter->second;
429   return type;
430 }
431 
AndroidNetworkMonitorFactory()432 AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory()
433     : j_application_context_(nullptr) {}
434 
AndroidNetworkMonitorFactory(JNIEnv * env,const JavaRef<jobject> & j_application_context)435 AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory(
436     JNIEnv* env,
437     const JavaRef<jobject>& j_application_context)
438     : j_application_context_(env, j_application_context) {}
439 
440 AndroidNetworkMonitorFactory::~AndroidNetworkMonitorFactory() = default;
441 
442 rtc::NetworkMonitorInterface*
CreateNetworkMonitor()443 AndroidNetworkMonitorFactory::CreateNetworkMonitor() {
444   return new AndroidNetworkMonitor(AttachCurrentThreadIfNeeded(),
445                                    j_application_context_);
446 }
447 
NotifyConnectionTypeChanged(JNIEnv * env,const JavaRef<jobject> & j_caller)448 void AndroidNetworkMonitor::NotifyConnectionTypeChanged(
449     JNIEnv* env,
450     const JavaRef<jobject>& j_caller) {
451   OnNetworksChanged();
452 }
453 
NotifyOfActiveNetworkList(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobjectArray> & j_network_infos)454 void AndroidNetworkMonitor::NotifyOfActiveNetworkList(
455     JNIEnv* env,
456     const JavaRef<jobject>& j_caller,
457     const JavaRef<jobjectArray>& j_network_infos) {
458   std::vector<NetworkInformation> network_infos =
459       JavaToNativeVector<NetworkInformation>(env, j_network_infos,
460                                              &GetNetworkInformationFromJava);
461   SetNetworkInfos(network_infos);
462 }
463 
NotifyOfNetworkConnect(JNIEnv * env,const JavaRef<jobject> & j_caller,const JavaRef<jobject> & j_network_info)464 void AndroidNetworkMonitor::NotifyOfNetworkConnect(
465     JNIEnv* env,
466     const JavaRef<jobject>& j_caller,
467     const JavaRef<jobject>& j_network_info) {
468   NetworkInformation network_info =
469       GetNetworkInformationFromJava(env, j_network_info);
470   OnNetworkConnected(network_info);
471 }
472 
NotifyOfNetworkDisconnect(JNIEnv * env,const JavaRef<jobject> & j_caller,jlong network_handle)473 void AndroidNetworkMonitor::NotifyOfNetworkDisconnect(
474     JNIEnv* env,
475     const JavaRef<jobject>& j_caller,
476     jlong network_handle) {
477   OnNetworkDisconnected(static_cast<NetworkHandle>(network_handle));
478 }
479 
480 }  // namespace jni
481 }  // namespace webrtc
482