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/types.h>
28 #include <sys/stat.h>
29 #include <sys/socket.h>
30 #include <netdb.h>
31 #include <netinet/in.h>
32 #ifdef HAVE_NETINET_TCP_H
33 #include <netinet/tcp.h>
34 #endif
35 #include <arpa/inet.h>
36 #include <sys/file.h>
37 
38 #include "common/ip.h"
39 
40 
41 
42 #ifdef HAVE_UNIX_SOCKETS
43 static int getaddrinfo_unix(const char *path,
44  const struct addrinfo * hintsp,
45  struct addrinfo ** result);
46 
47 static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
48  char *node, int nodelen,
49  char *service, int servicelen,
50  int flags);
51 #endif
52 
53 
54 /*
55  * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
56  */
57 int
58 pg_getaddrinfo_all(const char *hostname, const char *servname,
59  const struct addrinfo * hintp, struct addrinfo ** result)
60 {
61  int rc;
62 
63  /* not all versions of getaddrinfo() zero *result on failure */
64  *result = NULL;
65 
66 #ifdef HAVE_UNIX_SOCKETS
67  if (hintp->ai_family == AF_UNIX)
68  return getaddrinfo_unix(servname, hintp, result);
69 #endif
70 
71  /* NULL has special meaning to getaddrinfo(). */
72  rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
73  servname, hintp, result);
74 
75  return rc;
76 }
77 
78 
79 /*
80  * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
81  *
82  * Note: the ai_family field of the original hint structure must be passed
83  * so that we can tell whether the addrinfo struct was built by the system's
84  * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions
85  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
86  * not safe to look at ai_family in the addrinfo itself.
87  */
88 void
89 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
90 {
91 #ifdef HAVE_UNIX_SOCKETS
92  if (hint_ai_family == AF_UNIX)
93  {
94  /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
95  while (ai != NULL)
96  {
97  struct addrinfo *p = ai;
98 
99  ai = ai->ai_next;
100  free(p->ai_addr);
101  free(p);
102  }
103  }
104  else
105 #endif /* HAVE_UNIX_SOCKETS */
106  {
107  /* struct was built by getaddrinfo() */
108  if (ai != NULL)
109  freeaddrinfo(ai);
110  }
111 }
112 
113 
114 /*
115  * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
116  *
117  * The API of this routine differs from the standard getnameinfo() definition
118  * in two ways: first, the addr parameter is declared as sockaddr_storage
119  * rather than struct sockaddr, and second, the node and service fields are
120  * guaranteed to be filled with something even on failure return.
121  */
122 int
123 pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen,
124  char *node, int nodelen,
125  char *service, int servicelen,
126  int flags)
127 {
128  int rc;
129 
130 #ifdef HAVE_UNIX_SOCKETS
131  if (addr && addr->ss_family == AF_UNIX)
132  rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
133  node, nodelen,
134  service, servicelen,
135  flags);
136  else
137 #endif
138  rc = getnameinfo((const struct sockaddr *) addr, salen,
139  node, nodelen,
140  service, servicelen,
141  flags);
142 
143  if (rc != 0)
144  {
145  if (node)
146  strlcpy(node, "???", nodelen);
147  if (service)
148  strlcpy(service, "???", servicelen);
149  }
150 
151  return rc;
152 }
153 
154 
155 #if defined(HAVE_UNIX_SOCKETS)
156 
157 /* -------
158  * getaddrinfo_unix - get unix socket info using IPv6-compatible API
159  *
160  * Bugs: only one addrinfo is set even though hintsp is NULL or
161  * ai_socktype is 0
162  * AI_CANONNAME is not supported.
163  * -------
164  */
165 static int
166 getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
167  struct addrinfo ** result)
168 {
169  struct addrinfo hints;
170  struct addrinfo *aip;
171  struct sockaddr_un *unp;
172 
173  *result = NULL;
174 
175  MemSet(&hints, 0, sizeof(hints));
176 
177  if (strlen(path) >= sizeof(unp->sun_path))
178  return EAI_FAIL;
179 
180  if (hintsp == NULL)
181  {
182  hints.ai_family = AF_UNIX;
183  hints.ai_socktype = SOCK_STREAM;
184  }
185  else
186  memcpy(&hints, hintsp, sizeof(hints));
187 
188  if (hints.ai_socktype == 0)
189  hints.ai_socktype = SOCK_STREAM;
190 
191  if (hints.ai_family != AF_UNIX)
192  {
193  /* shouldn't have been called */
194  return EAI_FAIL;
195  }
196 
197  aip = calloc(1, sizeof(struct addrinfo));
198  if (aip == NULL)
199  return EAI_MEMORY;
200 
201  unp = calloc(1, sizeof(struct sockaddr_un));
202  if (unp == NULL)
203  {
204  free(aip);
205  return EAI_MEMORY;
206  }
207 
208  aip->ai_family = AF_UNIX;
209  aip->ai_socktype = hints.ai_socktype;
210  aip->ai_protocol = hints.ai_protocol;
211  aip->ai_next = NULL;
212  aip->ai_canonname = NULL;
213  *result = aip;
214 
215  unp->sun_family = AF_UNIX;
216  aip->ai_addr = (struct sockaddr *) unp;
217  aip->ai_addrlen = sizeof(struct sockaddr_un);
218 
219  strcpy(unp->sun_path, path);
220 
221 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
222  unp->sun_len = sizeof(struct sockaddr_un);
223 #endif
224 
225  return 0;
226 }
227 
228 /*
229  * Convert an address to a hostname.
230  */
231 static int
232 getnameinfo_unix(const struct sockaddr_un * sa, int salen,
233  char *node, int nodelen,
234  char *service, int servicelen,
235  int flags)
236 {
237  int ret = -1;
238 
239  /* Invalid arguments. */
240  if (sa == NULL || sa->sun_family != AF_UNIX ||
241  (node == NULL && service == NULL))
242  return EAI_FAIL;
243 
244  if (node)
245  {
246  ret = snprintf(node, nodelen, "%s", "[local]");
247  if (ret == -1 || ret > nodelen)
248  return EAI_MEMORY;
249  }
250 
251  if (service)
252  {
253  ret = snprintf(service, servicelen, "%s", sa->sun_path);
254  if (ret == -1 || ret > servicelen)
255  return EAI_MEMORY;
256  }
257 
258  return 0;
259 }
260 #endif /* HAVE_UNIX_SOCKETS */
#define calloc(a, b)
Definition: header.h:50
#define getaddrinfo
Definition: getaddrinfo.h:138
void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
Definition: ip.c:89
#define EAI_FAIL
Definition: getaddrinfo.h:36
#define freeaddrinfo
Definition: getaddrinfo.h:143
#define MemSet(start, val, len)
Definition: c.h:852
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:58
char * ai_canonname
Definition: getaddrinfo.h:108
#define free(a)
Definition: header.h:60
int ai_protocol
Definition: getaddrinfo.h:105
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define NULL
Definition: c.h:226
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:123
int ai_socktype
Definition: getaddrinfo.h:104
struct addrinfo * ai_next
Definition: getaddrinfo.h:109
#define getnameinfo
Definition: getaddrinfo.h:153
size_t ai_addrlen
Definition: getaddrinfo.h:106
#define EAI_MEMORY
Definition: getaddrinfo.h:40
static char * hostname
Definition: pg_regress.c:86
struct sockaddr * ai_addr
Definition: getaddrinfo.h:107
int ai_family
Definition: getaddrinfo.h:103