• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 <netinet/ip.h>
17 #include <netinet/udp.h>
18 #include <thread>
19 #include <pthread.h>
20 #include <unistd.h>
21 
22 #include "dns_config_client.h"
23 #include "dns_param_cache.h"
24 #include "netnative_log_wrapper.h"
25 #include "netsys_udp_transfer.h"
26 #include "singleton.h"
27 
28 #include "dns_proxy_listen.h"
29 
30 namespace OHOS {
31 namespace nmd {
32 uint16_t DnsProxyListen::netId_ = 0;
33 bool DnsProxyListen::proxyListenSwitch_ = false;
34 constexpr uint16_t DNS_PROXY_PORT = 53;
35 constexpr uint8_t RESPONSE_FLAG = 0x80;
36 constexpr uint8_t RESPONSE_FLAG_USED = 80;
37 constexpr size_t FLAG_BUFF_LEN = 1;
38 constexpr size_t FLAG_BUFF_OFFSET = 2;
DnsProxyListen()39 DnsProxyListen::DnsProxyListen() : proxySockFd_(-1) {}
~DnsProxyListen()40 DnsProxyListen::~DnsProxyListen()
41 {
42     if (proxySockFd_ > 0) {
43         close(proxySockFd_);
44         proxySockFd_ = -1;
45     }
46 }
47 
DnsProxyGetPacket(int32_t clientSocket,RecvBuff recvBuff,sockaddr_in proxyAddr)48 void DnsProxyListen::DnsProxyGetPacket(int32_t clientSocket, RecvBuff recvBuff, sockaddr_in proxyAddr)
49 {
50     std::vector<std::string> servers;
51     std::vector<std::string> domains;
52     uint16_t baseTimeoutMsec;
53     uint8_t retryCount;
54     auto status = DelayedSingleton<DnsParamCache>::GetInstance()->GetResolverConfig(
55         DnsProxyListen::netId_, servers, domains, baseTimeoutMsec, retryCount);
56     if (status < 0) {
57         NETNATIVE_LOGE("GetResolvConfig failed set default server failed status:[%{poublic}d]", status);
58         return;
59     }
60     DnsParseBySocket(clientSocket, servers, recvBuff, proxyAddr);
61 }
62 
DnsParseBySocket(int32_t clientSocket,std::vector<std::string> servers,RecvBuff recvBuff,sockaddr_in proxyAddr)63 void DnsProxyListen::DnsParseBySocket(int32_t clientSocket, std::vector<std::string> servers, RecvBuff recvBuff,
64                                       sockaddr_in proxyAddr)
65 {
66     int32_t socketFd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP);
67     if (socketFd < 0) {
68         NETNATIVE_LOGE("socketFd create socket failed %{public}d", errno);
69         return;
70     }
71 
72     if (!PollUdpDataTransfer::MakeUdpNonBlock(socketFd)) {
73         NETNATIVE_LOGE("MakeNonBlock error  %{public}d: %{public}s", errno, strerror(errno));
74         close(socketFd);
75         return;
76     }
77     int32_t resLen = 0;
78     socklen_t addrLen;
79     char requesData[MAX_REQUESTDATA_LEN] = {0};
80     sockaddr_in addrParse = {0};
81     uint32_t serversNum = 0;
82     while (serversNum < servers.size()) {
83         addrParse.sin_family = AF_INET;
84         addrParse.sin_addr.s_addr = inet_addr(servers[serversNum].c_str());
85         if (addrParse.sin_addr.s_addr == INADDR_NONE) {
86             NETNATIVE_LOGE("Input dns server [%{public}s] is not correct!", servers[serversNum].c_str());
87             serversNum++;
88             continue;
89         }
90         addrParse.sin_port = htons(DNS_PROXY_PORT);
91         if (PollUdpDataTransfer::PollUdpSendData(socketFd, recvBuff.questionsBuff, recvBuff.questionLen, addrParse,
92                                                  addrLen) < 0) {
93             NETNATIVE_LOGE("send failed %{public}d: %{public}s", errno, strerror(errno));
94             serversNum++;
95             continue;
96         }
97         addrLen = sizeof(addrParse);
98         resLen = PollUdpDataTransfer::PollUdpRecvData(socketFd, requesData, MAX_REQUESTDATA_LEN, addrParse, addrLen);
99         if (resLen > 0) {
100             break;
101         }
102         if (!CheckDnsResponse(requesData, MAX_REQUESTDATA_LEN)) {
103             NETNATIVE_LOGE("read buff is not dns answer");
104             break;
105         }
106         if (serversNum == servers.size() - 1) {
107             return;
108         }
109         serversNum++;
110     }
111     close(socketFd);
112     if (resLen > 0) {
113         DnsSendRecvParseData(clientSocket, requesData, resLen, proxyAddr);
114     }
115 }
116 
DnsSendRecvParseData(int32_t clientSocket,char * requesData,int32_t resLen,sockaddr_in proxyAddr)117 void DnsProxyListen::DnsSendRecvParseData(int32_t clientSocket, char *requesData, int32_t resLen, sockaddr_in proxyAddr)
118 {
119     socklen_t addrLen = sizeof(proxyAddr);
120     if (PollUdpDataTransfer::PollUdpSendData(clientSocket, requesData, resLen, proxyAddr, addrLen) < 0) {
121         NETNATIVE_LOGE("send failed %{public}d: %{public}s", errno, strerror(errno));
122     }
123 }
124 
StartListen()125 void DnsProxyListen::StartListen()
126 {
127     RecvBuff recvBuff = {{0}};
128     NETNATIVE_LOG_D("StartListen proxySockFd_ : %{public}d", proxySockFd_);
129     if (proxySockFd_ < 0) {
130         proxySockFd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
131         if (proxySockFd_ < 0) {
132             NETNATIVE_LOGE("proxySockFd_ create socket failed %{public}d", errno);
133             return;
134         }
135     }
136 
137     sockaddr_in proxyAddr;
138     (void)memset_s(&proxyAddr, sizeof(proxyAddr), 0, sizeof(proxyAddr));
139     proxyAddr.sin_family = AF_INET;
140     proxyAddr.sin_addr.s_addr = htonl(INADDR_ANY);
141     proxyAddr.sin_port = htons(DNS_PROXY_PORT);
142 
143     if (bind(proxySockFd_, (sockaddr *)&proxyAddr, sizeof(proxyAddr)) == -1) {
144         NETNATIVE_LOGE("bind errno %{public}d: %{public}s", errno, strerror(errno));
145         close(proxySockFd_);
146         proxySockFd_ = -1;
147         return;
148     }
149     while (true) {
150         if (DnsThreadClose()) {
151             break;
152         }
153         (void)memset_s(recvBuff.questionsBuff, MAX_REQUESTDATA_LEN, 0, MAX_REQUESTDATA_LEN);
154         socklen_t len = sizeof(proxyAddr);
155         recvBuff.questionLen = recvfrom(proxySockFd_, recvBuff.questionsBuff, MAX_REQUESTDATA_LEN, 0,
156                                         reinterpret_cast<sockaddr *>(&proxyAddr), &len);
157         if (!(recvBuff.questionLen > 0)) {
158             NETNATIVE_LOGE("read errno %{public}d", errno);
159             continue;
160         }
161         if (CheckDnsResponse(recvBuff.questionsBuff, MAX_REQUESTDATA_LEN)) {
162             NETNATIVE_LOGE("read buff is not dns question");
163             continue;
164         }
165 
166         if (DnsThreadClose()) {
167             break;
168         }
169         std::thread t(DnsProxyListen::DnsProxyGetPacket, proxySockFd_, recvBuff, proxyAddr);
170         std::string threadName = "DnsPxyPacket";
171         pthread_setname_np(t.native_handle(), threadName.c_str());
172         t.detach();
173     }
174 }
175 
CheckDnsResponse(char * recBuff,size_t recLen)176 bool DnsProxyListen::CheckDnsResponse(char *recBuff, size_t recLen)
177 {
178     if (recLen < FLAG_BUFF_LEN + FLAG_BUFF_OFFSET) {
179         return false;
180     }
181     uint8_t flagBuff;
182     char *recFlagBuff = recBuff + FLAG_BUFF_OFFSET;
183     if (memcpy_s(reinterpret_cast<char *>(&flagBuff), FLAG_BUFF_LEN, recFlagBuff, FLAG_BUFF_LEN) != 0) {
184         return false;
185     }
186     int reqFlag = (flagBuff & RESPONSE_FLAG) / RESPONSE_FLAG_USED;
187     if (reqFlag) {
188         return true; // answer
189     } else {
190         return false; // question
191     }
192 }
193 
DnsThreadClose()194 bool DnsProxyListen::DnsThreadClose()
195 {
196     return !DnsProxyListen::proxyListenSwitch_;
197 }
198 
OnListen()199 void DnsProxyListen::OnListen()
200 {
201     DnsProxyListen::proxyListenSwitch_ = true;
202     NETNATIVE_LOG_D("endl OnListen");
203 }
204 
OffListen()205 void DnsProxyListen::OffListen()
206 {
207     DnsProxyListen::proxyListenSwitch_ = false;
208     if (proxySockFd_ > 0) {
209         close(proxySockFd_);
210         proxySockFd_ = -1;
211     }
212     NETNATIVE_LOG_D("endl OffListen");
213 }
214 
SetParseNetId(uint16_t netId)215 void DnsProxyListen::SetParseNetId(uint16_t netId)
216 {
217     DnsProxyListen::netId_ = netId;
218     NETNATIVE_LOG_D("endl SetParseNetId");
219 }
220 } // namespace nmd
221 } // namespace OHOS