Rizin
unix-like reverse engineering framework and cli tools
getaddrinfo.c
Go to the documentation of this file.
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include <assert.h>
23 
24 #include "uv.h"
25 #include "internal.h"
26 #include "req-inl.h"
27 #include "idna.h"
28 
29 /* EAI_* constants. */
30 #include <winsock2.h>
31 
32 /* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
33 #include <iphlpapi.h>
34 
36  switch (sys_err) {
37  case 0: return 0;
38  case WSATRY_AGAIN: return UV_EAI_AGAIN;
39  case WSAEINVAL: return UV_EAI_BADFLAGS;
40  case WSANO_RECOVERY: return UV_EAI_FAIL;
41  case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
42  case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
43  case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
44  case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
45  case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
46  default: return uv_translate_sys_error(sys_err);
47  }
48 }
49 
50 
51 /*
52  * MinGW is missing this
53  */
54 #if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
55  typedef struct addrinfoW {
56  int ai_flags;
57  int ai_family;
60  size_t ai_addrlen;
61  WCHAR* ai_canonname;
62  struct sockaddr* ai_addr;
63  struct addrinfoW* ai_next;
65 
66  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
67  const WCHAR* service,
68  const ADDRINFOW* hints,
69  PADDRINFOW* result);
70 
71  DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
72 #endif
73 
74 
75 /* Adjust size value to be multiple of 4. Use to keep pointer aligned.
76  * Do we need different versions of this for different architectures? */
77 #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
78 
79 #ifndef NDIS_IF_MAX_STRING_SIZE
80 #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
81 #endif
82 
83 static void uv__getaddrinfo_work(struct uv__work* w) {
85  struct addrinfoW* hints;
86  int err;
87 
88  req = container_of(w, uv_getaddrinfo_t, work_req);
89  hints = req->addrinfow;
90  req->addrinfow = NULL;
91  err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
93 }
94 
95 
96 /*
97  * Called from uv_run when complete. Call user specified callback
98  * then free returned addrinfo
99  * Returned addrinfo strings are converted from UTF-16 to UTF-8.
100  *
101  * To minimize allocation we calculate total size required,
102  * and copy all structs and referenced strings into the one block.
103  * Each size calculation is adjusted to avoid unaligned pointers.
104  */
105 static void uv__getaddrinfo_done(struct uv__work* w, int status) {
107  int addrinfo_len = 0;
108  int name_len = 0;
109  size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
110  struct addrinfoW* addrinfow_ptr;
111  struct addrinfo* addrinfo_ptr;
112  char* alloc_ptr = NULL;
113  char* cur_ptr = NULL;
114 
115  req = container_of(w, uv_getaddrinfo_t, work_req);
116 
117  /* release input parameter memory */
118  uv__free(req->alloc);
119  req->alloc = NULL;
120 
121  if (status == UV_ECANCELED) {
122  assert(req->retcode == 0);
123  req->retcode = UV_EAI_CANCELED;
124  goto complete;
125  }
126 
127  if (req->retcode == 0) {
128  /* Convert addrinfoW to addrinfo. First calculate required length. */
129  addrinfow_ptr = req->addrinfow;
130  while (addrinfow_ptr != NULL) {
131  addrinfo_len += addrinfo_struct_len +
132  ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
133  if (addrinfow_ptr->ai_canonname != NULL) {
134  name_len = WideCharToMultiByte(CP_UTF8,
135  0,
136  addrinfow_ptr->ai_canonname,
137  -1,
138  NULL,
139  0,
140  NULL,
141  NULL);
142  if (name_len == 0) {
143  req->retcode = uv_translate_sys_error(GetLastError());
144  goto complete;
145  }
146  addrinfo_len += ALIGNED_SIZE(name_len);
147  }
148  addrinfow_ptr = addrinfow_ptr->ai_next;
149  }
150 
151  /* allocate memory for addrinfo results */
152  alloc_ptr = (char*)uv__malloc(addrinfo_len);
153 
154  /* do conversions */
155  if (alloc_ptr != NULL) {
156  cur_ptr = alloc_ptr;
157  addrinfow_ptr = req->addrinfow;
158 
159  while (addrinfow_ptr != NULL) {
160  /* copy addrinfo struct data */
161  assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
162  addrinfo_ptr = (struct addrinfo*)cur_ptr;
163  addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
164  addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
165  addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
166  addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
167  addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
168  addrinfo_ptr->ai_canonname = NULL;
169  addrinfo_ptr->ai_addr = NULL;
170  addrinfo_ptr->ai_next = NULL;
171 
172  cur_ptr += addrinfo_struct_len;
173 
174  /* copy sockaddr */
175  if (addrinfo_ptr->ai_addrlen > 0) {
176  assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
177  alloc_ptr + addrinfo_len);
178  memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
179  addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
180  cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
181  }
182 
183  /* convert canonical name to UTF-8 */
184  if (addrinfow_ptr->ai_canonname != NULL) {
185  name_len = WideCharToMultiByte(CP_UTF8,
186  0,
187  addrinfow_ptr->ai_canonname,
188  -1,
189  NULL,
190  0,
191  NULL,
192  NULL);
193  assert(name_len > 0);
194  assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
195  name_len = WideCharToMultiByte(CP_UTF8,
196  0,
197  addrinfow_ptr->ai_canonname,
198  -1,
199  cur_ptr,
200  name_len,
201  NULL,
202  NULL);
203  assert(name_len > 0);
204  addrinfo_ptr->ai_canonname = cur_ptr;
205  cur_ptr += ALIGNED_SIZE(name_len);
206  }
207  assert(cur_ptr <= alloc_ptr + addrinfo_len);
208 
209  /* set next ptr */
210  addrinfow_ptr = addrinfow_ptr->ai_next;
211  if (addrinfow_ptr != NULL) {
212  addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
213  }
214  }
215  req->addrinfo = (struct addrinfo*)alloc_ptr;
216  } else {
217  req->retcode = UV_EAI_MEMORY;
218  }
219  }
220 
221  /* return memory to system */
222  if (req->addrinfow != NULL) {
223  FreeAddrInfoW(req->addrinfow);
224  req->addrinfow = NULL;
225  }
226 
227 complete:
228  uv__req_unregister(req->loop, req);
229 
230  /* finally do callback with converted result */
231  if (req->getaddrinfo_cb)
232  req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
233 }
234 
235 
236 void uv_freeaddrinfo(struct addrinfo* ai) {
237  char* alloc_ptr = (char*)ai;
238 
239  /* release copied result memory */
240  uv__free(alloc_ptr);
241 }
242 
243 
244 /*
245  * Entry point for getaddrinfo
246  * we convert the UTF-8 strings to UNICODE
247  * and save the UNICODE string pointers in the req
248  * We also copy hints so that caller does not need to keep memory until the
249  * callback.
250  * return 0 if a callback will be made
251  * return error code if validation fails
252  *
253  * To minimize allocation we calculate total size required,
254  * and copy all structs and referenced strings into the one block.
255  * Each size calculation is adjusted to avoid unaligned pointers.
256  */
259  uv_getaddrinfo_cb getaddrinfo_cb,
260  const char* node,
261  const char* service,
262  const struct addrinfo* hints) {
263  char hostname_ascii[256];
264  int nodesize = 0;
265  int servicesize = 0;
266  int hintssize = 0;
267  char* alloc_ptr = NULL;
268  int err;
269  long rc;
270 
271  if (req == NULL || (node == NULL && service == NULL)) {
272  return UV_EINVAL;
273  }
274 
275  UV_REQ_INIT(req, UV_GETADDRINFO);
276  req->getaddrinfo_cb = getaddrinfo_cb;
277  req->addrinfo = NULL;
278  req->loop = loop;
279  req->retcode = 0;
280 
281  /* calculate required memory size for all input values */
282  if (node != NULL) {
283  rc = uv__idna_toascii(node,
284  node + strlen(node),
285  hostname_ascii,
286  hostname_ascii + sizeof(hostname_ascii));
287  if (rc < 0)
288  return rc;
289  nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
290  -1, NULL, 0) * sizeof(WCHAR));
291  if (nodesize == 0) {
292  err = GetLastError();
293  goto error;
294  }
295  node = hostname_ascii;
296  }
297 
298  if (service != NULL) {
299  servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
300  0,
301  service,
302  -1,
303  NULL,
304  0) *
305  sizeof(WCHAR));
306  if (servicesize == 0) {
307  err = GetLastError();
308  goto error;
309  }
310  }
311  if (hints != NULL) {
312  hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
313  }
314 
315  /* allocate memory for inputs, and partition it as needed */
316  alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
317  if (!alloc_ptr) {
318  err = WSAENOBUFS;
319  goto error;
320  }
321 
322  /* save alloc_ptr now so we can free if error */
323  req->alloc = (void*)alloc_ptr;
324 
325  /* Convert node string to UTF16 into allocated memory and save pointer in the
326  * request. */
327  if (node != NULL) {
328  req->node = (WCHAR*)alloc_ptr;
329  if (MultiByteToWideChar(CP_UTF8,
330  0,
331  node,
332  -1,
333  (WCHAR*) alloc_ptr,
334  nodesize / sizeof(WCHAR)) == 0) {
335  err = GetLastError();
336  goto error;
337  }
338  alloc_ptr += nodesize;
339  } else {
340  req->node = NULL;
341  }
342 
343  /* Convert service string to UTF16 into allocated memory and save pointer in
344  * the req. */
345  if (service != NULL) {
346  req->service = (WCHAR*)alloc_ptr;
347  if (MultiByteToWideChar(CP_UTF8,
348  0,
349  service,
350  -1,
351  (WCHAR*) alloc_ptr,
352  servicesize / sizeof(WCHAR)) == 0) {
353  err = GetLastError();
354  goto error;
355  }
356  alloc_ptr += servicesize;
357  } else {
358  req->service = NULL;
359  }
360 
361  /* copy hints to allocated memory and save pointer in req */
362  if (hints != NULL) {
363  req->addrinfow = (struct addrinfoW*)alloc_ptr;
364  req->addrinfow->ai_family = hints->ai_family;
365  req->addrinfow->ai_socktype = hints->ai_socktype;
366  req->addrinfow->ai_protocol = hints->ai_protocol;
367  req->addrinfow->ai_flags = hints->ai_flags;
368  req->addrinfow->ai_addrlen = 0;
369  req->addrinfow->ai_canonname = NULL;
370  req->addrinfow->ai_addr = NULL;
371  req->addrinfow->ai_next = NULL;
372  } else {
373  req->addrinfow = NULL;
374  }
375 
377 
378  if (getaddrinfo_cb) {
380  &req->work_req,
384  return 0;
385  } else {
386  uv__getaddrinfo_work(&req->work_req);
387  uv__getaddrinfo_done(&req->work_req, 0);
388  return req->retcode;
389  }
390 
391 error:
392  if (req != NULL) {
393  uv__free(req->alloc);
394  req->alloc = NULL;
395  }
396  return uv_translate_sys_error(err);
397 }
398 
399 int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
400  NET_LUID luid;
401  wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
402  DWORD bufsize;
403  int r;
404 
405  if (buffer == NULL || size == NULL || *size == 0)
406  return UV_EINVAL;
407 
408  r = ConvertInterfaceIndexToLuid(ifindex, &luid);
409 
410  if (r != 0)
411  return uv_translate_sys_error(r);
412 
413  r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
414 
415  if (r != 0)
416  return uv_translate_sys_error(r);
417 
418  /* Check how much space we need */
419  bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
420 
421  if (bufsize == 0) {
422  return uv_translate_sys_error(GetLastError());
423  } else if (bufsize > *size) {
424  *size = bufsize;
425  return UV_ENOBUFS;
426  }
427 
428  /* Convert to UTF-8 */
429  bufsize = WideCharToMultiByte(CP_UTF8,
430  0,
431  wname,
432  -1,
433  buffer,
434  *size,
435  NULL,
436  NULL);
437 
438  if (bufsize == 0)
439  return uv_translate_sys_error(GetLastError());
440 
441  *size = bufsize - 1;
442  return 0;
443 }
444 
445 int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
446  int r;
447 
448  if (buffer == NULL || size == NULL || *size == 0)
449  return UV_EINVAL;
450 
451  r = snprintf(buffer, *size, "%d", ifindex);
452 
453  if (r < 0)
454  return uv_translate_sys_error(r);
455 
456  if (r >= (int) *size) {
457  *size = r + 1;
458  return UV_ENOBUFS;
459  }
460 
461  *size = r;
462  return 0;
463 }
#define ARRAY_SIZE(a)
static bool err
Definition: armass.c:435
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
#define w
Definition: crypto_rc6.c:13
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec req
Definition: sflib.h:128
long uv__idna_toascii(const char *s, const char *se, char *d, char *de)
Definition: idna.c:250
voidpf void uLong size
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
assert(limit<=UINT32_MAX/2)
#define container_of(ptr, type, member)
Definition: rz_types.h:650
WCHAR * ai_canonname
Definition: getaddrinfo.c:61
int ai_protocol
Definition: getaddrinfo.c:59
size_t ai_addrlen
Definition: getaddrinfo.c:60
struct addrinfoW * ai_next
Definition: getaddrinfo.c:63
int ai_flags
Definition: getaddrinfo.c:56
int ai_family
Definition: getaddrinfo.c:57
struct sockaddr * ai_addr
Definition: getaddrinfo.c:62
int ai_socktype
Definition: getaddrinfo.c:58
Definition: buffer.h:15
Definition: uv.h:1780
uv_loop_t * loop
Definition: main.c:7
void uv__work_submit(uv_loop_t *loop, struct uv__work *w, enum uv__work_kind kind, void(*work)(struct uv__work *w), void(*done)(struct uv__work *w, int status))
Definition: threadpool.c:256
int uv_if_indextoiid(unsigned int ifindex, char *buffer, size_t *size)
Definition: getaddrinfo.c:253
void uv_freeaddrinfo(struct addrinfo *ai)
Definition: getaddrinfo.c:223
int uv_getaddrinfo(uv_loop_t *loop, uv_getaddrinfo_t *req, uv_getaddrinfo_cb cb, const char *hostname, const char *service, const struct addrinfo *hints)
Definition: getaddrinfo.c:141
int uv__getaddrinfo_translate_error(int sys_err)
Definition: getaddrinfo.c:42
int uv_if_indextoname(unsigned int ifindex, char *buffer, size_t *size)
Definition: getaddrinfo.c:229
void error(const char *msg)
Definition: untgz.c:593
void * uv__malloc(size_t size)
Definition: uv-common.c:75
void uv__free(void *ptr)
Definition: uv-common.c:81
#define UV_REQ_INIT(req, typ)
Definition: uv-common.h:322
@ UV__WORK_SLOW_IO
Definition: uv-common.h:194
#define uv__req_register(loop, req)
Definition: uv-common.h:224
#define uv__req_unregister(loop, req)
Definition: uv-common.h:230
UV_EXTERN int uv_translate_sys_error(int sys_errno)
Definition: core.c:1249
void(* uv_getaddrinfo_cb)(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
Definition: uv.h:331
static void uv__getaddrinfo_work(struct uv__work *w)
Definition: getaddrinfo.c:83
static void uv__getaddrinfo_done(struct uv__work *w, int status)
Definition: getaddrinfo.c:105
#define ALIGNED_SIZE(X)
Definition: getaddrinfo.c:77
struct addrinfoW ADDRINFOW
#define NDIS_IF_MAX_STRING_SIZE
Definition: getaddrinfo.c:80
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo)
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR *node, const WCHAR *service, const ADDRINFOW *hints, PADDRINFOW *result)
struct addrinfoW * PADDRINFOW
DWORD