1 /*
2 * Copyright (c) 2022 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 <unistd.h>
20
21 #include "dns_config_client.h"
22 #include "dns_param_cache.h"
23 #include "netnative_log_wrapper.h"
24 #include "netsys_udp_transfer.h"
25 #include "singleton.h"
26
27 #include "dns_proxy_listen.h"
28
29 namespace OHOS {
30 namespace nmd {
31 uint16_t DnsProxyListen::netId_ = 0;
32 bool DnsProxyListen::proxyListenSwitch_ = false;
33 constexpr uint16_t DNS_PROXY_PORT = 53;
34 constexpr uint8_t RESPONSE_FLAG = 0x80;
35 constexpr uint8_t RESPONSE_FLAG_USED = 80;
36 constexpr size_t FLAG_BUFF_LEN = 1;
37 constexpr size_t FLAG_BUFF_OFFSET = 2;
DnsProxyListen()38 DnsProxyListen::DnsProxyListen() : proxySockFd_(-1) {}
~DnsProxyListen()39 DnsProxyListen::~DnsProxyListen()
40 {
41 if (proxySockFd_ > 0) {
42 close(proxySockFd_);
43 proxySockFd_ = -1;
44 }
45 }
46
DnsProxyGetPacket(int32_t clientSocket,RecvBuff recvBuff,sockaddr_in proxyAddr)47 void DnsProxyListen::DnsProxyGetPacket(int32_t clientSocket, RecvBuff recvBuff, sockaddr_in proxyAddr)
48 {
49 std::vector<std::string> servers;
50 std::vector<std::string> domains;
51 uint16_t baseTimeoutMsec;
52 uint8_t retryCount;
53 auto status = DelayedSingleton<DnsParamCache>::GetInstance()->GetResolverConfig(
54 DnsProxyListen::netId_, servers, domains, baseTimeoutMsec, retryCount);
55 if (status < 0) {
56 NETNATIVE_LOGE("GetResolvConfig failed set default server failed status:[%{poublic}d]", status);
57 return;
58 }
59 DnsParseBySocket(clientSocket, servers, recvBuff, proxyAddr);
60 }
61
DnsParseBySocket(int32_t clientSocket,std::vector<std::string> servers,RecvBuff recvBuff,sockaddr_in proxyAddr)62 void DnsProxyListen::DnsParseBySocket(int32_t clientSocket, std::vector<std::string> servers, RecvBuff recvBuff,
63 sockaddr_in proxyAddr)
64 {
65 int32_t parseSocketFd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP);
66 if (parseSocketFd < 0) {
67 NETNATIVE_LOGE("parseSocketFd create socket failed %{public}d", errno);
68 return;
69 }
70
71 if (!PollUdpDataTransfer::MakeUdpNonBlock(parseSocketFd)) {
72 NETNATIVE_LOGE("MakeNonBlock error %{public}d: %{public}s", errno, strerror(errno));
73 close(parseSocketFd);
74 return;
75 }
76 int32_t resLen;
77 socklen_t addrLen;
78 char requesData[MAX_REQUESTDATA_LEN] = {0};
79 sockaddr_in addrParse = {0};
80 uint32_t serversNum = 0;
81 while (serversNum < servers.size()) {
82 addrParse.sin_family = AF_INET;
83 addrParse.sin_addr.s_addr = inet_addr(servers[serversNum].c_str());
84 if (addrParse.sin_addr.s_addr == INADDR_NONE) {
85 NETNATIVE_LOGE("Input dns server [%{public}s] is not correct!", servers[serversNum].c_str());
86 serversNum++;
87 continue;
88 }
89 addrParse.sin_port = htons(DNS_PROXY_PORT);
90 if (PollUdpDataTransfer::PollUdpSendData(parseSocketFd, recvBuff.questionsBuff, recvBuff.questionLen, addrParse,
91 addrLen) < 0) {
92 NETNATIVE_LOGE("send failed %{public}d: %{public}s", errno, strerror(errno));
93 serversNum++;
94 continue;
95 }
96 addrLen = sizeof(addrParse);
97 resLen =
98 PollUdpDataTransfer::PollUdpRecvData(parseSocketFd, 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(parseSocketFd);
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(DnsProxyListen::DnsProxyGetPacket, proxySockFd_, recvBuff, proxyAddr).detach();
170 }
171 }
172
CheckDnsResponse(char * recBuff,size_t recLen)173 bool DnsProxyListen::CheckDnsResponse(char *recBuff, size_t recLen)
174 {
175 if (recLen < FLAG_BUFF_LEN + FLAG_BUFF_OFFSET) {
176 return false;
177 }
178 uint8_t flagBuff;
179 char *recFlagBuff = recBuff + FLAG_BUFF_OFFSET;
180 if (memcpy_s(reinterpret_cast<char *>(&flagBuff), FLAG_BUFF_LEN, recFlagBuff, FLAG_BUFF_LEN) != 0) {
181 return false;
182 }
183 int reqFlag = (flagBuff & RESPONSE_FLAG) / RESPONSE_FLAG_USED;
184 if (reqFlag) {
185 return true; // answer
186 } else {
187 return false; // question
188 }
189 }
190
DnsThreadClose()191 bool DnsProxyListen::DnsThreadClose()
192 {
193 return !DnsProxyListen::proxyListenSwitch_;
194 }
195
OnListen()196 void DnsProxyListen::OnListen()
197 {
198 DnsProxyListen::proxyListenSwitch_ = true;
199 NETNATIVE_LOG_D("endl OnListen");
200 }
201
OffListen()202 void DnsProxyListen::OffListen()
203 {
204 DnsProxyListen::proxyListenSwitch_ = false;
205 if (proxySockFd_ > 0) {
206 close(proxySockFd_);
207 proxySockFd_ = -1;
208 }
209 NETNATIVE_LOG_D("endl OffListen");
210 }
211
SetParseNetId(uint16_t netId)212 void DnsProxyListen::SetParseNetId(uint16_t netId)
213 {
214 DnsProxyListen::netId_ = netId;
215 NETNATIVE_LOG_D("endl SetParseNetId");
216 }
217 } // namespace nmd
218 } // namespace OHOS