• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 <fstream>
17 #include <sstream>
18 
19 #include "dns_quality_diag.h"
20 #include "third_party/musl/include/netdb.h"
21 #include "net_handle.h"
22 #include "net_conn_client.h"
23 
24 namespace OHOS::nmd {
25 namespace {
26 using namespace OHOS::NetsysNative;
27 }
28 
29 const char *DNS_DIAG_WORK_THREAD = "DNS_DIAG_WORK_THREAD";
30 const char *HW_HICLOUD_ADDR = "connectivitycheck.platform.hicloud.com";
31 const uint32_t MAX_RESULT_SIZE = 32;
32 const char *URL_CFG_FILE = "/system/etc/netdetectionurl.conf";
33 const char *DNS_URL_HEADER = "DnsProbeUrl:";
34 const char NEW_LINE_STR = '\n';
35 const uint32_t TIME_DELAY = 500;
36 
DnsQualityDiag()37 DnsQualityDiag::DnsQualityDiag()
38     : defaultNetId_(0),
39       monitor_loop_delay(TIME_DELAY),
40       report_delay(TIME_DELAY),
41       handler_started(false),
42       handler_(nullptr)
43 {
44     InitHandler();
45     load_query_addr(HW_HICLOUD_ADDR);
46 }
47 
GetInstance()48 DnsQualityDiag &DnsQualityDiag::GetInstance()
49 {
50     static DnsQualityDiag instance;
51     return instance;
52 }
53 
InitHandler()54 int32_t DnsQualityDiag::InitHandler()
55 {
56     if (handler_ == nullptr) {
57         std::shared_ptr<AppExecFwk::EventRunner> runner_ =
58             AppExecFwk::EventRunner::Create(DNS_DIAG_WORK_THREAD);
59         if (!runner_) {
60             NETNATIVE_LOGE("Create net policy work event runner.");
61         } else {
62             handler_ = std::make_shared<DnsQualityEventHandler>(runner_);
63         }
64     }
65     return 0;
66 }
67 
SendHealthReport(NetsysNative::NetDnsHealthReport healthreport)68 int32_t DnsQualityDiag::SendHealthReport(NetsysNative::NetDnsHealthReport healthreport)
69 {
70     for (auto cb: healthListeners_) {
71         cb->OnDnsHealthReport(healthreport);
72     }
73 
74     return 0;
75 }
ParseReportAddr(uint32_t size,AddrInfo * addrinfo,NetsysNative::NetDnsResultReport & report)76 int32_t DnsQualityDiag::ParseReportAddr(uint32_t size, AddrInfo* addrinfo, NetsysNative::NetDnsResultReport &report)
77 {
78     for (uint8_t i = 0; i < size; i++) {
79         NetsysNative::NetDnsResultAddrInfo ai;
80         AddrInfo *tmp = &(addrinfo[i]);
81         void* addr = NULL;
82         char c_addr[INET6_ADDRSTRLEN];
83         switch (tmp->aiFamily) {
84             case AF_INET:
85                 ai.type_ = NetsysNative::ADDR_TYPE_IPV4;
86                 addr = &(tmp->aiAddr.sin.sin_addr);
87                 break;
88             case AF_INET6:
89                 ai.type_ = NetsysNative::ADDR_TYPE_IPV6;
90                 addr = &(tmp->aiAddr.sin6.sin6_addr);
91                 break;
92         }
93         inet_ntop(tmp->aiFamily, addr, c_addr, sizeof(c_addr));
94         ai.addr_ = c_addr;
95         if (report.addrlist_.size() < MAX_RESULT_SIZE) {
96             report.addrlist_.push_back(ai);
97         } else {
98             break;
99         }
100     }
101     return 0;
102 }
103 
ReportDnsResult(uint16_t netId,uint16_t uid,uint32_t pid,int32_t usedtime,char * name,uint32_t size,int32_t failreason,QueryParam queryParam,AddrInfo * addrinfo)104 int32_t DnsQualityDiag::ReportDnsResult(uint16_t netId, uint16_t uid, uint32_t pid, int32_t usedtime,
105     char* name, uint32_t size, int32_t failreason, QueryParam queryParam, AddrInfo* addrinfo)
106 {
107     bool reportSizeReachLimit = (report_.size() >= MAX_RESULT_SIZE);
108 
109     NETNATIVE_LOG_D("ReportDnsResult: %{public}d, %{public}d, %{public}d, %{public}d, %{public}d, %{public}d",
110                     netId, uid, pid, usedtime, size, failreason);
111 
112     if (!reportSizeReachLimit) {
113         NetsysNative::NetDnsResultReport report;
114         report.netid_ = netId;
115         report.uid_ = uid;
116         report.pid_ = pid;
117         report.timeused_ = usedtime;
118         report.queryresult_ = failreason;
119         report.host_ = name;
120         if (failreason == 0) {
121             ParseReportAddr(size, addrinfo, report);
122         }
123         NETNATIVE_LOG_D("ReportDnsResult: %{public}s", report.host_.c_str());
124         std::shared_ptr<NetsysNative::NetDnsResultReport> rpt =
125             std::make_shared<NetsysNative::NetDnsResultReport>(report);
126         auto event = AppExecFwk::InnerEvent::Get(DnsQualityEventHandler::MSG_DNS_NEW_REPORT, rpt);
127         handler_->SendEvent(event);
128     }
129 
130     return 0;
131 }
132 
RegisterResultListener(const sptr<INetDnsResultCallback> & callback,uint32_t timeStep)133 int32_t DnsQualityDiag::RegisterResultListener(const sptr<INetDnsResultCallback> &callback, uint32_t timeStep)
134 {
135     report_delay = std::max(report_delay, timeStep);
136     resultListeners_.push_back(callback);
137 
138     if (handler_started != true) {
139         handler_started = true;
140         handler_->SendEvent(DnsQualityEventHandler::MSG_DNS_REPORT_LOOP, report_delay);
141 #if NETSYS_DNS_MONITOR
142         handler_->SendEvent(DnsQualityEventHandler::MSG_DNS_MONITOR_LOOP, monitor_loop_delay);
143 #endif
144     }
145     NETNATIVE_LOG_D("RegisterResultListener, %{public}d", report_delay);
146 
147     return 0;
148 }
149 
UnregisterResultListener(const sptr<INetDnsResultCallback> & callback)150 int32_t DnsQualityDiag::UnregisterResultListener(const sptr<INetDnsResultCallback> &callback)
151 {
152     resultListeners_.remove(callback);
153     if (resultListeners_.empty()) {
154         handler_started = false;
155     }
156     NETNATIVE_LOG_D("UnregisterResultListener");
157 
158     return 0;
159 }
160 
RegisterHealthListener(const sptr<INetDnsHealthCallback> & callback)161 int32_t DnsQualityDiag::RegisterHealthListener(const sptr<INetDnsHealthCallback> &callback)
162 {
163     healthListeners_.push_back(callback);
164     handler_started = true;
165     handler_->SendEvent(DnsQualityEventHandler::MSG_DNS_MONITOR_LOOP, monitor_loop_delay);
166 
167     return 0;
168 }
169 
UnregisterHealthListener(const sptr<INetDnsHealthCallback> & callback)170 int32_t DnsQualityDiag::UnregisterHealthListener(const sptr<INetDnsHealthCallback> &callback)
171 {
172     healthListeners_.remove(callback);
173     if (healthListeners_.empty()) {
174         handler_started = false;
175     }
176 
177     return 0;
178 }
179 
SetLoopDelay(int32_t delay)180 int32_t DnsQualityDiag::SetLoopDelay(int32_t delay)
181 {
182     monitor_loop_delay = delay;
183     return 0;
184 }
185 
query_default_host()186 int32_t DnsQualityDiag::query_default_host()
187 {
188 #if NETSYS_DNS_MONITOR
189     struct addrinfo *res;
190     struct queryparam param;
191     param.qp_type = 1;
192 #endif
193 
194     OHOS::NetManagerStandard::NetHandle netHandle;
195     OHOS::NetManagerStandard::NetConnClient::GetInstance().GetDefaultNet(netHandle);
196     int netid = netHandle.GetNetId();
197 
198     NETNATIVE_LOG_D("query_default_host: %{public}d, ", netid);
199 
200 #if NETSYS_DNS_MONITOR
201     param.qp_netid = netid;
202     getaddrinfo_ext(queryAddr.c_str(), NULL, NULL, &res, &param);
203     freeaddrinfo(res);
204 #endif
205 
206     return 0;
207 }
208 
handle_dns_loop()209 int32_t DnsQualityDiag::handle_dns_loop()
210 {
211     if (handler_started) {
212         if (report_.size() == 0) {
213             query_default_host();
214         }
215         handler_->SendEvent(DnsQualityEventHandler::MSG_DNS_MONITOR_LOOP, monitor_loop_delay);
216     }
217     return 0;
218 }
219 
handle_dns_fail()220 int32_t DnsQualityDiag::handle_dns_fail()
221 {
222     if (handler_started) {
223         query_default_host();
224     }
225     return 0;
226 }
227 
send_dns_report()228 int32_t DnsQualityDiag::send_dns_report()
229 {
230     if (!handler_started) {
231         report_.clear();
232         return 0;
233     }
234 
235     if (report_.size() > 0) {
236         std::list<NetsysNative::NetDnsResultReport> reportSend(report_);
237         report_.clear();
238         NETNATIVE_LOG_D("send_dns_report (%{public}u)", reportSend.size());
239         for (auto cb: resultListeners_) {
240             NETNATIVE_LOGI("send_dns_report cb)");
241             cb->OnDnsResultReport(reportSend.size(), reportSend);
242         }
243     }
244     handler_->SendEvent(DnsQualityEventHandler::MSG_DNS_REPORT_LOOP, report_delay);
245     return 0;
246 }
247 
add_dns_report(std::shared_ptr<NetsysNative::NetDnsResultReport> report)248 int32_t DnsQualityDiag::add_dns_report(std::shared_ptr<NetsysNative::NetDnsResultReport> report)
249 {
250     NETNATIVE_LOGI("add_dns_report (%{public}s)", report->host_.c_str());
251     if (report_.size() < MAX_RESULT_SIZE) {
252         report_.push_back(*report);
253     }
254     return 0;
255 }
256 
load_query_addr(const char * defaultAddr)257 int32_t DnsQualityDiag::load_query_addr(const char* defaultAddr)
258 {
259     if (!std::filesystem::exists(URL_CFG_FILE)) {
260         NETNATIVE_LOGE("File not exist (%{public}s)", URL_CFG_FILE);
261         queryAddr = defaultAddr;
262         return 0;
263     }
264 
265     std::ifstream file(URL_CFG_FILE);
266     if (!file.is_open()) {
267         NETNATIVE_LOGE("Open file failed (%{public}s)", strerror(errno));
268         queryAddr = defaultAddr;
269         return 0;
270     }
271 
272     std::ostringstream oss;
273     oss << file.rdbuf();
274     std::string content = oss.str();
275     auto pos = content.find(DNS_URL_HEADER);
276     if (pos != std::string::npos) {
277         pos += strlen(DNS_URL_HEADER);
278         queryAddr = content.substr(pos, content.find(NEW_LINE_STR, pos) - pos);
279     } else {
280         queryAddr = defaultAddr;
281     }
282     NETNATIVE_LOG_D("Get queryAddr url:[%{public}s]]", queryAddr.c_str());
283 
284     return 0;
285 }
286 
HandleEvent(const AppExecFwk::InnerEvent::Pointer & event)287 int32_t DnsQualityDiag::HandleEvent(const AppExecFwk::InnerEvent::Pointer &event)
288 {
289     if (!handler_started) {
290         NETNATIVE_LOGI("DnsQualityDiag Handler not started");
291         return 0;
292     }
293     NETNATIVE_LOG_D("DnsQualityDiag Handler event: %{public}d", event->GetInnerEventId());
294 
295     switch (event->GetInnerEventId()) {
296         case DnsQualityEventHandler::MSG_DNS_MONITOR_LOOP:
297             handle_dns_loop();
298             break;
299         case DnsQualityEventHandler::MSG_DNS_QUERY_FAIL:
300             handle_dns_fail();
301             break;
302         case DnsQualityEventHandler::MSG_DNS_REPORT_LOOP:
303             send_dns_report();
304             break;
305         case DnsQualityEventHandler::MSG_DNS_NEW_REPORT:
306             auto report = event->GetSharedObject<NetsysNative::NetDnsResultReport>();
307             add_dns_report(report);
308             break;
309     }
310     return 0;
311 }
312 } // namespace OHOS::nmd
313