PostgreSQL Source Code  git master
getaddrinfo.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * getaddrinfo.c
4  * Support getaddrinfo() on platforms that don't have it.
5  *
6  * We also supply getnameinfo() here, assuming that the platform will have
7  * it if and only if it has getaddrinfo(). If this proves false on some
8  * platform, we'll need to split this file and provide a separate configure
9  * test for getnameinfo().
10  *
11  * Windows may or may not have these routines, so we handle Windows specially
12  * by dynamically checking for their existence. If they already exist, we
13  * use the Windows native routines, but if not, we use our own.
14  *
15  *
16  * Copyright (c) 2003-2022, PostgreSQL Global Development Group
17  *
18  * IDENTIFICATION
19  * src/port/getaddrinfo.c
20  *
21  *-------------------------------------------------------------------------
22  */
23 
24 /* This is intended to be used in both frontend and backend, so use c.h */
25 #include "c.h"
26 
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 
32 #include "getaddrinfo.h"
33 #include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */
34 #include "port/pg_bswap.h"
35 
36 
37 #ifdef FRONTEND
38 static int pqGethostbyname(const char *name,
39  struct hostent *resultbuf,
40  char *buffer, size_t buflen,
41  struct hostent **result,
42  int *herrno);
43 #endif
44 
45 #ifdef WIN32
46 /*
47  * The native routines may or may not exist on the Windows platform we are on,
48  * so we dynamically look up the routines, and call them via function pointers.
49  * Here we need to declare what the function pointers look like
50  */
51 typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
52  const char *servname,
53  const struct addrinfo *hints,
54  struct addrinfo **res);
55 
56 typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo *ai);
57 
58 typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr *sa,
59  int salen,
60  char *node, int nodelen,
61  char *service, int servicelen,
62  int flags);
63 
64 /* static pointers to the native routines, so we only do the lookup once. */
65 static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
66 static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
67 static getnameinfo_ptr_t getnameinfo_ptr = NULL;
68 
69 
70 static bool
71 haveNativeWindowsIPv6routines(void)
72 {
73  void *hLibrary = NULL;
74  static bool alreadyLookedForIpv6routines = false;
75 
76  if (alreadyLookedForIpv6routines)
77  return (getaddrinfo_ptr != NULL);
78 
79  /*
80  * For Windows XP and later versions, the IPv6 routines are present in the
81  * WinSock 2 library (ws2_32.dll).
82  */
83  hLibrary = LoadLibraryA("ws2_32");
84 
85  /* If hLibrary is null, we couldn't find a dll with functions */
86  if (hLibrary != NULL)
87  {
88  /* We found a dll, so now get the addresses of the routines */
89 
90  getaddrinfo_ptr = (getaddrinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
91  "getaddrinfo");
92  freeaddrinfo_ptr = (freeaddrinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
93  "freeaddrinfo");
94  getnameinfo_ptr = (getnameinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
95  "getnameinfo");
96 
97  /*
98  * If any one of the routines is missing, let's play it safe and
99  * ignore them all
100  */
101  if (getaddrinfo_ptr == NULL ||
102  freeaddrinfo_ptr == NULL ||
103  getnameinfo_ptr == NULL)
104  {
105  FreeLibrary(hLibrary);
106  hLibrary = NULL;
107  getaddrinfo_ptr = NULL;
108  freeaddrinfo_ptr = NULL;
109  getnameinfo_ptr = NULL;
110  }
111  }
112 
113  alreadyLookedForIpv6routines = true;
114  return (getaddrinfo_ptr != NULL);
115 }
116 #endif
117 
118 
119 /*
120  * get address info for ipv4 sockets.
121  *
122  * Bugs: - only one addrinfo is set even though hintp is NULL or
123  * ai_socktype is 0
124  * - AI_CANONNAME is not supported.
125  * - servname can only be a number, not text.
126  */
127 int
128 getaddrinfo(const char *node, const char *service,
129  const struct addrinfo *hintp,
130  struct addrinfo **res)
131 {
132  struct addrinfo *ai;
133  struct sockaddr_in sin,
134  *psin;
135  struct addrinfo hints;
136 
137 #ifdef WIN32
138 
139  /*
140  * If Windows has native IPv6 support, use the native Windows routine.
141  * Otherwise, fall through and use our own code.
142  */
143  if (haveNativeWindowsIPv6routines())
144  return (*getaddrinfo_ptr) (node, service, hintp, res);
145 #endif
146 
147  if (hintp == NULL)
148  {
149  memset(&hints, 0, sizeof(hints));
150  hints.ai_family = AF_INET;
151  hints.ai_socktype = SOCK_STREAM;
152  }
153  else
154  memcpy(&hints, hintp, sizeof(hints));
155 
156  if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
157  return EAI_FAMILY;
158 
159  if (hints.ai_socktype == 0)
160  hints.ai_socktype = SOCK_STREAM;
161 
162  if (!node && !service)
163  return EAI_NONAME;
164 
165  memset(&sin, 0, sizeof(sin));
166 
167  sin.sin_family = AF_INET;
168 
169  if (node)
170  {
171  if (node[0] == '\0')
172  sin.sin_addr.s_addr = pg_hton32(INADDR_ANY);
173  else if (hints.ai_flags & AI_NUMERICHOST)
174  {
175  if (!inet_aton(node, &sin.sin_addr))
176  return EAI_NONAME;
177  }
178  else
179  {
180  struct hostent *hp;
181 
182 #ifdef FRONTEND
183  struct hostent hpstr;
184  char buf[BUFSIZ];
185  int herrno = 0;
186 
187  pqGethostbyname(node, &hpstr, buf, sizeof(buf),
188  &hp, &herrno);
189 #else
190  hp = gethostbyname(node);
191 #endif
192  if (hp == NULL)
193  {
194  switch (h_errno)
195  {
196  case HOST_NOT_FOUND:
197  case NO_DATA:
198  return EAI_NONAME;
199  case TRY_AGAIN:
200  return EAI_AGAIN;
201  case NO_RECOVERY:
202  default:
203  return EAI_FAIL;
204  }
205  }
206  if (hp->h_addrtype != AF_INET)
207  return EAI_FAIL;
208 
209  memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
210  }
211  }
212  else
213  {
214  if (hints.ai_flags & AI_PASSIVE)
215  sin.sin_addr.s_addr = pg_hton32(INADDR_ANY);
216  else
217  sin.sin_addr.s_addr = pg_hton32(INADDR_LOOPBACK);
218  }
219 
220  if (service)
221  sin.sin_port = pg_hton16((unsigned short) atoi(service));
222 
223 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
224  sin.sin_len = sizeof(sin);
225 #endif
226 
227  ai = malloc(sizeof(*ai));
228  if (!ai)
229  return EAI_MEMORY;
230 
231  psin = malloc(sizeof(*psin));
232  if (!psin)
233  {
234  free(ai);
235  return EAI_MEMORY;
236  }
237 
238  memcpy(psin, &sin, sizeof(*psin));
239 
240  ai->ai_flags = 0;
241  ai->ai_family = AF_INET;
242  ai->ai_socktype = hints.ai_socktype;
243  ai->ai_protocol = hints.ai_protocol;
244  ai->ai_addrlen = sizeof(*psin);
245  ai->ai_addr = (struct sockaddr *) psin;
246  ai->ai_canonname = NULL;
247  ai->ai_next = NULL;
248 
249  *res = ai;
250 
251  return 0;
252 }
253 
254 
255 void
257 {
258  if (res)
259  {
260 #ifdef WIN32
261 
262  /*
263  * If Windows has native IPv6 support, use the native Windows routine.
264  * Otherwise, fall through and use our own code.
265  */
266  if (haveNativeWindowsIPv6routines())
267  {
268  (*freeaddrinfo_ptr) (res);
269  return;
270  }
271 #endif
272 
273  if (res->ai_addr)
274  free(res->ai_addr);
275  free(res);
276  }
277 }
278 
279 
280 const char *
282 {
283 #ifdef HAVE_HSTRERROR
284  int hcode;
285 
286  switch (errcode)
287  {
288  case EAI_NONAME:
289  hcode = HOST_NOT_FOUND;
290  break;
291  case EAI_AGAIN:
292  hcode = TRY_AGAIN;
293  break;
294  case EAI_FAIL:
295  default:
296  hcode = NO_RECOVERY;
297  break;
298  }
299 
300  return hstrerror(hcode);
301 #else /* !HAVE_HSTRERROR */
302 
303  switch (errcode)
304  {
305  case EAI_NONAME:
306  return "Unknown host";
307  case EAI_AGAIN:
308  return "Host name lookup failure";
309  /* Errors below are probably WIN32 only */
310 #ifdef EAI_BADFLAGS
311  case EAI_BADFLAGS:
312  return "Invalid argument";
313 #endif
314 #ifdef EAI_FAMILY
315  case EAI_FAMILY:
316  return "Address family not supported";
317 #endif
318 #ifdef EAI_MEMORY
319  case EAI_MEMORY:
320  return "Not enough memory";
321 #endif
322 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
323  case EAI_NODATA:
324  return "No host data of that type was found";
325 #endif
326 #ifdef EAI_SERVICE
327  case EAI_SERVICE:
328  return "Class type not found";
329 #endif
330 #ifdef EAI_SOCKTYPE
331  case EAI_SOCKTYPE:
332  return "Socket type not supported";
333 #endif
334  default:
335  return "Unknown server error";
336  }
337 #endif /* HAVE_HSTRERROR */
338 }
339 
340 /*
341  * Convert an ipv4 address to a hostname.
342  *
343  * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
344  * It will never resolve a hostname.
345  * - No IPv6 support.
346  */
347 int
348 getnameinfo(const struct sockaddr *sa, int salen,
349  char *node, int nodelen,
350  char *service, int servicelen, int flags)
351 {
352 #ifdef WIN32
353 
354  /*
355  * If Windows has native IPv6 support, use the native Windows routine.
356  * Otherwise, fall through and use our own code.
357  */
358  if (haveNativeWindowsIPv6routines())
359  return (*getnameinfo_ptr) (sa, salen, node, nodelen,
360  service, servicelen, flags);
361 #endif
362 
363  /* Invalid arguments. */
364  if (sa == NULL || (node == NULL && service == NULL))
365  return EAI_FAIL;
366 
367 #ifdef HAVE_IPV6
368  if (sa->sa_family == AF_INET6)
369  return EAI_FAMILY;
370 #endif
371 
372  /* Unsupported flags. */
373  if (flags & NI_NAMEREQD)
374  return EAI_AGAIN;
375 
376  if (node)
377  {
378  if (sa->sa_family == AF_INET)
379  {
380  if (pg_inet_net_ntop(AF_INET,
381  &((struct sockaddr_in *) sa)->sin_addr,
382  sa->sa_family == AF_INET ? 32 : 128,
383  node, nodelen) == NULL)
384  return EAI_MEMORY;
385  }
386  else
387  return EAI_MEMORY;
388  }
389 
390  if (service)
391  {
392  int ret = -1;
393 
394  if (sa->sa_family == AF_INET)
395  {
396  ret = snprintf(service, servicelen, "%d",
397  pg_ntoh16(((struct sockaddr_in *) sa)->sin_port));
398  }
399  if (ret < 0 || ret >= servicelen)
400  return EAI_MEMORY;
401  }
402 
403  return 0;
404 }
405 
406 /*
407  * Wrapper around gethostbyname() or gethostbyname_r() to mimic
408  * POSIX gethostbyname_r() behaviour, if it is not available or required.
409  */
410 #ifdef FRONTEND
411 static int
412 pqGethostbyname(const char *name,
413  struct hostent *resultbuf,
414  char *buffer, size_t buflen,
415  struct hostent **result,
416  int *herrno)
417 {
418 #if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R)
419 
420  /*
421  * broken (well early POSIX draft) gethostbyname_r() which returns 'struct
422  * hostent *'
423  */
424  *result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno);
425  return (*result == NULL) ? -1 : 0;
426 #else
427 
428  /* no gethostbyname_r(), just use gethostbyname() */
429  *result = gethostbyname(name);
430 
431  if (*result != NULL)
432  *herrno = h_errno;
433 
434  if (*result != NULL)
435  return 0;
436  else
437  return -1;
438 #endif
439 }
440 #endif /* FRONTEND */
void(* pg_funcptr_t)(void)
Definition: c.h:340
int errcode(int sqlerrcode)
Definition: elog.c:693
const char * name
Definition: encode.c:561
void freeaddrinfo(struct addrinfo *res)
Definition: getaddrinfo.c:256
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hintp, struct addrinfo **res)
Definition: getaddrinfo.c:128
const char * gai_strerror(int errcode)
Definition: getaddrinfo.c:281
int getnameinfo(const struct sockaddr *sa, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: getaddrinfo.c:348
#define EAI_NONAME
Definition: getaddrinfo.h:34
#define EAI_SOCKTYPE
Definition: getaddrinfo.h:38
#define EAI_FAMILY
Definition: getaddrinfo.h:37
#define NI_NAMEREQD
Definition: getaddrinfo.h:84
#define AI_NUMERICHOST
Definition: getaddrinfo.h:73
#define EAI_MEMORY
Definition: getaddrinfo.h:40
#define EAI_BADFLAGS
Definition: getaddrinfo.h:33
#define EAI_AGAIN
Definition: getaddrinfo.h:35
#define EAI_SERVICE
Definition: getaddrinfo.h:39
#define EAI_FAIL
Definition: getaddrinfo.h:36
#define AI_PASSIVE
Definition: getaddrinfo.h:62
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
#define pg_hton32(x)
Definition: pg_bswap.h:121
#define pg_hton16(x)
Definition: pg_bswap.h:120
#define pg_ntoh16(x)
Definition: pg_bswap.h:124
static char * buf
Definition: pg_test_fsync.c:67
char * pg_inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
Definition: inet_net_ntop.c:77
int inet_aton(const char *cp, struct in_addr *addr)
Definition: inet_aton.c:56
#define snprintf
Definition: port.h:225
size_t ai_addrlen
Definition: getaddrinfo.h:104
struct sockaddr * ai_addr
Definition: getaddrinfo.h:105
char * ai_canonname
Definition: getaddrinfo.h:106
int ai_socktype
Definition: getaddrinfo.h:102
int ai_protocol
Definition: getaddrinfo.h:103
struct addrinfo * ai_next
Definition: getaddrinfo.h:107
int ai_flags
Definition: getaddrinfo.h:100
int ai_family
Definition: getaddrinfo.h:101