1 /*
2 * Copyright (C) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <arpa/inet.h>
17 #include <cstring>
18 #include <fcntl.h>
19 #include <fstream>
20 #include <future>
21 #include <list>
22 #include <memory>
23 #include <netdb.h>
24 #include <regex>
25 #include <securec.h>
26 #include <sys/socket.h>
27 #include <thread>
28 #include <pthread.h>
29 #include <unistd.h>
30
31 #include "net_monitor.h"
32 #include "dns_config_client.h"
33 #include "event_report.h"
34 #include "fwmark_client.h"
35 #include "netmanager_base_common_utils.h"
36 #include "netsys_controller.h"
37 #include "net_http_proxy_tracker.h"
38 #include "net_mgr_log_wrapper.h"
39 #include "net_manager_constants.h"
40
41 namespace OHOS {
42 namespace NetManagerStandard {
43 namespace {
44 constexpr int32_t INIT_DETECTION_DELAY_MS = 1 * 1000;
45 constexpr int32_t MAX_FAILED_DETECTION_DELAY_MS = 10 * 60 * 1000;
46 constexpr int32_t CAPTIVE_PORTAL_DETECTION_DELAY_MS = 30 * 1000;
47 constexpr int32_t DOUBLE = 2;
48 constexpr const char NEW_LINE_STR = '\n';
49 constexpr const char *URL_CFG_FILE = "/system/etc/netdetectionurl.conf";
50 constexpr const char *HTTP_URL_HEADER = "HttpProbeUrl:";
51 constexpr const char *HTTPS_URL_HEADER = "HttpsProbeUrl:";
52 constexpr const char *NET_HTTP_PROBE_URL = "http://connectivitycheck.platform.hicloud.com/generate_204";
53 constexpr const char *NET_HTTPS_PROBE_URL = "https://connectivitycheck.platform.hicloud.com/generate_204";
54 } // namespace
NetDetectThread(const std::shared_ptr<NetMonitor> & netMonitor)55 static void NetDetectThread(const std::shared_ptr<NetMonitor> &netMonitor)
56 {
57 if (netMonitor == nullptr) {
58 NETMGR_LOG_E("netMonitor is nullptr");
59 return;
60 }
61 while (netMonitor->IsDetecting()) {
62 netMonitor->Detection();
63 }
64 }
65
NetMonitor(uint32_t netId,NetBearType bearType,const NetLinkInfo & netLinkInfo,const std::weak_ptr<INetMonitorCallback> & callback)66 NetMonitor::NetMonitor(uint32_t netId, NetBearType bearType, const NetLinkInfo &netLinkInfo,
67 const std::weak_ptr<INetMonitorCallback> &callback)
68 : netId_(netId), netMonitorCallback_(callback)
69 {
70 httpProbe_ = std::make_unique<NetHttpProbe>(netId, bearType, netLinkInfo);
71 LoadGlobalHttpProxy();
72 }
73
Start()74 void NetMonitor::Start()
75 {
76 NETMGR_LOG_I("Start net[%{public}d] monitor in", netId_);
77 if (isDetecting_) {
78 NETMGR_LOG_W("Net[%{public}d] monitor is detecting, no need to start", netId_);
79 return;
80 }
81 isDetecting_ = true;
82 std::shared_ptr<NetMonitor> netMonitor = shared_from_this();
83 std::thread t([netMonitor] { return NetDetectThread(netMonitor); });
84 std::string threadName = "netDetect";
85 pthread_setname_np(t.native_handle(), threadName.c_str());
86 t.detach();
87 }
88
Stop()89 void NetMonitor::Stop()
90 {
91 NETMGR_LOG_I("Stop net[%{public}d] monitor in", netId_);
92 isDetecting_ = false;
93 detectionCond_.notify_all();
94 NETMGR_LOG_D("Stop net[%{public}d] monitor out", netId_);
95 }
96
IsDetecting()97 bool NetMonitor::IsDetecting()
98 {
99 return isDetecting_.load();
100 }
101
Detection()102 void NetMonitor::Detection()
103 {
104 NetHttpProbeResult probeResult = SendHttpProbe(PROBE_HTTP_HTTPS);
105 if (isDetecting_) {
106 NetDetectionStatus result = UNKNOWN_STATE;
107 if (probeResult.IsSuccessful()) {
108 NETMGR_LOG_I("Net[%{public}d] probe success", netId_);
109 isDetecting_ = false;
110 detectionSteps_ = 0;
111 result = VERIFICATION_STATE;
112 } else if (probeResult.IsNeedPortal()) {
113 NETMGR_LOG_W("Net[%{public}d] need portal", netId_);
114 detectionDelay_ = CAPTIVE_PORTAL_DETECTION_DELAY_MS;
115 result = CAPTIVE_PORTAL_STATE;
116 } else {
117 NETMGR_LOG_E("Net[%{public}d] probe failed", netId_);
118 detectionDelay_ *= DOUBLE;
119 if (detectionDelay_ == 0) {
120 detectionDelay_ = INIT_DETECTION_DELAY_MS;
121 } else if (detectionDelay_ >= MAX_FAILED_DETECTION_DELAY_MS) {
122 detectionDelay_ = MAX_FAILED_DETECTION_DELAY_MS;
123 }
124 NETMGR_LOG_I("Net probe failed detectionDelay time [%{public}d]", detectionDelay_);
125 detectionSteps_++;
126 result = INVALID_DETECTION_STATE;
127 }
128 auto monitorCallback = netMonitorCallback_.lock();
129 if (monitorCallback) {
130 monitorCallback->OnHandleNetMonitorResult(result, probeResult.GetRedirectUrl());
131 }
132 struct EventInfo eventInfo = {.monitorStatus = static_cast<int32_t>(result)};
133 EventReport::SendMonitorBehaviorEvent(eventInfo);
134 if (isDetecting_) {
135 std::unique_lock<std::mutex> locker(detectionMtx_);
136 detectionCond_.wait_for(locker, std::chrono::milliseconds(detectionDelay_));
137 }
138 }
139 }
140
SendHttpProbe(ProbeType probeType)141 NetHttpProbeResult NetMonitor::SendHttpProbe(ProbeType probeType)
142 {
143 std::lock_guard<std::mutex> locker(probeMtx_);
144 std::string httpProbeUrl;
145 std::string httpsProbeUrl;
146 GetHttpProbeUrlFromConfig(httpProbeUrl, httpsProbeUrl);
147
148 if (httpProbe_ == nullptr) {
149 NETMGR_LOG_E("Net:[%{public}d] httpProbe_ is nullptr", netId_);
150 return NetHttpProbeResult();
151 }
152
153 if (httpProbe_->SendProbe(probeType, httpProbeUrl, httpsProbeUrl) != NETMANAGER_SUCCESS) {
154 NETMGR_LOG_E("Net:[%{public}d] send probe failed.", netId_);
155 return NetHttpProbeResult();
156 }
157
158 if (httpProbe_->GetHttpProbeResult().IsNeedPortal()) {
159 return httpProbe_->GetHttpProbeResult();
160 }
161
162 #ifdef NEED_REPORT_PARTIAL_CONNECTION
163 if (httpProbe_->HasProbeType(probeType, ProbeType::PROBE_HTTP) &&
164 httpProbe_->HasProbeType(probeType, ProbeType::PROBE_HTTPS)) {
165 if (httpProbe_->GetHttpProbeResult().IsSuccessful() && httpProbe_->GetHttpsProbeResult().IsFailed) {
166 // return probe result: PARTIAL;
167 }
168 }
169 #endif
170
171 if (httpProbe_->HasProbeType(probeType, ProbeType::PROBE_HTTPS)) {
172 return httpProbe_->GetHttpsProbeResult();
173 }
174
175 return httpProbe_->GetHttpProbeResult();
176 }
177
GetHttpProbeUrlFromConfig(std::string & httpUrl,std::string & httpsUrl)178 void NetMonitor::GetHttpProbeUrlFromConfig(std::string &httpUrl, std::string &httpsUrl)
179 {
180 if (!std::filesystem::exists(URL_CFG_FILE)) {
181 NETMGR_LOG_E("File not exist (%{public}s)", URL_CFG_FILE);
182 return;
183 }
184
185 std::ifstream file(URL_CFG_FILE);
186 if (!file.is_open()) {
187 NETMGR_LOG_E("Open file failed (%{public}s)", strerror(errno));
188 return;
189 }
190
191 std::ostringstream oss;
192 oss << file.rdbuf();
193 std::string content = oss.str();
194 auto pos = content.find(HTTP_URL_HEADER);
195 if (pos != std::string::npos) {
196 pos += strlen(HTTP_URL_HEADER);
197 httpUrl = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
198 }
199 httpUrl = httpUrl.empty() ? NET_HTTP_PROBE_URL : httpUrl;
200
201 pos = content.find(HTTPS_URL_HEADER);
202 if (pos != std::string::npos) {
203 pos += strlen(HTTPS_URL_HEADER);
204 httpsUrl = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
205 }
206 httpsUrl = httpsUrl.empty() ? NET_HTTPS_PROBE_URL : httpsUrl;
207 NETMGR_LOG_D("Get net detection http url:[%{public}s], https url:[%{public}s]", httpUrl.c_str(), httpsUrl.c_str());
208 }
209
LoadGlobalHttpProxy()210 void NetMonitor::LoadGlobalHttpProxy()
211 {
212 HttpProxy globalHttpProxy;
213 NetHttpProxyTracker httpProxyTracker;
214 httpProxyTracker.ReadFromSettingsData(globalHttpProxy);
215 UpdateGlobalHttpProxy(globalHttpProxy);
216 }
217
UpdateGlobalHttpProxy(const HttpProxy & httpProxy)218 void NetMonitor::UpdateGlobalHttpProxy(const HttpProxy &httpProxy)
219 {
220 if (httpProbe_) {
221 httpProbe_->UpdateGlobalHttpProxy(httpProxy);
222 }
223 }
224 } // namespace NetManagerStandard
225 } // namespace OHOS
226