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