• 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 "dns_lookup_name.h"
17 
18 #include "fwmark_client.h"
19 #include "net_manager_constants.h"
20 
21 namespace OHOS {
22 namespace nmd {
23 using namespace NetManagerStandard;
24 static constexpr int32_t HOST_NAME_LEN = 10;
25 static constexpr int32_t TEMPORARY_FAILURE = 2;
26 static constexpr int32_t NO_ERROR = 3;
27 
28 static constexpr uint32_t ADDR_SECOND_LAST_BIT = 15;
29 static constexpr int32_t PREFIX_SIZE = 128;
30 static constexpr int32_t PREFIX_LEN = 8;
31 static constexpr int32_t BUFF_NUM = 2;
32 
33 static constexpr int32_t ALENS_MAX_LEN = 4;
34 static constexpr int32_t SEARCH_MAX_LEN = 256;
35 
36 static constexpr int32_t DAS_USABLE = 0x40000000;
37 static constexpr int32_t DAS_MATCHINGSCOPE = 0x20000000;
38 static constexpr int32_t DAS_MATCHINGLABEL = 0x10000000;
39 static constexpr int32_t DAS_PREC_SHIFT = 20;
40 static constexpr int32_t DAS_SCOPE_SHIFT = 16;
41 static constexpr int32_t DAS_PREFIX_SHIFT = 8;
42 static constexpr int32_t DAS_ORDER_SHIFT = 0;
43 static constexpr int32_t NAMESERVICES_LEN = 12;
44 static constexpr int32_t ADDR_LEN = 4;
45 static constexpr int32_t CNT_NUM = 2;
46 
47 static constexpr int32_t SCOPEOF_RESULT_2 = 2;
48 static constexpr int32_t SCOPEOF_RESULT_5 = 5;
49 static constexpr int32_t SCOPEOF_RESULT_14 = 14;
50 static constexpr int32_t DSCOPE_MAX_LEN = 15;
51 
52 static const struct policy {
53     uint8_t addr[ADDR_A6_LEN];
54     uint8_t len;
55     uint8_t mask;
56     uint8_t prec;
57     uint8_t label;
58 } DEF_POLICY[] = {
59     {{'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\1'}, 15, 0xff, 50, 0},
60     {"\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4},
61     {"\x20\2", 1, 0xff, 30, 2},
62     {"\x20\1", 3, 0xff, 5, 5},
63     {"\xfc", 0, 0xfe, 3, 13},
64     {"", 0, 0, 40, 1},
65 };
66 
NameFromNull(AddrData buf[SECOND_ADDR_IN_BUFF],const std::string name,int32_t family,int32_t flags)67 int32_t DnsLookUpName::NameFromNull(AddrData buf[SECOND_ADDR_IN_BUFF], const std::string name, int32_t family,
68                                     int32_t flags)
69 {
70     if (!name.empty()) {
71         return DNS_ERR_NONE;
72     }
73     int32_t cnt = 0;
74     if (static_cast<uint32_t>(flags) & AI_PASSIVE) {
75         if (family != AF_INET6) {
76             buf[cnt++] = (AddrData){.family = AF_INET};
77         }
78         if (family != AF_INET) {
79             buf[cnt++] = (AddrData){.family = AF_INET6};
80         }
81     } else {
82         if (family != AF_INET6) {
83             buf[cnt++] = (AddrData){.family = AF_INET, .addr = {127, 0, 0, 1}};
84         }
85         if (family != AF_INET) {
86             buf[cnt] = (AddrData){.family = AF_INET6};
87             buf[cnt].addr[ADDR_SECOND_LAST_BIT] = ADDR_FIRST_BIT;
88             ++cnt;
89         }
90     }
91     NETNATIVE_LOG_D("NameFromNull cnt %{public}d", cnt);
92     return cnt;
93 }
94 
NameFromNumeric(AddrData buf[ADDR_FIRST_BIT],const std::string name,int32_t family)95 int32_t DnsLookUpName::NameFromNumeric(AddrData buf[ADDR_FIRST_BIT], const std::string name, int32_t family)
96 {
97     return DnsLookUpParse().LookupIpLiteral(buf, name, family);
98 }
99 
ProcessMdnsFailed(int32_t answersLens[],uint8_t answersBuf[][PACKET_LINE])100 int32_t DnsLookUpName::ProcessMdnsFailed(int32_t answersLens[], uint8_t answersBuf[][PACKET_LINE])
101 {
102     if (answersLens[ARG_INDEX_0] < ALENS_MAX_LEN ||
103         (answersBuf[ARG_INDEX_0][ARG_INDEX_3] & ADDR_SECOND_LAST_BIT) == TEMPORARY_FAILURE) {
104         NETNATIVE_LOGE("NameFromDns failed try again");
105         return EAI_AGAIN;
106     }
107     if ((answersBuf[ARG_INDEX_0][ARG_INDEX_3] & ADDR_SECOND_LAST_BIT) == SERVER_FAILURE) {
108         NETNATIVE_LOGE("NameFromDns failed return server failure");
109         return EAI_NONAME;
110     }
111     if ((answersBuf[ARG_INDEX_0][ARG_INDEX_3] & ADDR_SECOND_LAST_BIT) == NO_ERROR) {
112         return DNS_ERR_NONE;
113     }
114     NETNATIVE_LOGE("NameFromDns failed non-recoverable failure in name res.");
115     return EAI_FAIL;
116 }
117 
NameFromDns(AddrData buf[MAXADDRS],char canon[CANON_LINE],const std::string name,int32_t family,const ResolvConf * conf,uint16_t netId)118 int32_t DnsLookUpName::NameFromDns(AddrData buf[MAXADDRS], char canon[CANON_LINE], const std::string name,
119                                    int32_t family, const ResolvConf *conf, uint16_t netId)
120 {
121     static const struct {
122         int32_t af;
123         int32_t rr;
124     } afrr[BUFF_NUM] = {
125         {.af = AF_INET6, .rr = RR_A},
126         {.af = AF_INET, .rr = RR_AAAA},
127     };
128     uint8_t queriesBuf[ARG_INDEX_2][BUFF_MAX_LEN];
129     uint8_t answersBuf[ARG_INDEX_2][PACKET_LINE];
130     int32_t queriesLens[ARG_INDEX_2];
131     int32_t answersLens[ARG_INDEX_2];
132     int32_t queriesNum = 0;
133     for (int32_t i = 0; i < BUFF_NUM; i++) {
134         if (family != afrr[i].af) {
135             queriesLens[queriesNum] = DnsLookUpParse().ResMkQuery(0, name, 1, afrr[i].rr, nullptr, 0, nullptr,
136                                                                   queriesBuf[queriesNum], sizeof(*queriesBuf));
137             if (queriesLens[queriesNum] == -1) {
138                 NETNATIVE_LOGE("NameFromDns failed  to make query");
139                 return EAI_NONAME;
140             }
141             queriesNum++;
142         }
143     }
144     const uint8_t *queries[ARG_INDEX_2] = {queriesBuf[ARG_INDEX_0], queriesBuf[ARG_INDEX_1]};
145     uint8_t *answers[ARG_INDEX_2] = {answersBuf[ARG_INDEX_0], answersBuf[ARG_INDEX_1]};
146     if (DnsLookUpParse().ResMSendRc(queriesNum, queries, queriesLens, answers, answersLens, sizeof(*answersBuf), conf,
147                                     netId) < 0) {
148         NETNATIVE_LOGE("NameFromDns failed return to send or recv data");
149         return EAI_SYSTEM;
150     }
151 
152     DpcCtx ctx = {.addrs = buf, .canon = canon};
153     for (int32_t i = 0; i < queriesNum; i++) {
154         DnsLookUpParse().DnsParse(answersBuf[i], answersLens[i], DnsLookUpParse().DnsParseCallback, &ctx);
155     }
156 
157     if (ctx.cnt) {
158         return ctx.cnt;
159     }
160     return ProcessMdnsFailed(answersLens, answersBuf);
161 }
162 
NameFromDnsSearch(AddrData buf[MAXADDRS],char canon[CANON_LINE],const std::string name,int32_t family,uint16_t netId)163 int32_t DnsLookUpName::NameFromDnsSearch(AddrData buf[MAXADDRS], char canon[CANON_LINE], const std::string name,
164                                          int32_t family, uint16_t netId)
165 {
166     char search[SEARCH_MAX_LEN] = {0};
167     ResolvConf conf{};
168     if (DnsLookUpParse().GetResolvConf(&conf, search, sizeof(search), netId) < 0 || name.empty()) {
169         NETNATIVE_LOGE("Get resolv from conf failed or the param name is empty.");
170         return EAI_NONAME;
171     }
172 
173     size_t nameLen;
174     auto ret = NameFromDnsSearch(nameLen, name, conf, search, canon);
175     if (ret != 0) {
176         return ret;
177     }
178     char *pos;
179     char *temp;
180     for (pos = search; *pos; pos = temp) {
181         for (; isspace(*pos); pos++) {
182         };
183         for (temp = pos; *temp && !isspace(*temp); temp++) {
184         };
185         if (temp == pos) {
186             break;
187         }
188         if (temp - pos < static_cast<long>(SEARCH_MAX_LEN - LOOKUP_NAME_ONE) - static_cast<long>(nameLen)) {
189             uint32_t cannonAddLen = nameLen + LOOKUP_NAME_ONE;
190             uint32_t posLen = temp - pos;
191             if (memcpy_s(canon + cannonAddLen, posLen, pos, posLen) != 0) {
192                 NETNATIVE_LOGE("memcpy_s faild");
193                 return NETMANAGER_ERR_MEMCPY_FAIL;
194             }
195             canon[temp - pos + LOOKUP_NAME_ONE + nameLen] = LOOKUP_NAME_ZERO;
196             int32_t cnt = NameFromDns(buf, canon, canon, family, &conf, netId);
197             if (cnt) {
198                 return cnt;
199             }
200         }
201     }
202 
203     canon[nameLen] = LOOKUP_NAME_ZERO;
204     return NameFromDns(buf, canon, name, family, &conf, netId);
205 }
206 
NameFromDnsSearch(size_t & nameLen,const std::string name,ResolvConf conf,char search[],char canon[])207 int32_t DnsLookUpName::NameFromDnsSearch(size_t &nameLen, const std::string name, ResolvConf conf, char search[],
208                                          char canon[])
209 {
210     size_t dots;
211     for (dots = nameLen = 0; name[nameLen]; nameLen++) {
212         if (name[nameLen] == DOT) {
213             dots++;
214         }
215     }
216     if (dots >= conf.nDots || name[nameLen - LOOKUP_NAME_ONE] == DOT) {
217         *search = LOOKUP_NAME_ZERO;
218     }
219 
220     if (name[nameLen - LOOKUP_NAME_ONE] == DOT) {
221         nameLen--;
222     }
223     if (!nameLen || name[nameLen - LOOKUP_NAME_ONE] == DOT || nameLen >= SEARCH_MAX_LEN) {
224         NETNATIVE_LOGE("name is unknown");
225         return EAI_NONAME;
226     }
227     if (strcpy_s(canon, name.length() + 1, name.c_str()) != 0) {
228         return EAI_AGAIN;
229     }
230     canon[nameLen] = DOT;
231     return 0;
232 }
PolicyOf(const in6_addr * in6Addr)233 const struct policy *DnsLookUpName::PolicyOf(const in6_addr *in6Addr)
234 {
235     for (int32_t i = 0;; i++) {
236         if (memcmp(in6Addr->s6_addr, DEF_POLICY[i].addr, DEF_POLICY[i].len)) {
237             continue;
238         }
239         if ((in6Addr->s6_addr[DEF_POLICY[i].len] & DEF_POLICY[i].mask) != DEF_POLICY[i].addr[DEF_POLICY[i].len]) {
240             continue;
241         }
242         return DEF_POLICY + i;
243     }
244     return {};
245 }
246 
LabelOf(const in6_addr * in6Addr)247 int32_t DnsLookUpName::LabelOf(const in6_addr *in6Addr)
248 {
249     return PolicyOf(in6Addr)->label;
250 }
251 
ScopeOf(const in6_addr * in6Addr)252 int32_t DnsLookUpName::ScopeOf(const in6_addr *in6Addr)
253 {
254     if (IN6_IS_ADDR_MULTICAST(in6Addr)) {
255         return in6Addr->s6_addr[ARG_INDEX_1] & DSCOPE_MAX_LEN;
256     }
257     if (IN6_IS_ADDR_LINKLOCAL(in6Addr)) {
258         return SCOPEOF_RESULT_2;
259     }
260     if (IN6_IS_ADDR_LOOPBACK(in6Addr)) {
261         return SCOPEOF_RESULT_2;
262     }
263     if (IN6_IS_ADDR_SITELOCAL(in6Addr)) {
264         return SCOPEOF_RESULT_5;
265     }
266     return SCOPEOF_RESULT_14;
267 }
268 
PreFixMatch(const in6_addr * s,const in6_addr * d)269 int32_t DnsLookUpName::PreFixMatch(const in6_addr *s, const in6_addr *d)
270 {
271     int32_t i;
272     for (i = 0; i < PREFIX_SIZE &&
273                 !((s->s6_addr[i / PREFIX_LEN] ^ d->s6_addr[i / PREFIX_LEN]) & (PREFIX_SIZE >> (i % PREFIX_LEN)));
274          i++) {
275     };
276     return i;
277 }
278 
AddrCmp(const void * addrA,const void * addrB)279 int32_t DnsLookUpName::AddrCmp(const void *addrA, const void *addrB)
280 {
281     const auto *a = static_cast<const AddrData *>(addrA);
282     const auto *b = static_cast<const AddrData *>(addrB);
283     return b->sortKey - a->sortKey;
284 }
285 
CheckNameParam(const std::string name,int32_t & flags,int32_t & family)286 int32_t DnsLookUpName::CheckNameParam(const std::string name, int32_t &flags, int32_t &family)
287 {
288     if (!name.empty()) {
289         size_t len = name.length() > HOST_MAX_LEN ? HOST_MAX_LEN : name.length();
290         if (len - 1 >= HOST_MAX_LEN_MINUS_ONE) {
291             NETNATIVE_LOGE("name is too long : %{public}d", static_cast<int32_t>(len));
292             return EAI_NONAME;
293         }
294     }
295 
296     if (static_cast<uint32_t>(flags) & AI_V4MAPPED) {
297         if (family == AF_INET6) {
298             family = AF_UNSPEC;
299         } else {
300             flags -= AI_V4MAPPED;
301         }
302     }
303     return DNS_ERR_NONE;
304 }
305 
RefreshBuf(AddrData * buf,int32_t num,int32_t & cnt)306 void DnsLookUpName::RefreshBuf(AddrData *buf, int32_t num, int32_t &cnt)
307 {
308     int32_t j = 0;
309     for (j = 0; num < cnt; num++) {
310         if (buf[num].family == AF_INET6) {
311             buf[j++] = buf[num];
312         }
313     }
314     cnt = j;
315 }
316 
UpdateBuf(int32_t flags,int32_t family,AddrData * buf,int32_t & cnt)317 bool DnsLookUpName::UpdateBuf(int32_t flags, int32_t family, AddrData *buf, int32_t &cnt)
318 {
319     if ((static_cast<uint32_t>(flags) & AI_V4MAPPED)) {
320         int32_t i = 0;
321         if (!(static_cast<uint32_t>(flags) & AI_ALL)) {
322             for (; i < cnt && buf[i].family != AF_INET6; i++) {
323             };
324             if (i < cnt) {
325                 RefreshBuf(buf, i, cnt);
326             }
327         }
328         for (i = 0; i < cnt; i++) {
329             if (buf[i].family != AF_INET) {
330                 continue;
331             }
332             int32_t ret = memcpy_s(buf[i].addr + NAMESERVICES_LEN, ADDR_LEN, buf[i].addr, ADDR_LEN);
333             ret += memcpy_s(buf[i].addr, NAMESERVICES_LEN, ADDR_BUF, NAMESERVICES_LEN);
334             if (ret != 0) {
335                 NETNATIVE_LOGE("memcpy_s faild");
336                 return false;
337             }
338             buf[i].family = AF_INET6;
339         }
340     }
341     if (cnt < CNT_NUM || family == AF_INET) {
342         NETNATIVE_LOGE("cnt is less two or there are only IPv4 results, cnt : %{public}d", cnt);
343         return false;
344     }
345     int32_t i = 0;
346     for (i = 0; i < cnt; i++) {
347         if (buf[i].family != AF_INET) {
348             break;
349         }
350     }
351     return i != cnt;
352 }
353 
SockAddrCopy(ScokAddrCopy addrBuff,void * da,void * sa,int32_t & dScope,int32_t & preFixLen,uint32_t & key)354 void DnsLookUpName::SockAddrCopy(ScokAddrCopy addrBuff, void *da, void *sa, int32_t &dScope, int32_t &preFixLen,
355                                  uint32_t &key)
356 {
357     if (!connect(addrBuff.lookUpNameFd, static_cast<sockaddr *>(da), addrBuff.daLen)) {
358         key = key | DAS_USABLE;
359         int32_t res = getsockname(addrBuff.lookUpNameFd, static_cast<sockaddr *>(sa), &addrBuff.saLen);
360         if (res) {
361             (void)close(addrBuff.lookUpNameFd);
362             return;
363         }
364         if (addrBuff.family == AF_INET) {
365             if (memcpy_s(addrBuff.sa6.sin6_addr.s6_addr + NAMESERVICES_LEN, ADDR_A4_LEN, &addrBuff.sa4.sin_addr,
366                          ADDR_A4_LEN) != 0) {
367                 NETNATIVE_LOGE("memcpy_s faild");
368                 return;
369             }
370         }
371         if (dScope == ScopeOf(&addrBuff.sa6.sin6_addr)) {
372             key = key | DAS_MATCHINGSCOPE;
373         }
374         if (addrBuff.dLabel == LabelOf(&addrBuff.sa6.sin6_addr)) {
375             key = key | DAS_MATCHINGLABEL;
376         }
377         preFixLen = PreFixMatch(&addrBuff.sa6.sin6_addr, &addrBuff.da6.sin6_addr);
378     }
379     (void)close(addrBuff.lookUpNameFd);
380 }
381 
FindName(AddrData * buf,char * canon,const std::string name,int32_t family,int32_t flags,uint16_t netId)382 int32_t DnsLookUpName::FindName(AddrData *buf, char *canon, const std::string name, int32_t family, int32_t flags,
383                                 uint16_t netId)
384 {
385     int32_t cnt = NameFromNull(buf, name, family, flags);
386     if (!cnt) {
387         cnt = NameFromNumeric(buf, name, family);
388     }
389     if (!cnt && !(static_cast<uint32_t>(flags) & AI_NUMERICHOST)) {
390         cnt = NameFromDnsSearch(buf, canon, name.c_str(), family, netId);
391     }
392     NETNATIVE_LOG_D("FindName cnt : %{public}d", cnt);
393     return cnt;
394 }
395 
MemcpySockaddr(sockaddr_in6 & sa6,sockaddr_in6 & da6,sockaddr_in & da4,AddrData * buf,uint32_t cnt)396 int32_t DnsLookUpName::MemcpySockaddr(sockaddr_in6 &sa6, sockaddr_in6 &da6, sockaddr_in &da4, AddrData *buf,
397                                       uint32_t cnt)
398 {
399     int32_t ret = memcpy_s(sa6.sin6_addr.s6_addr, NAMESERVICES_LEN, ADDR_BUF, NAMESERVICES_LEN);
400     ret += memcpy_s(da6.sin6_addr.s6_addr + NAMESERVICES_LEN, ADDR_A4_LEN, buf[cnt].addr, ADDR_A4_LEN);
401     ret += memcpy_s(da6.sin6_addr.s6_addr, NAMESERVICES_LEN, ADDR_BUF, NAMESERVICES_LEN);
402     ret += memcpy_s(da6.sin6_addr.s6_addr + NAMESERVICES_LEN, ADDR_A4_LEN, buf[cnt].addr, ADDR_A4_LEN);
403     ret += memcpy_s(&da4.sin_addr, ADDR_A4_LEN, buf[cnt].addr, ADDR_A4_LEN);
404     if (ret != 0) {
405         NETNATIVE_LOGE("memcpy_s faild");
406         return -1;
407     }
408     return 0;
409 }
410 
LookUpNameParam(AddrData * buf,int32_t cnt,int32_t netId)411 void DnsLookUpName::LookUpNameParam(AddrData *buf, int32_t cnt, int32_t netId)
412 {
413     for (int32_t i = 0; i < cnt; i++) {
414         int32_t family = buf[i].family;
415         uint32_t key = 0;
416         sockaddr_in6 sa6 = {0};
417         sockaddr_in6 da6 = {.sin6_family = AF_INET6, .sin6_port = PORT_NUM, .sin6_scope_id = buf[i].scopeid};
418         sockaddr_in sa4 = {0};
419         sockaddr_in da4 = {.sin_family = AF_INET, .sin_port = PORT_NUM};
420         void *sa;
421         void *da;
422         socklen_t saLen;
423         socklen_t daLen;
424         if (family == AF_INET6) {
425             if (memcpy_s(da6.sin6_addr.s6_addr, ADDR_A6_LEN, buf[i].addr, ADDR_A6_LEN) != 0) {
426                 NETNATIVE_LOGE("memcpy_s faild");
427                 return;
428             }
429             da = &da6;
430             daLen = sizeof(da6);
431             sa = &sa6;
432             saLen = sizeof(da6);
433         } else {
434             if (MemcpySockaddr(sa6, da6, da4, buf, i) < 0) {
435                 return;
436             }
437             da = &da4;
438             daLen = sizeof(da4);
439             sa = &sa4;
440             saLen = sizeof(sa4);
441         }
442         const policy *dPolicy = PolicyOf(&da6.sin6_addr);
443         int32_t dScope = ScopeOf(&da6.sin6_addr);
444         int32_t dLabel = dPolicy->label;
445         uint32_t dPrec = dPolicy->prec;
446         int32_t preFixLen = 0;
447         int32_t lookUpNameFd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
448         if (lookUpNameFd >= 0) {
449             ScokAddrCopy addrBuff = {.lookUpNameFd = lookUpNameFd, .sa6 = sa6, .da6 = da6, .sa4 = sa4,
450                 .saLen = saLen, .daLen = daLen, .dLabel = dLabel, .family = family};
451             SockAddrCopy(addrBuff, da, sa, dScope, preFixLen, key);
452         }
453         key |= dPrec << DAS_PREC_SHIFT;
454         key |= static_cast<uint32_t>(DSCOPE_MAX_LEN - dScope) << DAS_SCOPE_SHIFT;
455         key |= static_cast<uint32_t>(preFixLen) << DAS_PREFIX_SHIFT;
456         key |= static_cast<uint32_t>(MAXADDRS - i) << DAS_ORDER_SHIFT;
457         buf[i].sortKey = static_cast<int32_t>(key);
458     }
459 }
460 
LookUpName(AddrData buf[MAXADDRS],char canon[CANON_LINE],const std::string & name,int32_t family,int32_t flags,uint16_t netId)461 int32_t DnsLookUpName::LookUpName(AddrData buf[MAXADDRS], char canon[CANON_LINE], const std::string &name,
462                                   int32_t family, int32_t flags, uint16_t netId)
463 {
464     *canon = 0;
465     int32_t error = CheckNameParam(name, flags, family);
466     if (error < 0) {
467         return error;
468     }
469     int32_t cnt = FindName(buf, canon, name, family, flags, netId);
470     if (cnt <= 0) {
471         NETNATIVE_LOGE("find name failed: %{public}d", cnt);
472         return cnt ? cnt : EAI_NONAME;
473     }
474 
475     if (!UpdateBuf(flags, family, buf, cnt)) {
476         return cnt;
477     }
478 
479     LookUpNameParam(buf, cnt, netId);
480     qsort(buf, cnt, sizeof(*buf), AddrCmp);
481 
482     return cnt;
483 }
484 
SwitchSocketType(int32_t sockType,const std::string name,int32_t & proto,ServData * buf)485 int32_t DnsLookUpName::SwitchSocketType(int32_t sockType, const std::string name, int32_t &proto, ServData *buf)
486 {
487     switch (sockType) {
488         case SOCK_STREAM:
489             switch (proto) {
490                 case 0:
491                     proto = IPPROTO_TCP;
492                     [[fallthrough]];
493                 case IPPROTO_TCP:
494                     break;
495                 default:
496                     return EAI_SERVICE;
497             }
498             break;
499         case SOCK_DGRAM:
500             switch (proto) {
501                 case 0:
502                     proto = IPPROTO_UDP;
503                     [[fallthrough]];
504                 case IPPROTO_UDP:
505                     break;
506                 default:
507                     return EAI_SERVICE;
508             }
509             [[fallthrough]];
510         case 0:
511             break;
512         default:
513             if (!name.empty()) {
514                 return EAI_SERVICE;
515             }
516             buf[0].port = 0;
517             buf[0].proto = proto;
518             buf[0].sockType = sockType;
519             break;
520     }
521     return DNS_ERR_NONE;
522 }
523 
LookUpServer(ServData buf[MAXSERVS],const std::string name,int32_t proto,int32_t sockType,int32_t flags)524 int32_t DnsLookUpName::LookUpServer(ServData buf[MAXSERVS], const std::string name, int32_t proto, int32_t sockType,
525                                     int32_t flags)
526 {
527     char* end = nullptr;
528     unsigned long port = 0;
529     int32_t error = SwitchSocketType(sockType, name, proto, buf);
530     if (error < 0) {
531         return error;
532     }
533     const char *serv = (name.length() > 0 ? name.c_str() : nullptr);
534     if (serv) {
535         if (!*serv) {
536             return EAI_SERVICE;
537         }
538         port = strtoul(serv, &end, HOST_NAME_LEN);
539     }
540     if (!end) {
541         if (port > PORT_NUM) {
542             return EAI_SERVICE;
543         }
544         int32_t cnt = 0;
545         if (proto != IPPROTO_UDP) {
546             buf[cnt].port = port;
547             buf[cnt].sockType = SOCK_STREAM;
548             buf[cnt++].proto = IPPROTO_TCP;
549         }
550         if (proto != IPPROTO_TCP) {
551             buf[cnt].port = port;
552             buf[cnt].sockType = SOCK_DGRAM;
553             buf[cnt++].proto = IPPROTO_UDP;
554         }
555         return cnt;
556     }
557 
558     if (static_cast<uint32_t>(flags) & AI_NUMERICSERV) {
559         return EAI_NONAME;
560     }
561     return EAI_SERVICE;
562 }
563 } // namespace nmd
564 } // namespace OHOS
565