1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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 http://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 "setup.h"
24
25#include <string.h>
26
27#ifdef HAVE_SYS_SOCKET_H
28#include <sys/socket.h>
29#endif
30#ifdef HAVE_NETINET_IN_H
31#include <netinet/in.h>
32#endif
33#ifdef HAVE_NETDB_H
34#include <netdb.h>
35#endif
36#ifdef HAVE_ARPA_INET_H
37#include <arpa/inet.h>
38#endif
39#ifdef HAVE_STDLIB_H
40#include <stdlib.h>     /* required for free() prototypes */
41#endif
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>     /* for the close() proto */
44#endif
45#ifdef __VMS
46#include <in.h>
47#include <inet.h>
48#include <stdlib.h>
49#endif
50
51#ifdef HAVE_PROCESS_H
52#include <process.h>
53#endif
54
55#include "urldata.h"
56#include "sendf.h"
57#include "hostip.h"
58#include "hash.h"
59#include "share.h"
60#include "strerror.h"
61#include "url.h"
62#include "inet_pton.h"
63#include "connect.h"
64
65#define _MPRINTF_REPLACE /* use our functions only */
66#include <curl/mprintf.h>
67
68#include "curl_memory.h"
69/* The last #include file should be: */
70#include "memdebug.h"
71
72/***********************************************************************
73 * Only for ipv6-enabled builds
74 **********************************************************************/
75#ifdef CURLRES_IPV6
76
77
78#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
79/* These are strictly for memory tracing and are using the same style as the
80 * family otherwise present in memdebug.c. I put these ones here since they
81 * require a bunch of structs I didn't want to include in memdebug.c
82 */
83
84/*
85 * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
86 * (ignoring the fact c-ares doesn't return 'serv').
87 */
88
89int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
90                       GETNAMEINFO_TYPE_ARG2 salen,
91                       char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
92                       char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
93                       GETNAMEINFO_TYPE_ARG7 flags,
94                       int line, const char *source)
95{
96  int res = (getnameinfo)(sa, salen,
97                          host, hostlen,
98                          serv, servlen,
99                          flags);
100  if(0 == res)
101    /* success */
102    curl_memlog("GETNAME %s:%d getnameinfo()\n",
103                source, line);
104  else
105    curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
106                source, line, res);
107  return res;
108}
109#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
110
111/*
112 * Curl_ipv6works() returns TRUE if ipv6 seems to work.
113 */
114bool Curl_ipv6works(void)
115{
116  /* the nature of most system is that IPv6 status doesn't come and go
117     during a program's lifetime so we only probe the first time and then we
118     have the info kept for fast re-use */
119  static int ipv6_works = -1;
120  if(-1 == ipv6_works) {
121    /* probe to see if we have a working IPv6 stack */
122    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
123    if(s == CURL_SOCKET_BAD)
124      /* an ipv6 address was requested but we can't get/use one */
125      ipv6_works = 0;
126    else {
127      ipv6_works = 1;
128      Curl_closesocket(NULL, s);
129    }
130  }
131  return (ipv6_works>0)?TRUE:FALSE;
132}
133
134/*
135 * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
136 * been set and returns TRUE if they are OK.
137 */
138bool Curl_ipvalid(struct connectdata *conn)
139{
140  if(conn->ip_version == CURL_IPRESOLVE_V6)
141    return Curl_ipv6works();
142  return TRUE;
143}
144
145#if defined(CURLRES_SYNCH)
146
147#ifdef DEBUG_ADDRINFO
148static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
149{
150  printf("dump_addrinfo:\n");
151  for(; ai; ai = ai->ai_next) {
152    char  buf[INET6_ADDRSTRLEN];
153
154    printf("    fam %2d, CNAME %s, ",
155           ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
156    if(Curl_printable_address(ai, buf, sizeof(buf)))
157      printf("%s\n", buf);
158    else
159      printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
160  }
161}
162#else
163#define dump_addrinfo(x,y)
164#endif
165
166/*
167 * Curl_getaddrinfo() when built ipv6-enabled (non-threading and
168 * non-ares version).
169 *
170 * Returns name information about the given hostname and port number. If
171 * successful, the 'addrinfo' is returned and the forth argument will point to
172 * memory we need to free after use. That memory *MUST* be freed with
173 * Curl_freeaddrinfo(), nothing else.
174 */
175Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
176                                const char *hostname,
177                                int port,
178                                int *waitp)
179{
180  struct addrinfo hints;
181  Curl_addrinfo *res;
182  int error;
183  char sbuf[NI_MAXSERV];
184  char *sbufptr = NULL;
185  char addrbuf[128];
186  int pf;
187  struct SessionHandle *data = conn->data;
188
189  *waitp = 0; /* synchronous response only */
190
191  /*
192   * Check if a limited name resolve has been requested.
193   */
194  switch(conn->ip_version) {
195  case CURL_IPRESOLVE_V4:
196    pf = PF_INET;
197    break;
198  case CURL_IPRESOLVE_V6:
199    pf = PF_INET6;
200    break;
201  default:
202    pf = PF_UNSPEC;
203    break;
204  }
205
206  if((pf != PF_INET) && !Curl_ipv6works())
207    /* the stack seems to be a non-ipv6 one */
208    pf = PF_INET;
209
210  memset(&hints, 0, sizeof(hints));
211  hints.ai_family = pf;
212  hints.ai_socktype = conn->socktype;
213
214  if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
215     (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
216    /* the given address is numerical only, prevent a reverse lookup */
217    hints.ai_flags = AI_NUMERICHOST;
218  }
219
220  if(port) {
221    snprintf(sbuf, sizeof(sbuf), "%d", port);
222    sbufptr=sbuf;
223  }
224  error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
225  if(error) {
226    infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
227    return NULL;
228  }
229
230  dump_addrinfo(conn, res);
231
232  return res;
233}
234#endif /* CURLRES_SYNCH */
235#endif /* CURLRES_IPV6 */
236
237