1#include <stdlib.h> 2#include <sys/socket.h> 3#include <sys/time.h> 4#include <netinet/in.h> 5#include <netdb.h> 6#include <string.h> 7#include <pthread.h> 8#include <unistd.h> 9#include <endian.h> 10#include <errno.h> 11#include "lookup.h" 12 13#define COST_FOR_MS 1000 14#define COST_FOR_NANOSEC 1000000 15#define DNS_QUERY_SUCCESS 0 16#define DNS_QUERY_COMMOM_FAIL (-1) 17#define GETADDRINFO_PRINT_DEBUG(...) 18 19int reportdnsresult(int netid, char* name, int usedtime, int queryret, struct addrinfo *res, struct queryparam *param) 20{ 21#if OHOS_DNS_PROXY_BY_NETSYS 22 if (dns_post_result_to_netsys_cache(netid, name, usedtime, queryret, res, param) == 0) { 23 GETADDRINFO_PRINT_DEBUG("getaddrinfo_ext reportdnsresult fail\n"); 24 } 25#endif 26 return 0; 27} 28 29static custom_dns_resolver g_customdnsresolvehook; 30static pthread_key_t g_recursiveKey; 31static int* g_recursive; 32 33int setdnsresolvehook(custom_dns_resolver hookfunc) 34{ 35 int ret = -1; 36 if (g_customdnsresolvehook) { 37 return ret; 38 } 39 if (hookfunc) { 40 g_customdnsresolvehook = hookfunc; 41 pthread_key_create(&g_recursiveKey, NULL); 42 ret = 0; 43 } 44 return ret; 45} 46 47int removednsresolvehook() 48{ 49 g_customdnsresolvehook = NULL; 50 if (g_recursive) { 51 free(g_recursive); 52 g_recursive = NULL; 53 } 54 if (g_recursiveKey) { 55 pthread_key_delete(g_recursiveKey); 56 g_recursiveKey = NULL; 57 } 58 return 0; 59} 60 61int getaddrinfo_hook(const char* host, const char* serv, const struct addrinfo* hints, 62 struct addrinfo** res) 63{ 64 if (g_customdnsresolvehook) { 65 int ret = g_customdnsresolvehook(host, serv, hints, res); 66 if (ret == 0) { 67 return ret; 68 } 69 } 70 return predefined_host_lookup_ip(host, serv, hints, res); 71} 72 73int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) 74{ 75 struct queryparam param = {0, 0, 0, 0, NULL}; 76 return getaddrinfo_ext(host, serv, hint, res, ¶m); 77} 78 79int getaddrinfo_ext(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, 80 struct addrinfo **restrict res, struct queryparam *restrict param) 81{ 82 int netid = 0; 83 int type = 0; 84 int usedtime = 0; 85 struct timeval timeStart, timeEnd; 86 87 if (!host && !serv) return EAI_NONAME; 88 if (!param) { 89 netid = 0; 90 type = 0; 91 } else { 92 netid = param->qp_netid; 93 type = param->qp_type; 94 } 95 96 if (g_customdnsresolvehook) { 97 g_recursive = pthread_getspecific(g_recursiveKey); 98 if (g_recursive == NULL) { 99 int *newRecursive = malloc(sizeof(int)); 100 *newRecursive = 0; 101 pthread_setspecific(g_recursiveKey, newRecursive); 102 g_recursive = newRecursive; 103 } 104 if (*g_recursive == 0) { 105 ++(*g_recursive); 106 int ret = g_customdnsresolvehook(host, serv, hint, res); 107 --(*g_recursive); 108 return ret; 109 } 110 } 111 112#if OHOS_DNS_PROXY_BY_NETSYS 113 GETADDRINFO_PRINT_DEBUG("getaddrinfo_ext netid:%{public}d type:%{public}d \n", netid, type); 114 if (type == QEURY_TYPE_NORMAL && predefined_host_is_contain_host(host) == 0) { 115 if (dns_get_addr_info_from_netsys_cache2(netid, host, serv, hint, res) == 0) { 116 GETADDRINFO_PRINT_DEBUG("getaddrinfo_ext get from netsys cache OK\n"); 117 reportdnsresult(netid, host, 0, DNS_QUERY_SUCCESS, *res, param); 118 return 0; 119 } 120 } 121#endif 122 123 struct service ports[MAXSERVS]; 124 struct address addrs[MAXADDRS]; 125 char canon[256], *outcanon; 126 int nservs, naddrs, nais, canon_len, i, j, k; 127 int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; 128 struct aibuf *out; 129 130 if (hint) { 131 family = hint->ai_family; 132 flags = hint->ai_flags; 133 proto = hint->ai_protocol; 134 socktype = hint->ai_socktype; 135 136 const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | 137 AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; 138 if ((flags & mask) != flags) { 139#ifndef __LITEOS__ 140 MUSL_LOGE("%{public}s: %{public}d: bad hint ai_flag: %{public}d", __func__, __LINE__, flags); 141#endif 142 return EAI_BADFLAGS; 143 } 144 145 switch (family) { 146 case AF_INET: 147 case AF_INET6: 148 case AF_UNSPEC: 149 break; 150 default: 151#ifndef __LITEOS__ 152 MUSL_LOGE("%{public}s: %{public}d: wrong family in hint: %{public}d", __func__, __LINE__, family); 153#endif 154 return EAI_FAMILY; 155 } 156 } 157 158 if (flags & AI_ADDRCONFIG) { 159 /* Define the "an address is configured" condition for address 160 * families via ability to create a socket for the family plus 161 * routability of the loopback address for the family. */ 162 static const struct sockaddr_in lo4 = { 163 .sin_family = AF_INET, .sin_port = 65535, 164 .sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN 165 ? 0x7f000001 : 0x0100007f 166 }; 167 static const struct sockaddr_in6 lo6 = { 168 .sin6_family = AF_INET6, .sin6_port = 65535, 169 .sin6_addr = IN6ADDR_LOOPBACK_INIT 170 }; 171 int tf[2] = { AF_INET, AF_INET6 }; 172 const void *ta[2] = { &lo4, &lo6 }; 173 socklen_t tl[2] = { sizeof lo4, sizeof lo6 }; 174 for (i = 0; i < 2; i++) { 175 if (family == tf[1 - i]) continue; 176 int s = socket(tf[i], SOCK_CLOEXEC | SOCK_DGRAM, 177 IPPROTO_UDP); 178#ifndef __LITEOS__ 179 if (s < 0) { 180 MUSL_LOGE("%{public}s: %{public}d: create socket failed for family: %{public}d, errno: %{public}d", 181 __func__, __LINE__, tf[i], errno); 182 } 183#endif 184 if (s >= 0) { 185 int cs; 186 pthread_setcancelstate( 187 PTHREAD_CANCEL_DISABLE, &cs); 188 int r = connect(s, ta[i], tl[i]); 189 int saved_errno = errno; 190 pthread_setcancelstate(cs, 0); 191 close(s); 192 if (!r) continue; 193 errno = saved_errno; 194 } 195 switch (errno) { 196 case EADDRNOTAVAIL: 197 case EAFNOSUPPORT: 198 case EHOSTUNREACH: 199 case ENETDOWN: 200 case ENETUNREACH: 201 break; 202 default: 203#ifndef __LITEOS__ 204 MUSL_LOGE("%{public}s: %{public}d: connect to local address failed: %{public}d", 205 __func__, __LINE__, errno); 206#endif 207 return EAI_SYSTEM; 208 } 209 if (family == tf[i]) { 210#ifndef __LITEOS__ 211 MUSL_LOGE("%{public}s: %{public}d: family mismatch: %{public}d", __func__, __LINE__, EAI_NONAME); 212#endif 213 return EAI_NONAME; 214 } 215 family = tf[1 - i]; 216 } 217 } 218 219 int timeStartRet = gettimeofday(&timeStart, NULL); 220 nservs = __lookup_serv(ports, serv, proto, socktype, flags); 221 if (nservs < 0) return nservs; 222 223 naddrs = lookup_name_ext(addrs, canon, host, family, flags, netid); 224 int timeEndRet = gettimeofday(&timeEnd, NULL); 225 int t_cost = 0; 226 if (timeStartRet == 0 && timeEndRet == 0) { 227 t_cost = COST_FOR_NANOSEC * (timeEnd.tv_sec - timeStart.tv_sec) + (timeEnd.tv_usec - timeStart.tv_usec); 228 t_cost /= COST_FOR_MS; 229 } 230 if (naddrs < 0) { 231 reportdnsresult(netid, host, t_cost, naddrs, NULL, param); 232#ifndef __LITEOS__ 233 MUSL_LOGE("%{public}s: %{public}d: reportdnsresult: %{public}d in process %{public}d", 234 __func__, __LINE__, naddrs, getpid()); 235#endif 236 return naddrs; 237 } 238 239 nais = nservs * naddrs; 240 canon_len = strlen(canon); 241 out = calloc(1, nais * sizeof(*out) + canon_len + 1); 242 if (!out) return EAI_MEMORY; 243 244 if (canon_len) { 245 outcanon = (void *)&out[nais]; 246 memcpy(outcanon, canon, canon_len + 1); 247 } else { 248 outcanon = 0; 249 } 250 251 for (k = i = 0; i < naddrs; i++) for (j = 0; j < nservs; j++, k++) { 252 out[k].slot = k; 253 out[k].ai = (struct addrinfo) { 254 .ai_family = addrs[i].family, 255 .ai_socktype = ports[j].socktype, 256 .ai_protocol = ports[j].proto, 257 .ai_addrlen = addrs[i].family == AF_INET 258 ? sizeof(struct sockaddr_in) 259 : sizeof(struct sockaddr_in6), 260 .ai_addr = (void *)&out[k].sa, 261 .ai_canonname = outcanon }; 262 if (k) out[k-1].ai.ai_next = &out[k].ai; 263 switch (addrs[i].family) { 264 case AF_INET: 265 out[k].sa.sin.sin_family = AF_INET; 266 out[k].sa.sin.sin_port = htons(ports[j].port); 267 memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4); 268 break; 269 case AF_INET6: 270 out[k].sa.sin6.sin6_family = AF_INET6; 271 out[k].sa.sin6.sin6_port = htons(ports[j].port); 272 out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid; 273 memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16); 274 break; 275 } 276 } 277 out[0].ref = nais; 278 *res = &out->ai; 279 280 reportdnsresult(netid, host, t_cost, DNS_QUERY_SUCCESS, *res, param); 281 int cnt = predefined_host_is_contain_host(host); 282#if OHOS_DNS_PROXY_BY_NETSYS 283 if (type == QEURY_TYPE_NORMAL && cnt == 0) { 284 dns_set_addr_info_to_netsys_cache2(netid, host, serv, hint, *res); 285 } 286#endif 287 return 0; 288} 289