1 /*
2  * Copyright (C) 2021-2024 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 #include <string>
31 
32 #include "net_monitor.h"
33 #include "dns_config_client.h"
34 #include "event_report.h"
35 #include "fwmark_client.h"
36 #include "netmanager_base_common_utils.h"
37 #include "netsys_controller.h"
38 #include "net_http_proxy_tracker.h"
39 #include "net_mgr_log_wrapper.h"
40 #include "net_manager_constants.h"
41 #include "tiny_count_down_latch.h"
42 
43 namespace OHOS {
44 namespace NetManagerStandard {
45 namespace {
46 constexpr int32_t INIT_DETECTION_DELAY_MS = 1 * 1000;
47 constexpr int32_t MAX_FAILED_DETECTION_DELAY_MS = 10 * 60 * 1000;
48 constexpr int32_t PRIMARY_DETECTION_RESULT_WAIT_MS = 3 * 1000;
49 constexpr int32_t ALL_DETECTION_RESULT_WAIT_MS = 10 * 1000;
50 constexpr int32_t CAPTIVE_PORTAL_DETECTION_DELAY_MS = 15 * 1000;
51 constexpr int32_t DOUBLE = 2;
52 constexpr int32_t SIM_PORTAL_CODE = 302;
53 constexpr int32_t ONE_URL_DETECT_NUM = 2;
54 constexpr int32_t ALL_DETECT_THREAD_NUM = 4;
55 constexpr const char NEW_LINE_STR = '\n';
56 constexpr const char* URL_CFG_FILE = "/system/etc/netdetectionurl.conf";
57 constexpr const char *SETTINGS_DATASHARE_URI =
58         "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true";
59 constexpr const char *SETTINGS_DATA_EXT_URI = "datashare:///com.ohos.settingsdata.DataAbility";
60 constexpr const char* DETECT_CFG_FILE = "/system/etc/detectionconfig.conf";
61 const std::string HTTP_URL_HEADER = "HttpProbeUrl:";
62 const std::string HTTPS_URL_HEADER = "HttpsProbeUrl:";
63 const std::string FALLBACK_HTTP_URL_HEADER = "FallbackHttpProbeUrl:";
64 const std::string FALLBACK_HTTPS_URL_HEADER = "FallbackHttpsProbeUrl:";
65 const std::string ADD_RANDOM_CFG_PREFIX = "AddSuffix:";
66 const std::string ADD_RANDOM_CFG_VALUE = "true";
67 } // namespace
NetDetectThread(const std::shared_ptr<NetMonitor> & netMonitor)68 static void NetDetectThread(const std::shared_ptr<NetMonitor> &netMonitor)
69 {
70     if (netMonitor == nullptr) {
71         NETMGR_LOG_E("netMonitor is nullptr");
72         return;
73     }
74     while (netMonitor->IsDetecting()) {
75         netMonitor->Detection();
76     }
77 }
78 
NetMonitor(uint32_t netId,NetBearType bearType,const NetLinkInfo & netLinkInfo,const std::weak_ptr<INetMonitorCallback> & callback)79 NetMonitor::NetMonitor(uint32_t netId, NetBearType bearType, const NetLinkInfo &netLinkInfo,
80                        const std::weak_ptr<INetMonitorCallback> &callback)
81     : netId_(netId), netLinkInfo_(netLinkInfo), netMonitorCallback_(callback)
82 {
83     netBearType_ = bearType;
84     LoadGlobalHttpProxy();
85     GetDetectUrlConfig();
86     GetHttpProbeUrlFromConfig();
87 }
88 
Start()89 void NetMonitor::Start()
90 {
91     NETMGR_LOG_D("Start net[%{public}d] monitor in", netId_);
92     if (isDetecting_) {
93         NETMGR_LOG_W("Net[%{public}d] monitor is detecting, no need to start", netId_);
94         return;
95     }
96     isDetecting_ = true;
97     std::shared_ptr<NetMonitor> netMonitor = shared_from_this();
98     std::thread t([netMonitor] { return NetDetectThread(netMonitor); });
99     std::string threadName = "netDetect";
100     pthread_setname_np(t.native_handle(), threadName.c_str());
101     t.detach();
102 }
103 
Stop()104 void NetMonitor::Stop()
105 {
106     NETMGR_LOG_I("Stop net[%{public}d] monitor in", netId_);
107     isDetecting_ = false;
108     detectionCond_.notify_all();
109     NETMGR_LOG_D("Stop net[%{public}d] monitor out", netId_);
110 }
111 
IsDetecting()112 bool NetMonitor::IsDetecting()
113 {
114     return isDetecting_.load();
115 }
116 
ProcessDetection(NetHttpProbeResult & probeResult,NetDetectionStatus & result)117 void NetMonitor::ProcessDetection(NetHttpProbeResult& probeResult, NetDetectionStatus& result)
118 {
119     if (probeResult.IsSuccessful()) {
120         NETMGR_LOG_I("Net[%{public}d] probe success", netId_);
121         isDetecting_ = false;
122         needDetectionWithoutProxy_ = true;
123         result = VERIFICATION_STATE;
124     } else if (probeResult.GetCode() == SIM_PORTAL_CODE && netBearType_ == BEARER_CELLULAR) {
125         NETMGR_LOG_E("Net[%{public}d] probe failed with 302 response on Cell", netId_);
126         detectionDelay_ = MAX_FAILED_DETECTION_DELAY_MS;
127         result = CAPTIVE_PORTAL_STATE;
128     } else if (probeResult.IsNeedPortal()) {
129         NETMGR_LOG_W("Net[%{public}d] need portal", netId_);
130         detectionDelay_ = CAPTIVE_PORTAL_DETECTION_DELAY_MS;
131         result = CAPTIVE_PORTAL_STATE;
132     } else {
133         NETMGR_LOG_E("Net[%{public}d] probe failed", netId_);
134         detectionDelay_ *= DOUBLE;
135         if (detectionDelay_ == 0) {
136             detectionDelay_ = INIT_DETECTION_DELAY_MS;
137         } else if (detectionDelay_ >= MAX_FAILED_DETECTION_DELAY_MS) {
138             detectionDelay_ = MAX_FAILED_DETECTION_DELAY_MS;
139         }
140         NETMGR_LOG_I("Net probe failed detectionDelay time [%{public}d]", detectionDelay_);
141         result = INVALID_DETECTION_STATE;
142     }
143     auto monitorCallback = netMonitorCallback_.lock();
144     if (monitorCallback) {
145         monitorCallback->OnHandleNetMonitorResult(result, probeResult.GetRedirectUrl());
146     }
147     struct EventInfo eventInfo = {.monitorStatus = static_cast<int32_t>(result)};
148     EventReport::SendMonitorBehaviorEvent(eventInfo);
149     if (isDetecting_) {
150         std::unique_lock<std::mutex> locker(detectionMtx_);
151         detectionCond_.wait_for(locker, std::chrono::milliseconds(detectionDelay_));
152     }
153 }
154 
Detection()155 void NetMonitor::Detection()
156 {
157     NetHttpProbeResult probeResult = SendProbe();
158     if (isDetecting_) {
159         NetDetectionStatus result = UNKNOWN_STATE;
160         ProcessDetection(probeResult, result);
161     }
162 }
163 
SendProbe()164 NetHttpProbeResult NetMonitor::SendProbe()
165 {
166     NETMGR_LOG_I("start net detection");
167     std::lock_guard<std::mutex> monitorLocker(probeMtx_);
168     std::shared_ptr<TinyCountDownLatch> latch = std::make_shared<TinyCountDownLatch>(ONE_URL_DETECT_NUM);
169     std::shared_ptr<TinyCountDownLatch> latchAll = std::make_shared<TinyCountDownLatch>(ALL_DETECT_THREAD_NUM);
170     std::shared_ptr<ProbeThread> primaryHttpThread = std::make_shared<ProbeThread>(
171         netId_, netBearType_, netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTP, httpUrl_, httpsUrl_);
172     std::shared_ptr<ProbeThread> primaryHttpsThread = std::make_shared<ProbeThread>(
173         netId_, netBearType_, netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTPS, httpUrl_, httpsUrl_);
174     {
175         std::lock_guard<std::mutex> proxyLocker(proxyMtx_);
176         primaryHttpThread->UpdateGlobalHttpProxy(globalHttpProxy_);
177         primaryHttpsThread->UpdateGlobalHttpProxy(globalHttpProxy_);
178     }
179     primaryHttpThread->Start();
180     primaryHttpsThread->Start();
181 
182     latch->Await(std::chrono::milliseconds(PRIMARY_DETECTION_RESULT_WAIT_MS));
183     NetHttpProbeResult httpProbeResult = GetThreadDetectResult(primaryHttpThread, ProbeType::PROBE_HTTP);
184     NetHttpProbeResult httpsProbeResult = GetThreadDetectResult(primaryHttpsThread, ProbeType::PROBE_HTTPS);
185     if (httpProbeResult.IsNeedPortal()) {
186         NETMGR_LOG_I("http detect result: portal");
187         return httpProbeResult;
188     }
189     if (httpsProbeResult.IsSuccessful()) {
190         NETMGR_LOG_I("https detect result: success");
191         return httpsProbeResult;
192     }
193     NETMGR_LOG_I("backup url detection start");
194     std::shared_ptr<ProbeThread> fallbackHttpThread = std::make_shared<ProbeThread>(netId_, netBearType_,
195         netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTP_FALLBACK, fallbackHttpUrl_, fallbackHttpsUrl_);
196     std::shared_ptr<ProbeThread> fallbackHttpsThread = std::make_shared<ProbeThread>(netId_, netBearType_,
197         netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTPS_FALLBACK, fallbackHttpUrl_, fallbackHttpsUrl_);
198     fallbackHttpThread->ProbeWithoutGlobalHttpProxy();
199     fallbackHttpsThread->ProbeWithoutGlobalHttpProxy();
200     fallbackHttpThread->Start();
201     fallbackHttpsThread->Start();
202     latchAll->Await(std::chrono::milliseconds(ALL_DETECTION_RESULT_WAIT_MS));
203     httpProbeResult = GetThreadDetectResult(primaryHttpThread, ProbeType::PROBE_HTTP);
204     httpsProbeResult = GetThreadDetectResult(primaryHttpsThread, ProbeType::PROBE_HTTPS);
205     NetHttpProbeResult fallbackHttpProbeResult =
206         GetThreadDetectResult(fallbackHttpThread, ProbeType::PROBE_HTTP_FALLBACK);
207     NetHttpProbeResult fallbackHttpsProbeResult =
208         GetThreadDetectResult(fallbackHttpsThread, ProbeType::PROBE_HTTPS_FALLBACK);
209     return ProcessThreadDetectResult(httpProbeResult, httpsProbeResult, fallbackHttpProbeResult,
210         fallbackHttpsProbeResult);
211 }
212 
GetThreadDetectResult(std::shared_ptr<ProbeThread> & probeThread,ProbeType probeType)213 NetHttpProbeResult NetMonitor::GetThreadDetectResult(std::shared_ptr<ProbeThread>& probeThread, ProbeType probeType)
214 {
215     NetHttpProbeResult result;
216     if (!probeThread->IsDetecting()) {
217         if (probeType == ProbeType::PROBE_HTTP || probeType == ProbeType::PROBE_HTTP_FALLBACK) {
218             return probeThread->GetHttpProbeResult();
219         } else {
220             return probeThread->GetHttpsProbeResult();
221         }
222     }
223     return result;
224 }
225 
ProcessThreadDetectResult(NetHttpProbeResult & httpProbeResult,NetHttpProbeResult & httpsProbeResult,NetHttpProbeResult & fallbackHttpProbeResult,NetHttpProbeResult & fallbackHttpsProbeResult)226 NetHttpProbeResult NetMonitor::ProcessThreadDetectResult(NetHttpProbeResult& httpProbeResult,
227     NetHttpProbeResult& httpsProbeResult, NetHttpProbeResult& fallbackHttpProbeResult,
228     NetHttpProbeResult& fallbackHttpsProbeResult)
229 {
230     if (httpProbeResult.IsNeedPortal()) {
231         NETMGR_LOG_I("primary http detect result: portal");
232         return httpProbeResult;
233     }
234     if (fallbackHttpProbeResult.IsNeedPortal()) {
235         NETMGR_LOG_I("fallback http detect result: portal");
236         return fallbackHttpProbeResult;
237     }
238     if (httpsProbeResult.IsSuccessful()) {
239         NETMGR_LOG_I("primary https detect result: success");
240         return httpsProbeResult;
241     }
242     if (fallbackHttpsProbeResult.IsSuccessful()) {
243         NETMGR_LOG_I("fallback https detect result: success");
244         return fallbackHttpsProbeResult;
245     }
246     if (httpProbeResult.IsSuccessful() && fallbackHttpProbeResult.IsSuccessful()) {
247         NETMGR_LOG_I("both primary http and fallback http detect result success");
248         return httpProbeResult;
249     }
250     return httpsProbeResult;
251 }
252 
LoadGlobalHttpProxy()253 void NetMonitor::LoadGlobalHttpProxy()
254 {
255     if (!CheckIfSettingsDataReady()) {
256         NETMGR_LOG_E("data_share is not ready");
257         return;
258     }
259     NetHttpProxyTracker httpProxyTracker;
260     httpProxyTracker.ReadFromSettingsData(globalHttpProxy_);
261 }
262 
UpdateGlobalHttpProxy(const HttpProxy & httpProxy)263 void NetMonitor::UpdateGlobalHttpProxy(const HttpProxy &httpProxy)
264 {
265     std::unique_lock<std::mutex> proxyLocker(proxyMtx_);
266     globalHttpProxy_ = httpProxy;
267 }
268 
GetHttpProbeUrlFromConfig()269 void NetMonitor::GetHttpProbeUrlFromConfig()
270 {
271     if (!std::filesystem::exists(URL_CFG_FILE)) {
272         NETMGR_LOG_E("File not exist (%{public}s)", URL_CFG_FILE);
273         return;
274     }
275 
276     std::ifstream file(URL_CFG_FILE);
277     if (!file.is_open()) {
278         NETMGR_LOG_E("Open file failed (%{public}s)", strerror(errno));
279         return;
280     }
281 
282     std::ostringstream oss;
283     oss << file.rdbuf();
284     std::string content = oss.str();
285     auto pos = content.find(HTTP_URL_HEADER);
286     if (pos != std::string::npos) {
287         pos += HTTP_URL_HEADER.length();
288         httpUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
289         if (isNeedSuffix_) {
290             uint64_t ranNum = CommonUtils::GenRandomNumber();
291             httpUrl_ = httpUrl_ + std::string("_") + std::to_string(ranNum);
292         }
293     }
294 
295     pos = content.find(HTTPS_URL_HEADER);
296     if (pos != std::string::npos) {
297         pos += HTTPS_URL_HEADER.length();
298         httpsUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
299     }
300 
301     pos = content.find(FALLBACK_HTTP_URL_HEADER);
302     if (pos != std::string::npos) {
303         pos += FALLBACK_HTTP_URL_HEADER.length();
304         fallbackHttpUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
305     }
306 
307     pos = content.find(FALLBACK_HTTPS_URL_HEADER);
308     if (pos != std::string::npos) {
309         pos += FALLBACK_HTTPS_URL_HEADER.length();
310         fallbackHttpsUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
311     }
312     NETMGR_LOG_D("Get net detection http url:[%{public}s], https url:[%{public}s], fallback http url:[%{public}s],"
313         " fallback https url:[%{public}s]", httpUrl_.c_str(), httpsUrl_.c_str(), fallbackHttpUrl_.c_str(),
314         fallbackHttpsUrl_.c_str());
315 }
316 
CheckIfSettingsDataReady()317 bool NetMonitor::CheckIfSettingsDataReady()
318 {
319     if (isDataShareReady_) {
320         return true;
321     }
322     sptr<ISystemAbilityManager> saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
323     if (saManager == nullptr) {
324         NETMGR_LOG_E("GetSystemAbilityManager failed.");
325         return false;
326     }
327     sptr<IRemoteObject> dataShareSa = saManager->GetSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID);
328     if (dataShareSa == nullptr) {
329         NETMGR_LOG_E("Get dataShare SA Failed.");
330         return false;
331     }
332     sptr<IRemoteObject> remoteObj = saManager->GetSystemAbility(COMM_NET_CONN_MANAGER_SYS_ABILITY_ID);
333     if (remoteObj == nullptr) {
334         NETMGR_LOG_E("NetDataShareHelperUtils GetSystemAbility Service Failed.");
335         return false;
336     }
337     std::pair<int, std::shared_ptr<DataShare::DataShareHelper>> ret =
338             DataShare::DataShareHelper::Create(remoteObj, SETTINGS_DATASHARE_URI, SETTINGS_DATA_EXT_URI);
339     NETMGR_LOG_I("create data_share helper, ret=%{public}d", ret.first);
340     if (ret.first == DataShare::E_OK) {
341         NETMGR_LOG_I("create data_share helper success");
342         auto helper = ret.second;
343         if (helper != nullptr) {
344             bool releaseRet = helper->Release();
345             NETMGR_LOG_I("release data_share helper, releaseRet=%{public}d", releaseRet);
346         }
347         isDataShareReady_ = true;
348         return true;
349     } else if (ret.first == DataShare::E_DATA_SHARE_NOT_READY) {
350         NETMGR_LOG_E("create data_share helper failed");
351         isDataShareReady_ = false;
352         return false;
353     }
354     NETMGR_LOG_E("data_share unknown.");
355     return true;
356 }
GetDetectUrlConfig()357 void NetMonitor::GetDetectUrlConfig()
358 {
359     if (!std::filesystem::exists(DETECT_CFG_FILE)) {
360         NETMGR_LOG_E("File not exist (%{public}s)", DETECT_CFG_FILE);
361         return;
362     }
363 
364     std::ifstream file(DETECT_CFG_FILE);
365     if (!file.is_open()) {
366         NETMGR_LOG_E("Open file failed (%{public}s)", strerror(errno));
367         return;
368     }
369     std::ostringstream oss;
370     oss << file.rdbuf();
371     std::string content = oss.str();
372     auto pos = content.find(ADD_RANDOM_CFG_PREFIX);
373     if (pos != std::string::npos) {
374         pos += ADD_RANDOM_CFG_PREFIX.length();
375         std::string value = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
376         value = CommonUtils::Trim(value);
377         isNeedSuffix_ = value.compare(ADD_RANDOM_CFG_VALUE) == 0;
378     }
379     NETMGR_LOG_I("is need add suffix (%{public}d)", isNeedSuffix_);
380 }
381 
382 } // namespace NetManagerStandard
383 } // namespace OHOS