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