PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
ip.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ip.c
4  * IPv6-aware network access.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/common/ip.c
12  *
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.
16  *
17  *-------------------------------------------------------------------------
18  */
19 
20 #ifndef FRONTEND
21 #include "postgres.h"
22 #else
23 #include "postgres_fe.h"
24 #endif
25 
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <netinet/in.h>
31 #ifdef HAVE_NETINET_TCP_H
32 #include <netinet/tcp.h>
33 #endif
34 #include <arpa/inet.h>
35 #include <sys/file.h>
36 
37 #include "common/ip.h"
38 
39 
40 
41 #ifdef HAVE_UNIX_SOCKETS
42 static int getaddrinfo_unix(const char *path,
43  const struct addrinfo *hintsp,
44  struct addrinfo **result);
45 
46 static int getnameinfo_unix(const struct sockaddr_un *sa, int salen,
47  char *node, int nodelen,
48  char *service, int servicelen,
49  int flags);
50 #endif
51 
52 
53 /*
54  * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
55  */
56 int
57 pg_getaddrinfo_all(const char *hostname, const char *servname,
58  const struct addrinfo *hintp, struct addrinfo **result)
59 {
60  int rc;
61 
62  /* not all versions of getaddrinfo() zero *result on failure */
63  *result = NULL;
64 
65 #ifdef HAVE_UNIX_SOCKETS
66  if (hintp->ai_family == AF_UNIX)
67  return getaddrinfo_unix(servname, hintp, result);
68 #endif
69 
70  /* NULL has special meaning to getaddrinfo(). */
71  rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
72  servname, hintp, result);
73 
74  return rc;
75 }
76 
77 
78 /*
79  * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
80  *
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.
86  */
87 void
88 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
89 {
90 #ifdef HAVE_UNIX_SOCKETS
91  if (hint_ai_family == AF_UNIX)
92  {
93  /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
94  while (ai != NULL)
95  {
96  struct addrinfo *p = ai;
97 
98  ai = ai->ai_next;
99  free(p->ai_addr);
100  free(p);
101  }
102  }
103  else
104 #endif /* HAVE_UNIX_SOCKETS */
105  {
106  /* struct was built by getaddrinfo() */
107  if (ai != NULL)
108  freeaddrinfo(ai);
109  }
110 }
111 
112 
113 /*
114  * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
115  *
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.
120  */
121 int
122 pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen,
123  char *node, int nodelen,
124  char *service, int servicelen,
125  int flags)
126 {
127  int rc;
128 
129 #ifdef HAVE_UNIX_SOCKETS
130  if (addr && addr->ss_family == AF_UNIX)
131  rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
132  node, nodelen,
133  service, servicelen,
134  flags);
135  else
136 #endif
137  rc = getnameinfo((const struct sockaddr *) addr, salen,
138  node, nodelen,
139  service, servicelen,
140  flags);
141 
142  if (rc != 0)
143  {
144  if (node)
145  strlcpy(node, "???", nodelen);
146  if (service)
147  strlcpy(service, "???", servicelen);
148  }
149 
150  return rc;
151 }
152 
153 
154 #if defined(HAVE_UNIX_SOCKETS)
155 
156 /* -------
157  * getaddrinfo_unix - get unix socket info using IPv6-compatible API
158  *
159  * Bugs: only one addrinfo is set even though hintsp is NULL or
160  * ai_socktype is 0
161  * AI_CANONNAME is not supported.
162  * -------
163  */
164 static int
165 getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
166  struct addrinfo **result)
167 {
168  struct addrinfo hints;
169  struct addrinfo *aip;
170  struct sockaddr_un *unp;
171 
172  *result = NULL;
173 
174  MemSet(&hints, 0, sizeof(hints));
175 
176  if (strlen(path) >= sizeof(unp->sun_path))
177  return EAI_FAIL;
178 
179  if (hintsp == NULL)
180  {
181  hints.ai_family = AF_UNIX;
182  hints.ai_socktype = SOCK_STREAM;
183  }
184  else
185  memcpy(&hints, hintsp, sizeof(hints));
186 
187  if (hints.ai_socktype == 0)
188  hints.ai_socktype = SOCK_STREAM;
189 
190  if (hints.ai_family != AF_UNIX)
191  {
192  /* shouldn't have been called */
193  return EAI_FAIL;
194  }
195 
196  aip = calloc(1, sizeof(struct addrinfo));
197  if (aip == NULL)
198  return EAI_MEMORY;
199 
200  unp = calloc(1, sizeof(struct sockaddr_un));
201  if (unp == NULL)
202  {
203  free(aip);
204  return EAI_MEMORY;
205  }
206 
207  aip->ai_family = AF_UNIX;
208  aip->ai_socktype = hints.ai_socktype;
209  aip->ai_protocol = hints.ai_protocol;
210  aip->ai_next = NULL;
211  aip->ai_canonname = NULL;
212  *result = aip;
213 
214  unp->sun_family = AF_UNIX;
215  aip->ai_addr = (struct sockaddr *) unp;
216  aip->ai_addrlen = sizeof(struct sockaddr_un);
217 
218  strcpy(unp->sun_path, path);
219 
220 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
221  unp->sun_len = sizeof(struct sockaddr_un);
222 #endif
223 
224  return 0;
225 }
226 
227 /*
228  * Convert an address to a hostname.
229  */
230 static int
231 getnameinfo_unix(const struct sockaddr_un *sa, int salen,
232  char *node, int nodelen,
233  char *service, int servicelen,
234  int flags)
235 {
236  int ret = -1;
237 
238  /* Invalid arguments. */
239  if (sa == NULL || sa->sun_family != AF_UNIX ||
240  (node == NULL && service == NULL))
241  return EAI_FAIL;
242 
243  if (node)
244  {
245  ret = snprintf(node, nodelen, "%s", "[local]");
246  if (ret == -1 || ret > nodelen)
247  return EAI_MEMORY;
248  }
249 
250  if (service)
251  {
252  ret = snprintf(service, servicelen, "%s", sa->sun_path);
253  if (ret == -1 || ret > servicelen)
254  return EAI_MEMORY;
255  }
256 
257  return 0;
258 }
259 #endif /* HAVE_UNIX_SOCKETS */
#define calloc(a, b)
Definition: header.h:55
#define getaddrinfo
Definition: getaddrinfo.h:136
void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
Definition: ip.c:88
#define EAI_FAIL
Definition: getaddrinfo.h:36
#define freeaddrinfo
Definition: getaddrinfo.h:141
#define MemSet(start, val, len)
Definition: c.h:857
return result
Definition: formatting.c:1633
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo *hintp, struct addrinfo **result)
Definition: ip.c:57
char * ai_canonname
Definition: getaddrinfo.h:106
#define free(a)
Definition: header.h:65
int ai_protocol
Definition: getaddrinfo.h:103
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define NULL
Definition: c.h:229
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:122
int ai_socktype
Definition: getaddrinfo.h:102
struct addrinfo * ai_next
Definition: getaddrinfo.h:107
#define getnameinfo
Definition: getaddrinfo.h:151
size_t ai_addrlen
Definition: getaddrinfo.h:104
#define EAI_MEMORY
Definition: getaddrinfo.h:40
static char * hostname
Definition: pg_regress.c:88
struct sockaddr * ai_addr
Definition: getaddrinfo.h:105
int ai_family
Definition: getaddrinfo.h:101