• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 #include "tiny_count_down_latch.h"
41 
42 namespace OHOS {
43 namespace NetManagerStandard {
44 namespace {
45 constexpr int32_t INIT_DETECTION_DELAY_MS = 1 * 1000;
46 constexpr int32_t MAX_FAILED_DETECTION_DELAY_MS = 10 * 60 * 1000;
47 constexpr int32_t PRIMARY_DETECTION_RESULT_WAIT_MS = 3 * 1000;
48 constexpr int32_t ALL_DETECTION_RESULT_WAIT_MS = 10 * 1000;
49 constexpr int32_t CAPTIVE_PORTAL_DETECTION_DELAY_MS = 15 * 1000;
50 constexpr int32_t DOUBLE = 2;
51 constexpr int32_t SIM_PORTAL_CODE = 302;
52 constexpr int32_t ONE_URL_DETECT_NUM = 2;
53 constexpr int32_t ALL_DETECT_THREAD_NUM = 4;
54 constexpr const char NEW_LINE_STR = '\n';
55 constexpr const char* URL_CFG_FILE = "/system/etc/netdetectionurl.conf";
56 const std::string HTTP_URL_HEADER = "HttpProbeUrl:";
57 const std::string HTTPS_URL_HEADER = "HttpsProbeUrl:";
58 const std::string FALLBACK_HTTP_URL_HEADER = "FallbackHttpProbeUrl:";
59 const std::string FALLBACK_HTTPS_URL_HEADER = "FallbackHttpsProbeUrl:";
60 } // namespace
NetDetectThread(const std::shared_ptr<NetMonitor> & netMonitor)61 static void NetDetectThread(const std::shared_ptr<NetMonitor> &netMonitor)
62 {
63     if (netMonitor == nullptr) {
64         NETMGR_LOG_E("netMonitor is nullptr");
65         return;
66     }
67     while (netMonitor->IsDetecting()) {
68         netMonitor->Detection();
69     }
70 }
71 
NetMonitor(uint32_t netId,NetBearType bearType,const NetLinkInfo & netLinkInfo,const std::weak_ptr<INetMonitorCallback> & callback)72 NetMonitor::NetMonitor(uint32_t netId, NetBearType bearType, const NetLinkInfo &netLinkInfo,
73                        const std::weak_ptr<INetMonitorCallback> &callback)
74     : netId_(netId), netLinkInfo_(netLinkInfo), netMonitorCallback_(callback)
75 {
76     netBearType_ = bearType;
77     LoadGlobalHttpProxy();
78     GetHttpProbeUrlFromConfig();
79 }
80 
Start()81 void NetMonitor::Start()
82 {
83     NETMGR_LOG_D("Start net[%{public}d] monitor in", netId_);
84     if (isDetecting_) {
85         NETMGR_LOG_W("Net[%{public}d] monitor is detecting, no need to start", netId_);
86         return;
87     }
88     isDetecting_ = true;
89     std::shared_ptr<NetMonitor> netMonitor = shared_from_this();
90     std::thread t([netMonitor] { return NetDetectThread(netMonitor); });
91     std::string threadName = "netDetect";
92     pthread_setname_np(t.native_handle(), threadName.c_str());
93     t.detach();
94 }
95 
Stop()96 void NetMonitor::Stop()
97 {
98     NETMGR_LOG_I("Stop net[%{public}d] monitor in", netId_);
99     isDetecting_ = false;
100     detectionCond_.notify_all();
101     NETMGR_LOG_D("Stop net[%{public}d] monitor out", netId_);
102 }
103 
IsDetecting()104 bool NetMonitor::IsDetecting()
105 {
106     return isDetecting_.load();
107 }
108 
ProcessDetection(NetHttpProbeResult & probeResult,NetDetectionStatus & result)109 void NetMonitor::ProcessDetection(NetHttpProbeResult& probeResult, NetDetectionStatus& result)
110 {
111     if (probeResult.IsSuccessful()) {
112         NETMGR_LOG_I("Net[%{public}d] probe success", netId_);
113         isDetecting_ = false;
114         needDetectionWithoutProxy_ = true;
115         result = VERIFICATION_STATE;
116     } else if (probeResult.GetCode() == SIM_PORTAL_CODE && netBearType_ == BEARER_CELLULAR) {
117         NETMGR_LOG_E("Net[%{public}d] probe failed with 302 response on Cell", netId_);
118         detectionDelay_ = MAX_FAILED_DETECTION_DELAY_MS;
119         result = CAPTIVE_PORTAL_STATE;
120     } else if (probeResult.IsNeedPortal()) {
121         NETMGR_LOG_W("Net[%{public}d] need portal", netId_);
122         detectionDelay_ = CAPTIVE_PORTAL_DETECTION_DELAY_MS;
123         result = CAPTIVE_PORTAL_STATE;
124     } else {
125         NETMGR_LOG_E("Net[%{public}d] probe failed", netId_);
126         detectionDelay_ *= DOUBLE;
127         if (detectionDelay_ == 0) {
128             detectionDelay_ = INIT_DETECTION_DELAY_MS;
129         } else if (detectionDelay_ >= MAX_FAILED_DETECTION_DELAY_MS) {
130             detectionDelay_ = MAX_FAILED_DETECTION_DELAY_MS;
131         }
132         NETMGR_LOG_I("Net probe failed detectionDelay time [%{public}d]", detectionDelay_);
133         result = INVALID_DETECTION_STATE;
134     }
135     auto monitorCallback = netMonitorCallback_.lock();
136     if (monitorCallback) {
137         monitorCallback->OnHandleNetMonitorResult(result, probeResult.GetRedirectUrl());
138     }
139     struct EventInfo eventInfo = {.monitorStatus = static_cast<int32_t>(result)};
140     EventReport::SendMonitorBehaviorEvent(eventInfo);
141     if (isDetecting_) {
142         std::unique_lock<std::mutex> locker(detectionMtx_);
143         detectionCond_.wait_for(locker, std::chrono::milliseconds(detectionDelay_));
144     }
145 }
146 
Detection()147 void NetMonitor::Detection()
148 {
149     NetHttpProbeResult probeResult = SendProbe();
150     if (isDetecting_) {
151         NetDetectionStatus result = UNKNOWN_STATE;
152         ProcessDetection(probeResult, result);
153     }
154 }
155 
SendProbe()156 NetHttpProbeResult NetMonitor::SendProbe()
157 {
158     NETMGR_LOG_I("start net detection");
159     std::lock_guard<std::mutex> monitorLocker(probeMtx_);
160     std::shared_ptr<TinyCountDownLatch> latch = std::make_shared<TinyCountDownLatch>(ONE_URL_DETECT_NUM);
161     std::shared_ptr<TinyCountDownLatch> latchAll = std::make_shared<TinyCountDownLatch>(ALL_DETECT_THREAD_NUM);
162     std::shared_ptr<ProbeThread> primaryHttpThread = std::make_shared<ProbeThread>(
163         netId_, netBearType_, netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTP, httpUrl_, httpsUrl_);
164     std::shared_ptr<ProbeThread> primaryHttpsThread = std::make_shared<ProbeThread>(
165         netId_, netBearType_, netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTPS, httpUrl_, httpsUrl_);
166     {
167         std::lock_guard<std::mutex> proxyLocker(proxyMtx_);
168         primaryHttpThread->UpdateGlobalHttpProxy(globalHttpProxy_);
169         primaryHttpsThread->UpdateGlobalHttpProxy(globalHttpProxy_);
170     }
171     primaryHttpThread->Start();
172     primaryHttpsThread->Start();
173 
174     latch->Await(std::chrono::milliseconds(PRIMARY_DETECTION_RESULT_WAIT_MS));
175     NetHttpProbeResult httpProbeResult = GetThreadDetectResult(primaryHttpThread, ProbeType::PROBE_HTTP);
176     NetHttpProbeResult httpsProbeResult = GetThreadDetectResult(primaryHttpsThread, ProbeType::PROBE_HTTPS);
177     if (httpProbeResult.IsNeedPortal()) {
178         NETMGR_LOG_I("http detect result: portal");
179         return httpProbeResult;
180     }
181     if (httpsProbeResult.IsSuccessful()) {
182         NETMGR_LOG_I("https detect result: success");
183         return httpsProbeResult;
184     }
185     NETMGR_LOG_I("backup url detection start");
186     std::shared_ptr<ProbeThread> fallbackHttpThread = std::make_shared<ProbeThread>(netId_, netBearType_,
187         netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTP_FALLBACK, fallbackHttpUrl_, fallbackHttpsUrl_);
188     std::shared_ptr<ProbeThread> fallbackHttpsThread = std::make_shared<ProbeThread>(netId_, netBearType_,
189         netLinkInfo_, latch, latchAll, ProbeType::PROBE_HTTPS_FALLBACK, fallbackHttpUrl_, fallbackHttpsUrl_);
190     fallbackHttpThread->ProbeWithoutGlobalHttpProxy();
191     fallbackHttpsThread->ProbeWithoutGlobalHttpProxy();
192     fallbackHttpThread->Start();
193     fallbackHttpsThread->Start();
194     latchAll->Await(std::chrono::milliseconds(ALL_DETECTION_RESULT_WAIT_MS));
195     httpProbeResult = GetThreadDetectResult(primaryHttpThread, ProbeType::PROBE_HTTP);
196     httpsProbeResult = GetThreadDetectResult(primaryHttpsThread, ProbeType::PROBE_HTTPS);
197     NetHttpProbeResult fallbackHttpProbeResult =
198         GetThreadDetectResult(fallbackHttpThread, ProbeType::PROBE_HTTP_FALLBACK);
199     NetHttpProbeResult fallbackHttpsProbeResult =
200         GetThreadDetectResult(fallbackHttpsThread, ProbeType::PROBE_HTTPS_FALLBACK);
201     return ProcessThreadDetectResult(httpProbeResult, httpsProbeResult, fallbackHttpProbeResult,
202         fallbackHttpsProbeResult);
203 }
204 
GetThreadDetectResult(std::shared_ptr<ProbeThread> & probeThread,ProbeType probeType)205 NetHttpProbeResult NetMonitor::GetThreadDetectResult(std::shared_ptr<ProbeThread>& probeThread, ProbeType probeType)
206 {
207     NetHttpProbeResult result;
208     if (!probeThread->IsDetecting()) {
209         if (probeType == ProbeType::PROBE_HTTP || probeType == ProbeType::PROBE_HTTP_FALLBACK) {
210             return probeThread->GetHttpProbeResult();
211         } else {
212             return probeThread->GetHttpsProbeResult();
213         }
214     }
215     return result;
216 }
217 
ProcessThreadDetectResult(NetHttpProbeResult & httpProbeResult,NetHttpProbeResult & httpsProbeResult,NetHttpProbeResult & fallbackHttpProbeResult,NetHttpProbeResult & fallbackHttpsProbeResult)218 NetHttpProbeResult NetMonitor::ProcessThreadDetectResult(NetHttpProbeResult& httpProbeResult,
219     NetHttpProbeResult& httpsProbeResult, NetHttpProbeResult& fallbackHttpProbeResult,
220     NetHttpProbeResult& fallbackHttpsProbeResult)
221 {
222     if (httpProbeResult.IsNeedPortal()) {
223         NETMGR_LOG_I("primary http detect result: portal");
224         return httpProbeResult;
225     }
226     if (fallbackHttpProbeResult.IsNeedPortal()) {
227         NETMGR_LOG_I("fallback http detect result: portal");
228         return fallbackHttpProbeResult;
229     }
230     if (httpsProbeResult.IsSuccessful()) {
231         NETMGR_LOG_I("primary https detect result: success");
232         return httpsProbeResult;
233     }
234     if (fallbackHttpsProbeResult.IsSuccessful()) {
235         NETMGR_LOG_I("fallback https detect result: success");
236         return fallbackHttpsProbeResult;
237     }
238     if (httpProbeResult.IsSuccessful() && fallbackHttpProbeResult.IsSuccessful()) {
239         NETMGR_LOG_I("both primary http and fallback http detect result success");
240         return httpProbeResult;
241     }
242     return httpsProbeResult;
243 }
244 
LoadGlobalHttpProxy()245 void NetMonitor::LoadGlobalHttpProxy()
246 {
247     NetHttpProxyTracker httpProxyTracker;
248     httpProxyTracker.ReadFromSettingsData(globalHttpProxy_);
249 }
250 
UpdateGlobalHttpProxy(const HttpProxy & httpProxy)251 void NetMonitor::UpdateGlobalHttpProxy(const HttpProxy &httpProxy)
252 {
253     std::unique_lock<std::mutex> proxyLocker(proxyMtx_);
254     globalHttpProxy_ = httpProxy;
255 }
256 
GetHttpProbeUrlFromConfig()257 void NetMonitor::GetHttpProbeUrlFromConfig()
258 {
259     if (!std::filesystem::exists(URL_CFG_FILE)) {
260         NETMGR_LOG_E("File not exist (%{public}s)", URL_CFG_FILE);
261         return;
262     }
263 
264     std::ifstream file(URL_CFG_FILE);
265     if (!file.is_open()) {
266         NETMGR_LOG_E("Open file failed (%{public}s)", strerror(errno));
267         return;
268     }
269 
270     std::ostringstream oss;
271     oss << file.rdbuf();
272     std::string content = oss.str();
273     auto pos = content.find(HTTP_URL_HEADER);
274     if (pos != std::string::npos) {
275         pos += HTTP_URL_HEADER.length();
276         httpUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
277     }
278 
279     pos = content.find(HTTPS_URL_HEADER);
280     if (pos != std::string::npos) {
281         pos += HTTPS_URL_HEADER.length();
282         httpsUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
283     }
284 
285     pos = content.find(FALLBACK_HTTP_URL_HEADER);
286     if (pos != std::string::npos) {
287         pos += FALLBACK_HTTP_URL_HEADER.length();
288         fallbackHttpUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
289     }
290 
291     pos = content.find(FALLBACK_HTTPS_URL_HEADER);
292     if (pos != std::string::npos) {
293         pos += FALLBACK_HTTPS_URL_HEADER.length();
294         fallbackHttpsUrl_ = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
295     }
296     NETMGR_LOG_D("Get net detection http url:[%{public}s], https url:[%{public}s], fallback http url:[%{public}s],"
297         " fallback https url:[%{public}s]", httpUrl_.c_str(), httpsUrl_.c_str(), fallbackHttpUrl_.c_str(),
298         fallbackHttpsUrl_.c_str());
299 }
300 
301 } // namespace NetManagerStandard
302 } // namespace OHOS
303