1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#include <curl/curl.h>
26
27#ifdef HAVE_NETINET_IN_H
28#  include <netinet/in.h>
29#endif
30#ifdef HAVE_NETDB_H
31#  include <netdb.h>
32#endif
33#ifdef HAVE_ARPA_INET_H
34#  include <arpa/inet.h>
35#endif
36#ifdef HAVE_SYS_UN_H
37#  include <sys/un.h>
38#endif
39
40#ifdef __VMS
41#  include <in.h>
42#  include <inet.h>
43#endif
44
45#if defined(NETWARE) && defined(__NOVELL_LIBC__)
46#  undef  in_addr_t
47#  define in_addr_t unsigned long
48#endif
49
50#include "curl_addrinfo.h"
51#include "inet_pton.h"
52#include "warnless.h"
53/* The last 3 #include files should be in this order */
54#include "curl_printf.h"
55#include "curl_memory.h"
56#include "memdebug.h"
57
58/*
59 * Curl_freeaddrinfo()
60 *
61 * This is used to free a linked list of Curl_addrinfo structs along
62 * with all its associated allocated storage. This function should be
63 * called once for each successful call to Curl_getaddrinfo_ex() or to
64 * any function call which actually allocates a Curl_addrinfo struct.
65 */
66
67#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
68    defined(__OPTIMIZE__) && defined(__unix__) &&  defined(__i386__)
69  /* workaround icc 9.1 optimizer issue */
70# define vqualifier volatile
71#else
72# define vqualifier
73#endif
74
75void
76Curl_freeaddrinfo(Curl_addrinfo *cahead)
77{
78  Curl_addrinfo *vqualifier canext;
79  Curl_addrinfo *ca;
80
81  for(ca = cahead; ca != NULL; ca = canext) {
82    free(ca->ai_addr);
83    free(ca->ai_canonname);
84    canext = ca->ai_next;
85
86    free(ca);
87  }
88}
89
90
91#ifdef HAVE_GETADDRINFO
92/*
93 * Curl_getaddrinfo_ex()
94 *
95 * This is a wrapper function around system's getaddrinfo(), with
96 * the only difference that instead of returning a linked list of
97 * addrinfo structs this one returns a linked list of Curl_addrinfo
98 * ones. The memory allocated by this function *MUST* be free'd with
99 * Curl_freeaddrinfo().  For each successful call to this function
100 * there must be an associated call later to Curl_freeaddrinfo().
101 *
102 * There should be no single call to system's getaddrinfo() in the
103 * whole library, any such call should be 'routed' through this one.
104 */
105
106int
107Curl_getaddrinfo_ex(const char *nodename,
108                    const char *servname,
109                    const struct addrinfo *hints,
110                    Curl_addrinfo **result)
111{
112  const struct addrinfo *ai;
113  struct addrinfo *aihead;
114  Curl_addrinfo *cafirst = NULL;
115  Curl_addrinfo *calast = NULL;
116  Curl_addrinfo *ca;
117  size_t ss_size;
118  int error;
119
120  *result = NULL; /* assume failure */
121
122  error = getaddrinfo(nodename, servname, hints, &aihead);
123  if(error)
124    return error;
125
126  /* traverse the addrinfo list */
127
128  for(ai = aihead; ai != NULL; ai = ai->ai_next) {
129
130    /* ignore elements with unsupported address family, */
131    /* settle family-specific sockaddr structure size.  */
132    if(ai->ai_family == AF_INET)
133      ss_size = sizeof(struct sockaddr_in);
134#ifdef ENABLE_IPV6
135    else if(ai->ai_family == AF_INET6)
136      ss_size = sizeof(struct sockaddr_in6);
137#endif
138    else
139      continue;
140
141    /* ignore elements without required address info */
142    if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0))
143      continue;
144
145    /* ignore elements with bogus address size */
146    if((size_t)ai->ai_addrlen < ss_size)
147      continue;
148
149    if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) {
150      error = EAI_MEMORY;
151      break;
152    }
153
154    /* copy each structure member individually, member ordering, */
155    /* size, or padding might be different for each platform.    */
156
157    ca->ai_flags     = ai->ai_flags;
158    ca->ai_family    = ai->ai_family;
159    ca->ai_socktype  = ai->ai_socktype;
160    ca->ai_protocol  = ai->ai_protocol;
161    ca->ai_addrlen   = (curl_socklen_t)ss_size;
162    ca->ai_addr      = NULL;
163    ca->ai_canonname = NULL;
164    ca->ai_next      = NULL;
165
166    if((ca->ai_addr = malloc(ss_size)) == NULL) {
167      error = EAI_MEMORY;
168      free(ca);
169      break;
170    }
171    memcpy(ca->ai_addr, ai->ai_addr, ss_size);
172
173    if(ai->ai_canonname != NULL) {
174      if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) {
175        error = EAI_MEMORY;
176        free(ca->ai_addr);
177        free(ca);
178        break;
179      }
180    }
181
182    /* if the return list is empty, this becomes the first element */
183    if(!cafirst)
184      cafirst = ca;
185
186    /* add this element last in the return list */
187    if(calast)
188      calast->ai_next = ca;
189    calast = ca;
190
191  }
192
193  /* destroy the addrinfo list */
194  if(aihead)
195    freeaddrinfo(aihead);
196
197  /* if we failed, also destroy the Curl_addrinfo list */
198  if(error) {
199    Curl_freeaddrinfo(cafirst);
200    cafirst = NULL;
201  }
202  else if(!cafirst) {
203#ifdef EAI_NONAME
204    /* rfc3493 conformant */
205    error = EAI_NONAME;
206#else
207    /* rfc3493 obsoleted */
208    error = EAI_NODATA;
209#endif
210#ifdef USE_WINSOCK
211    SET_SOCKERRNO(error);
212#endif
213  }
214
215  *result = cafirst;
216
217  /* This is not a CURLcode */
218  return error;
219}
220#endif /* HAVE_GETADDRINFO */
221
222
223/*
224 * Curl_he2ai()
225 *
226 * This function returns a pointer to the first element of a newly allocated
227 * Curl_addrinfo struct linked list filled with the data of a given hostent.
228 * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
229 * stack, but usable also for IPv4, all hosts and environments.
230 *
231 * The memory allocated by this function *MUST* be free'd later on calling
232 * Curl_freeaddrinfo().  For each successful call to this function there
233 * must be an associated call later to Curl_freeaddrinfo().
234 *
235 *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
236 *
237 *     struct Curl_addrinfo {
238 *       int                   ai_flags;
239 *       int                   ai_family;
240 *       int                   ai_socktype;
241 *       int                   ai_protocol;
242 *       curl_socklen_t        ai_addrlen;   * Follow rfc3493 struct addrinfo *
243 *       char                 *ai_canonname;
244 *       struct sockaddr      *ai_addr;
245 *       struct Curl_addrinfo *ai_next;
246 *     };
247 *     typedef struct Curl_addrinfo Curl_addrinfo;
248 *
249 *   hostent defined in <netdb.h>
250 *
251 *     struct hostent {
252 *       char    *h_name;
253 *       char    **h_aliases;
254 *       int     h_addrtype;
255 *       int     h_length;
256 *       char    **h_addr_list;
257 *     };
258 *
259 *   for backward compatibility:
260 *
261 *     #define h_addr  h_addr_list[0]
262 */
263
264Curl_addrinfo *
265Curl_he2ai(const struct hostent *he, int port)
266{
267  Curl_addrinfo *ai;
268  Curl_addrinfo *prevai = NULL;
269  Curl_addrinfo *firstai = NULL;
270  struct sockaddr_in *addr;
271#ifdef ENABLE_IPV6
272  struct sockaddr_in6 *addr6;
273#endif
274  CURLcode result = CURLE_OK;
275  int i;
276  char *curr;
277
278  if(!he)
279    /* no input == no output! */
280    return NULL;
281
282  DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
283
284  for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
285
286    size_t ss_size;
287#ifdef ENABLE_IPV6
288    if(he->h_addrtype == AF_INET6)
289      ss_size = sizeof (struct sockaddr_in6);
290    else
291#endif
292      ss_size = sizeof (struct sockaddr_in);
293
294    if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) {
295      result = CURLE_OUT_OF_MEMORY;
296      break;
297    }
298    if((ai->ai_canonname = strdup(he->h_name)) == NULL) {
299      result = CURLE_OUT_OF_MEMORY;
300      free(ai);
301      break;
302    }
303    if((ai->ai_addr = calloc(1, ss_size)) == NULL) {
304      result = CURLE_OUT_OF_MEMORY;
305      free(ai->ai_canonname);
306      free(ai);
307      break;
308    }
309
310    if(!firstai)
311      /* store the pointer we want to return from this function */
312      firstai = ai;
313
314    if(prevai)
315      /* make the previous entry point to this */
316      prevai->ai_next = ai;
317
318    ai->ai_family = he->h_addrtype;
319
320    /* we return all names as STREAM, so when using this address for TFTP
321       the type must be ignored and conn->socktype be used instead! */
322    ai->ai_socktype = SOCK_STREAM;
323
324    ai->ai_addrlen = (curl_socklen_t)ss_size;
325
326    /* leave the rest of the struct filled with zero */
327
328    switch (ai->ai_family) {
329    case AF_INET:
330      addr = (void *)ai->ai_addr; /* storage area for this info */
331
332      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
333      addr->sin_family = (unsigned short)(he->h_addrtype);
334      addr->sin_port = htons((unsigned short)port);
335      break;
336
337#ifdef ENABLE_IPV6
338    case AF_INET6:
339      addr6 = (void *)ai->ai_addr; /* storage area for this info */
340
341      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
342      addr6->sin6_family = (unsigned short)(he->h_addrtype);
343      addr6->sin6_port = htons((unsigned short)port);
344      break;
345#endif
346    }
347
348    prevai = ai;
349  }
350
351  if(result) {
352    Curl_freeaddrinfo(firstai);
353    firstai = NULL;
354  }
355
356  return firstai;
357}
358
359
360struct namebuff {
361  struct hostent hostentry;
362  union {
363    struct in_addr  ina4;
364#ifdef ENABLE_IPV6
365    struct in6_addr ina6;
366#endif
367  } addrentry;
368  char *h_addr_list[2];
369};
370
371
372/*
373 * Curl_ip2addr()
374 *
375 * This function takes an internet address, in binary form, as input parameter
376 * along with its address family and the string version of the address, and it
377 * returns a Curl_addrinfo chain filled in correctly with information for the
378 * given address/host
379 */
380
381Curl_addrinfo *
382Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
383{
384  Curl_addrinfo *ai;
385
386#if defined(__VMS) && \
387    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
388#pragma pointer_size save
389#pragma pointer_size short
390#pragma message disable PTRMISMATCH
391#endif
392
393  struct hostent  *h;
394  struct namebuff *buf;
395  char  *addrentry;
396  char  *hoststr;
397  size_t addrsize;
398
399  DEBUGASSERT(inaddr && hostname);
400
401  buf = malloc(sizeof(struct namebuff));
402  if(!buf)
403    return NULL;
404
405  hoststr = strdup(hostname);
406  if(!hoststr) {
407    free(buf);
408    return NULL;
409  }
410
411  switch(af) {
412  case AF_INET:
413    addrsize = sizeof(struct in_addr);
414    addrentry = (void *)&buf->addrentry.ina4;
415    memcpy(addrentry, inaddr, sizeof(struct in_addr));
416    break;
417#ifdef ENABLE_IPV6
418  case AF_INET6:
419    addrsize = sizeof(struct in6_addr);
420    addrentry = (void *)&buf->addrentry.ina6;
421    memcpy(addrentry, inaddr, sizeof(struct in6_addr));
422    break;
423#endif
424  default:
425    free(hoststr);
426    free(buf);
427    return NULL;
428  }
429
430  h = &buf->hostentry;
431  h->h_name = hoststr;
432  h->h_aliases = NULL;
433  h->h_addrtype = (short)af;
434  h->h_length = (short)addrsize;
435  h->h_addr_list = &buf->h_addr_list[0];
436  h->h_addr_list[0] = addrentry;
437  h->h_addr_list[1] = NULL; /* terminate list of entries */
438
439#if defined(__VMS) && \
440    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
441#pragma pointer_size restore
442#pragma message enable PTRMISMATCH
443#endif
444
445  ai = Curl_he2ai(h, port);
446
447  free(hoststr);
448  free(buf);
449
450  return ai;
451}
452
453/*
454 * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
455 * allocated Curl_addrinfo struct and returns it.
456 */
457Curl_addrinfo *Curl_str2addr(char *address, int port)
458{
459  struct in_addr in;
460  if(Curl_inet_pton(AF_INET, address, &in) > 0)
461    /* This is a dotted IP address 123.123.123.123-style */
462    return Curl_ip2addr(AF_INET, &in, address, port);
463#ifdef ENABLE_IPV6
464  else {
465    struct in6_addr in6;
466    if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
467      /* This is a dotted IPv6 address ::1-style */
468      return Curl_ip2addr(AF_INET6, &in6, address, port);
469  }
470#endif
471  return NULL; /* bad input format */
472}
473
474#ifdef USE_UNIX_SOCKETS
475/**
476 * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
477 * struct initialized with this path.
478 */
479Curl_addrinfo *Curl_unix2addr(const char *path)
480{
481  Curl_addrinfo *ai;
482  struct sockaddr_un *sa_un;
483  size_t path_len;
484
485  ai = calloc(1, sizeof(Curl_addrinfo));
486  if(!ai)
487    return NULL;
488  if((ai->ai_addr = calloc(1, sizeof(struct sockaddr_un))) == NULL) {
489    free(ai);
490    return NULL;
491  }
492  /* sun_path must be able to store the NUL-terminated path */
493  path_len = strlen(path);
494  if(path_len >= sizeof(sa_un->sun_path)) {
495    free(ai->ai_addr);
496    free(ai);
497    return NULL;
498  }
499
500  ai->ai_family = AF_UNIX;
501  ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
502  ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un);
503  sa_un = (void *) ai->ai_addr;
504  sa_un->sun_family = AF_UNIX;
505  memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */
506  return ai;
507}
508#endif
509
510#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
511/*
512 * curl_dofreeaddrinfo()
513 *
514 * This is strictly for memory tracing and are using the same style as the
515 * family otherwise present in memdebug.c. I put these ones here since they
516 * require a bunch of structs I didn't want to include in memdebug.c
517 */
518
519void
520curl_dofreeaddrinfo(struct addrinfo *freethis,
521                    int line, const char *source)
522{
523#ifdef USE_LWIPSOCK
524  lwip_freeaddrinfo(freethis);
525#else
526  (freeaddrinfo)(freethis);
527#endif
528  curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
529              source, line, (void *)freethis);
530}
531#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
532
533
534#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
535/*
536 * curl_dogetaddrinfo()
537 *
538 * This is strictly for memory tracing and are using the same style as the
539 * family otherwise present in memdebug.c. I put these ones here since they
540 * require a bunch of structs I didn't want to include in memdebug.c
541 */
542
543int
544curl_dogetaddrinfo(const char *hostname,
545                   const char *service,
546                   const struct addrinfo *hints,
547                   struct addrinfo **result,
548                   int line, const char *source)
549{
550#ifdef USE_LWIPSOCK
551  int res=lwip_getaddrinfo(hostname, service, hints, result);
552#else
553  int res=(getaddrinfo)(hostname, service, hints, result);
554#endif
555  if(0 == res)
556    /* success */
557    curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
558                source, line, (void *)*result);
559  else
560    curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
561                source, line);
562  return res;
563}
564#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
565
566#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
567/*
568 * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
569 * 10.11.5.
570 */
571void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port)
572{
573  Curl_addrinfo *ca;
574  struct sockaddr_in *addr;
575#ifdef ENABLE_IPV6
576  struct sockaddr_in6 *addr6;
577#endif
578  for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
579    switch (ca->ai_family) {
580    case AF_INET:
581      addr = (void *)ca->ai_addr; /* storage area for this info */
582      addr->sin_port = htons((unsigned short)port);
583      break;
584
585#ifdef ENABLE_IPV6
586    case AF_INET6:
587      addr6 = (void *)ca->ai_addr; /* storage area for this info */
588      addr6->sin6_port = htons((unsigned short)port);
589      break;
590#endif
591    }
592  }
593}
594#endif
595