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