• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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