1 /*-------------------------------------------------------------------------
4 * IPv6-aware network access.
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 * This file and the IPV6 implementation were initially provided by
14 * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
15 * http://www.lbsd.net.
17 *-------------------------------------------------------------------------
23 #include "postgres_fe.h"
28 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #ifdef HAVE_NETINET_TCP_H
32 #include <netinet/tcp.h>
34 #include <arpa/inet.h>
37 #include "common/ip.h"
41 #ifdef HAVE_UNIX_SOCKETS
42 static int getaddrinfo_unix(const char *path,
43 const struct addrinfo *hintsp,
44 struct addrinfo **result);
46 static int getnameinfo_unix(const struct sockaddr_un *sa, int salen,
47 char *node, int nodelen,
48 char *service, int servicelen,
54 * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
57 pg_getaddrinfo_all(const char *hostname, const char *servname,
58 const struct addrinfo *hintp, struct addrinfo **result)
62 /* not all versions of getaddrinfo() zero *result on failure */
65 #ifdef HAVE_UNIX_SOCKETS
66 if (hintp->ai_family == AF_UNIX)
67 return getaddrinfo_unix(servname, hintp, result);
70 /* NULL has special meaning to getaddrinfo(). */
71 rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
72 servname, hintp, result);
79 * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
81 * Note: the ai_family field of the original hint structure must be passed
82 * so that we can tell whether the addrinfo struct was built by the system's
83 * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions
84 * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
85 * not safe to look at ai_family in the addrinfo itself.
88 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
90 #ifdef HAVE_UNIX_SOCKETS
91 if (hint_ai_family == AF_UNIX)
93 /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
96 struct addrinfo *p = ai;
104 #endif /* HAVE_UNIX_SOCKETS */
106 /* struct was built by getaddrinfo() */
114 * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
116 * The API of this routine differs from the standard getnameinfo() definition
117 * in two ways: first, the addr parameter is declared as sockaddr_storage
118 * rather than struct sockaddr, and second, the node and service fields are
119 * guaranteed to be filled with something even on failure return.
122 pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen,
123 char *node, int nodelen,
124 char *service, int servicelen,
129 #ifdef HAVE_UNIX_SOCKETS
130 if (addr && addr->ss_family == AF_UNIX)
131 rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
137 rc = getnameinfo((const struct sockaddr *) addr, salen,
145 strlcpy(node, "???", nodelen);
147 strlcpy(service, "???", servicelen);
154 #if defined(HAVE_UNIX_SOCKETS)
157 * getaddrinfo_unix - get unix socket info using IPv6-compatible API
159 * Bugs: only one addrinfo is set even though hintsp is NULL or
161 * AI_CANONNAME is not supported.
165 getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
166 struct addrinfo **result)
168 struct addrinfo hints;
169 struct addrinfo *aip;
170 struct sockaddr_un *unp;
174 MemSet(&hints, 0, sizeof(hints));
176 if (strlen(path) >= sizeof(unp->sun_path))
181 hints.ai_family = AF_UNIX;
182 hints.ai_socktype = SOCK_STREAM;
185 memcpy(&hints, hintsp, sizeof(hints));
187 if (hints.ai_socktype == 0)
188 hints.ai_socktype = SOCK_STREAM;
190 if (hints.ai_family != AF_UNIX)
192 /* shouldn't have been called */
196 aip = calloc(1, sizeof(struct addrinfo));
200 unp = calloc(1, sizeof(struct sockaddr_un));
207 aip->ai_family = AF_UNIX;
208 aip->ai_socktype = hints.ai_socktype;
209 aip->ai_protocol = hints.ai_protocol;
211 aip->ai_canonname = NULL;
214 unp->sun_family = AF_UNIX;
215 aip->ai_addr = (struct sockaddr *) unp;
216 aip->ai_addrlen = sizeof(struct sockaddr_un);
218 strcpy(unp->sun_path, path);
220 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
221 unp->sun_len = sizeof(struct sockaddr_un);
228 * Convert an address to a hostname.
231 getnameinfo_unix(const struct sockaddr_un *sa, int salen,
232 char *node, int nodelen,
233 char *service, int servicelen,
238 /* Invalid arguments. */
239 if (sa == NULL || sa->sun_family != AF_UNIX ||
240 (node == NULL && service == NULL))
245 ret = snprintf(node, nodelen, "%s", "[local]");
246 if (ret == -1 || ret > nodelen)
252 ret = snprintf(service, servicelen, "%s", sa->sun_path);
253 if (ret == -1 || ret > servicelen)
259 #endif /* HAVE_UNIX_SOCKETS */