4 * $Header: /cvsroot/pgpool/pgpool-II/pool_ip.c,v 1.2.2.1 2009/08/22 04:19:49 t-ishii Exp $
6 * This file was imported from PostgreSQL 8.0.8 source code.
7 * See below for the copyright and description.
9 * pgpool: a language independent connection pool server for PostgreSQL
10 * written by Tatsuo Ishii
12 * Portions Copyright (c) 2003-2008 PgPool Global Development Group
13 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
14 * Portions Copyright (c) 1994, Regents of the University of California
16 * Permission to use, copy, modify, and distribute this software and
17 * its documentation for any purpose and without fee is hereby
18 * granted, provided that the above copyright notice appear in all
19 * copies and that both that copyright notice and this permission
20 * notice appear in supporting documentation, and that the name of the
21 * author not be used in advertising or publicity pertaining to
22 * distribution of the software without specific, written prior
23 * permission. The author makes no representations about the
24 * suitability of this software for any purpose. It is provided "as
25 * is" without express or implied warranty.
27 * ------------------------------
30 * This file and the IPV6 implementation were initially provided by
31 * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
32 * http://www.lbsd.net.
34 * pool_ip.c.: IPv6-aware network access.
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
54 static int rangeSockAddrAF_INET(const struct sockaddr_in * addr,
55 const struct sockaddr_in * netaddr,
56 const struct sockaddr_in * netmask);
59 static int rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
60 const struct sockaddr_in6 * netaddr,
61 const struct sockaddr_in6 * netmask);
64 static int getaddrinfo_unix(const char *path,
65 const struct addrinfo * hintsp,
66 struct addrinfo ** result);
68 static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
69 char *node, int nodelen,
70 char *service, int servicelen,
74 * pool_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
75 * caller MUST allocate NI_MAXHOST, NI_MAXSERV bytes for remote_host and remote_port
77 void pool_getnameinfo_all(SockAddr *saddr, char *remote_host, char *remote_port)
79 remote_host[0] = '\0';
80 remote_port[0] = '\0';
82 if (getnameinfo_all(&saddr->addr, saddr->salen,
83 remote_host, NI_MAXHOST,
84 remote_port, NI_MAXSERV,
85 (pool_config->log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV))
87 int ret = getnameinfo_all(&saddr->addr, saddr->salen,
88 remote_host, NI_MAXHOST,
89 remote_port, NI_MAXSERV,
90 NI_NUMERICHOST | NI_NUMERICSERV);
92 pool_error("getnameinfo_all() failed: %s", gai_strerror(ret));
97 * getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
100 getaddrinfo_all(const char *hostname, const char *servname,
101 const struct addrinfo * hintp, struct addrinfo ** result)
103 /* not all versions of getaddrinfo() zero *result on failure */
106 if (hintp->ai_family == AF_UNIX)
107 return getaddrinfo_unix(servname, hintp, result);
109 /* NULL has special meaning to getaddrinfo(). */
110 return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
111 servname, hintp, result);
116 * freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
118 * Note: the ai_family field of the original hint structure must be passed
119 * so that we can tell whether the addrinfo struct was built by the system's
120 * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions
121 * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
122 * not safe to look at ai_family in the addrinfo itself.
125 freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
127 if (hint_ai_family == AF_UNIX)
129 /* struct was built by getaddrinfo_unix (see getaddrinfo_all) */
132 struct addrinfo *p = ai;
141 /* struct was built by getaddrinfo() */
149 * getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
151 * The API of this routine differs from the standard getnameinfo() definition
152 * in two ways: first, the addr parameter is declared as sockaddr_storage
153 * rather than struct sockaddr, and second, the node and service fields are
154 * guaranteed to be filled with something even on failure return.
157 getnameinfo_all(const struct sockaddr_storage * addr, int salen,
158 char *node, int nodelen,
159 char *service, int servicelen,
164 if (addr && addr->ss_family == AF_UNIX)
165 rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
170 rc = getnameinfo((const struct sockaddr *) addr, salen,
178 strncpy(node, "???", nodelen);
180 strncpy(service, "???", servicelen);
187 #ifndef HAVE_GAI_STRERROR
189 gai_strerror(int errcode)
191 #ifdef HAVE_HSTRERROR
197 hcode = HOST_NOT_FOUND;
208 return hstrerror(hcode);
209 #else /* !HAVE_HSTRERROR */
214 return "Unknown host";
216 return "Host name lookup failure";
217 /* Errors below are probably WIN32 only */
220 return "Invalid argument";
224 return "Address family not supported";
228 return "Not enough memory";
231 #ifndef WIN32_ONLY_COMPILER /* MSVC complains because another case has the
234 return "No host data of that type was found";
239 return "Class type not found";
243 return "Socket type not supported";
246 return "Unknown server error";
248 #endif /* HAVE_HSTRERROR */
250 #endif /* HAVE_GAI_STRERROR */
254 * getaddrinfo_unix - get unix socket info using IPv6-compatible API
256 * Bugs: only one addrinfo is set even though hintsp is NULL or
258 * AI_CANONNAME is not supported.
262 getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
263 struct addrinfo ** result)
265 struct addrinfo hints;
266 struct addrinfo *aip;
267 struct sockaddr_un *unp;
271 memset(&hints, 0, sizeof(hints));
273 if (strlen(path) >= sizeof(unp->sun_path))
278 hints.ai_family = AF_UNIX;
279 hints.ai_socktype = SOCK_STREAM;
282 memcpy(&hints, hintsp, sizeof(hints));
284 if (hints.ai_socktype == 0)
285 hints.ai_socktype = SOCK_STREAM;
287 if (hints.ai_family != AF_UNIX)
289 /* shouldn't have been called */
293 aip = calloc(1, sizeof(struct addrinfo));
297 unp = calloc(1, sizeof(struct sockaddr_un));
304 aip->ai_family = AF_UNIX;
305 aip->ai_socktype = hints.ai_socktype;
306 aip->ai_protocol = hints.ai_protocol;
308 aip->ai_canonname = NULL;
311 unp->sun_family = AF_UNIX;
312 aip->ai_addr = (struct sockaddr *) unp;
313 aip->ai_addrlen = sizeof(struct sockaddr_un);
315 strcpy(unp->sun_path, path);
317 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
318 unp->sun_len = sizeof(struct sockaddr_un);
325 * Convert an address to a hostname.
328 getnameinfo_unix(const struct sockaddr_un * sa, int salen,
329 char *node, int nodelen,
330 char *service, int servicelen,
335 /* Invalid arguments. */
336 if (sa == NULL || sa->sun_family != AF_UNIX ||
337 (node == NULL && service == NULL))
340 /* We don't support those. */
341 if ((node && !(flags & NI_NUMERICHOST))
342 || (service && !(flags & NI_NUMERICSERV)))
347 ret = snprintf(node, nodelen, "%s", "[local]");
348 if (ret == -1 || ret > nodelen)
354 ret = snprintf(service, servicelen, "%s", sa->sun_path);
355 if (ret == -1 || ret > servicelen)
364 * rangeSockAddr - is addr within the subnet specified by netaddr/netmask ?
366 * Note: caller must already have verified that all three addresses are
367 * in the same address family; and AF_UNIX addresses are not supported.
370 rangeSockAddr(const struct sockaddr_storage * addr,
371 const struct sockaddr_storage * netaddr,
372 const struct sockaddr_storage * netmask)
374 if (addr->ss_family == AF_INET)
375 return rangeSockAddrAF_INET((struct sockaddr_in *) addr,
376 (struct sockaddr_in *) netaddr,
377 (struct sockaddr_in *) netmask);
379 else if (addr->ss_family == AF_INET6)
380 return rangeSockAddrAF_INET6((struct sockaddr_in6 *) addr,
381 (struct sockaddr_in6 *) netaddr,
382 (struct sockaddr_in6 *) netmask);
389 rangeSockAddrAF_INET(const struct sockaddr_in * addr,
390 const struct sockaddr_in * netaddr,
391 const struct sockaddr_in * netmask)
393 if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
394 netmask->sin_addr.s_addr) == 0)
403 rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
404 const struct sockaddr_in6 * netaddr,
405 const struct sockaddr_in6 * netmask)
409 for (i = 0; i < 16; i++)
411 if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
412 netmask->sin6_addr.s6_addr[i]) != 0)
421 * SockAddr_cidr_mask - make a network mask of the appropriate family
422 * and required number of significant bits
424 * The resulting mask is placed in *mask, which had better be big enough.
426 * Return value is 0 if okay, -1 if not.
429 SockAddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
434 bits = strtol(numbits, &endptr, 10);
436 if (*numbits == '\0' || *endptr != '\0')
443 struct sockaddr_in mask4;
446 if (bits < 0 || bits > 32)
448 /* avoid "x << 32", which is not portable */
450 maskl = (0xffffffffUL << (32 - (int) bits))
454 mask4.sin_addr.s_addr = htonl(maskl);
455 memcpy(mask, &mask4, sizeof(mask4));
462 struct sockaddr_in6 mask6;
465 if (bits < 0 || bits > 128)
467 for (i = 0; i < 16; i++)
470 mask6.sin6_addr.s6_addr[i] = 0;
472 mask6.sin6_addr.s6_addr[i] = 0xff;
475 mask6.sin6_addr.s6_addr[i] =
476 (0xff << (8 - (int) bits)) & 0xff;
480 memcpy(mask, &mask6, sizeof(mask6));
488 mask->ss_family = family;
496 * promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
497 * the standard convention for IPv4 addresses mapped into IPv6 world
499 * The passed addr is modified in place; be sure it is large enough to
500 * hold the result! Note that we only worry about setting the fields
501 * that rangeSockAddr will look at.
504 promote_v4_to_v6_addr(struct sockaddr_storage * addr)
506 struct sockaddr_in addr4;
507 struct sockaddr_in6 addr6;
510 memcpy(&addr4, addr, sizeof(addr4));
511 ip4addr = ntohl(addr4.sin_addr.s_addr);
513 memset(&addr6, 0, sizeof(addr6));
515 addr6.sin6_family = AF_INET6;
517 addr6.sin6_addr.s6_addr[10] = 0xff;
518 addr6.sin6_addr.s6_addr[11] = 0xff;
519 addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
520 addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
521 addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
522 addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
524 memcpy(addr, &addr6, sizeof(addr6));
528 * promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
529 * the standard convention for IPv4 addresses mapped into IPv6 world
531 * This must be different from promote_v4_to_v6_addr because we want to
532 * set the high-order bits to 1's not 0's.
534 * The passed addr is modified in place; be sure it is large enough to
535 * hold the result! Note that we only worry about setting the fields
536 * that rangeSockAddr will look at.
539 promote_v4_to_v6_mask(struct sockaddr_storage * addr)
541 struct sockaddr_in addr4;
542 struct sockaddr_in6 addr6;
546 memcpy(&addr4, addr, sizeof(addr4));
547 ip4addr = ntohl(addr4.sin_addr.s_addr);
549 memset(&addr6, 0, sizeof(addr6));
551 addr6.sin6_family = AF_INET6;
553 for (i = 0; i < 12; i++)
554 addr6.sin6_addr.s6_addr[i] = 0xff;
556 addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
557 addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
558 addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
559 addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
561 memcpy(addr, &addr6, sizeof(addr6));
564 #endif /* HAVE_IPV6 */