]> granicus.if.org Git - postgresql/blob - src/backend/libpq/ip.c
When a GUC string variable is not set, print the empty string (in SHOW etc.),
[postgresql] / src / backend / libpq / ip.c
1 /*-------------------------------------------------------------------------
2  *
3  * ip.c
4  *        IPv6-aware network access.
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/libpq/ip.c,v 1.36 2006/06/20 19:56:52 tgl Exp $
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 /* This is intended to be used in both frontend and backend, so use c.h */
21 #include "c.h"
22
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <netinet/in.h>
29 #ifdef HAVE_NETINET_TCP_H
30 #include <netinet/tcp.h>
31 #endif
32 #include <arpa/inet.h>
33 #include <sys/file.h>
34
35 #include "libpq/ip.h"
36
37
38 static int range_sockaddr_AF_INET(const struct sockaddr_in * addr,
39                                            const struct sockaddr_in * netaddr,
40                                            const struct sockaddr_in * netmask);
41
42 #ifdef HAVE_IPV6
43 static int range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr,
44                                                 const struct sockaddr_in6 * netaddr,
45                                                 const struct sockaddr_in6 * netmask);
46 #endif
47
48 #ifdef  HAVE_UNIX_SOCKETS
49 static int getaddrinfo_unix(const char *path,
50                                  const struct addrinfo * hintsp,
51                                  struct addrinfo ** result);
52
53 static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
54                                  char *node, int nodelen,
55                                  char *service, int servicelen,
56                                  int flags);
57 #endif
58
59
60 /*
61  *      pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
62  */
63 int
64 pg_getaddrinfo_all(const char *hostname, const char *servname,
65                                    const struct addrinfo * hintp, struct addrinfo ** result)
66 {
67         /* not all versions of getaddrinfo() zero *result on failure */
68         *result = NULL;
69
70 #ifdef HAVE_UNIX_SOCKETS
71         if (hintp->ai_family == AF_UNIX)
72                 return getaddrinfo_unix(servname, hintp, result);
73 #endif
74
75         /* NULL has special meaning to getaddrinfo(). */
76         return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
77                                            servname, hintp, result);
78 }
79
80
81 /*
82  *      pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
83  *
84  * Note: the ai_family field of the original hint structure must be passed
85  * so that we can tell whether the addrinfo struct was built by the system's
86  * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
87  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
88  * not safe to look at ai_family in the addrinfo itself.
89  */
90 void
91 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
92 {
93 #ifdef HAVE_UNIX_SOCKETS
94         if (hint_ai_family == AF_UNIX)
95         {
96                 /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
97                 while (ai != NULL)
98                 {
99                         struct addrinfo *p = ai;
100
101                         ai = ai->ai_next;
102                         free(p->ai_addr);
103                         free(p);
104                 }
105         }
106         else
107 #endif   /* HAVE_UNIX_SOCKETS */
108         {
109                 /* struct was built by getaddrinfo() */
110                 if (ai != NULL)
111                         freeaddrinfo(ai);
112         }
113 }
114
115
116 /*
117  *      pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
118  *
119  * The API of this routine differs from the standard getnameinfo() definition
120  * in two ways: first, the addr parameter is declared as sockaddr_storage
121  * rather than struct sockaddr, and second, the node and service fields are
122  * guaranteed to be filled with something even on failure return.
123  */
124 int
125 pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen,
126                                    char *node, int nodelen,
127                                    char *service, int servicelen,
128                                    int flags)
129 {
130         int                     rc;
131
132 #ifdef HAVE_UNIX_SOCKETS
133         if (addr && addr->ss_family == AF_UNIX)
134                 rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
135                                                           node, nodelen,
136                                                           service, servicelen,
137                                                           flags);
138         else
139 #endif
140                 rc = getnameinfo((const struct sockaddr *) addr, salen,
141                                                  node, nodelen,
142                                                  service, servicelen,
143                                                  flags);
144
145         if (rc != 0)
146         {
147                 if (node)
148                         StrNCpy(node, "???", nodelen);
149                 if (service)
150                         StrNCpy(service, "???", servicelen);
151         }
152
153         return rc;
154 }
155
156
157 #if defined(HAVE_UNIX_SOCKETS)
158
159 /* -------
160  *      getaddrinfo_unix - get unix socket info using IPv6-compatible API
161  *
162  *      Bugs: only one addrinfo is set even though hintsp is NULL or
163  *                ai_socktype is 0
164  *                AI_CANONNAME is not supported.
165  * -------
166  */
167 static int
168 getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
169                                  struct addrinfo ** result)
170 {
171         struct addrinfo hints;
172         struct addrinfo *aip;
173         struct sockaddr_un *unp;
174
175         *result = NULL;
176
177         MemSet(&hints, 0, sizeof(hints));
178
179         if (strlen(path) >= sizeof(unp->sun_path))
180                 return EAI_FAIL;
181
182         if (hintsp == NULL)
183         {
184                 hints.ai_family = AF_UNIX;
185                 hints.ai_socktype = SOCK_STREAM;
186         }
187         else
188                 memcpy(&hints, hintsp, sizeof(hints));
189
190         if (hints.ai_socktype == 0)
191                 hints.ai_socktype = SOCK_STREAM;
192
193         if (hints.ai_family != AF_UNIX)
194         {
195                 /* shouldn't have been called */
196                 return EAI_FAIL;
197         }
198
199         aip = calloc(1, sizeof(struct addrinfo));
200         if (aip == NULL)
201                 return EAI_MEMORY;
202
203         unp = calloc(1, sizeof(struct sockaddr_un));
204         if (unp == NULL)
205         {
206                 free(aip);
207                 return EAI_MEMORY;
208         }
209
210         aip->ai_family = AF_UNIX;
211         aip->ai_socktype = hints.ai_socktype;
212         aip->ai_protocol = hints.ai_protocol;
213         aip->ai_next = NULL;
214         aip->ai_canonname = NULL;
215         *result = aip;
216
217         unp->sun_family = AF_UNIX;
218         aip->ai_addr = (struct sockaddr *) unp;
219         aip->ai_addrlen = sizeof(struct sockaddr_un);
220
221         strcpy(unp->sun_path, path);
222
223 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
224         unp->sun_len = sizeof(struct sockaddr_un);
225 #endif
226
227         return 0;
228 }
229
230 /*
231  * Convert an address to a hostname.
232  */
233 static int
234 getnameinfo_unix(const struct sockaddr_un * sa, int salen,
235                                  char *node, int nodelen,
236                                  char *service, int servicelen,
237                                  int flags)
238 {
239         int                     ret = -1;
240
241         /* Invalid arguments. */
242         if (sa == NULL || sa->sun_family != AF_UNIX ||
243                 (node == NULL && service == NULL))
244                 return EAI_FAIL;
245
246         /* We don't support those. */
247         if ((node && !(flags & NI_NUMERICHOST))
248                 || (service && !(flags & NI_NUMERICSERV)))
249                 return EAI_FAIL;
250
251         if (node)
252         {
253                 ret = snprintf(node, nodelen, "%s", "[local]");
254                 if (ret == -1 || ret > nodelen)
255                         return EAI_MEMORY;
256         }
257
258         if (service)
259         {
260                 ret = snprintf(service, servicelen, "%s", sa->sun_path);
261                 if (ret == -1 || ret > servicelen)
262                         return EAI_MEMORY;
263         }
264
265         return 0;
266 }
267 #endif   /* HAVE_UNIX_SOCKETS */
268
269
270 /*
271  * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ?
272  *
273  * Note: caller must already have verified that all three addresses are
274  * in the same address family; and AF_UNIX addresses are not supported.
275  */
276 int
277 pg_range_sockaddr(const struct sockaddr_storage * addr,
278                                   const struct sockaddr_storage * netaddr,
279                                   const struct sockaddr_storage * netmask)
280 {
281         if (addr->ss_family == AF_INET)
282                 return range_sockaddr_AF_INET((struct sockaddr_in *) addr,
283                                                                           (struct sockaddr_in *) netaddr,
284                                                                           (struct sockaddr_in *) netmask);
285 #ifdef HAVE_IPV6
286         else if (addr->ss_family == AF_INET6)
287                 return range_sockaddr_AF_INET6((struct sockaddr_in6 *) addr,
288                                                                            (struct sockaddr_in6 *) netaddr,
289                                                                            (struct sockaddr_in6 *) netmask);
290 #endif
291         else
292                 return 0;
293 }
294
295 static int
296 range_sockaddr_AF_INET(const struct sockaddr_in * addr,
297                                            const struct sockaddr_in * netaddr,
298                                            const struct sockaddr_in * netmask)
299 {
300         if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
301                  netmask->sin_addr.s_addr) == 0)
302                 return 1;
303         else
304                 return 0;
305 }
306
307
308 #ifdef HAVE_IPV6
309
310 static int
311 range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr,
312                                                 const struct sockaddr_in6 * netaddr,
313                                                 const struct sockaddr_in6 * netmask)
314 {
315         int                     i;
316
317         for (i = 0; i < 16; i++)
318         {
319                 if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
320                          netmask->sin6_addr.s6_addr[i]) != 0)
321                         return 0;
322         }
323
324         return 1;
325 }
326 #endif   /* HAVE_IPV6 */
327
328 /*
329  *      pg_sockaddr_cidr_mask - make a network mask of the appropriate family
330  *        and required number of significant bits
331  *
332  * The resulting mask is placed in *mask, which had better be big enough.
333  *
334  * Return value is 0 if okay, -1 if not.
335  */
336 int
337 pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
338 {
339         long            bits;
340         char       *endptr;
341
342         bits = strtol(numbits, &endptr, 10);
343
344         if (*numbits == '\0' || *endptr != '\0')
345                 return -1;
346
347         switch (family)
348         {
349                 case AF_INET:
350                         {
351                                 struct sockaddr_in mask4;
352                                 long            maskl;
353
354                                 if (bits < 0 || bits > 32)
355                                         return -1;
356                                 /* avoid "x << 32", which is not portable */
357                                 if (bits > 0)
358                                         maskl = (0xffffffffUL << (32 - (int) bits))
359                                                 & 0xffffffffUL;
360                                 else
361                                         maskl = 0;
362                                 mask4.sin_addr.s_addr = htonl(maskl);
363                                 memcpy(mask, &mask4, sizeof(mask4));
364                                 break;
365                         }
366
367 #ifdef HAVE_IPV6
368                 case AF_INET6:
369                         {
370                                 struct sockaddr_in6 mask6;
371                                 int                     i;
372
373                                 if (bits < 0 || bits > 128)
374                                         return -1;
375                                 for (i = 0; i < 16; i++)
376                                 {
377                                         if (bits <= 0)
378                                                 mask6.sin6_addr.s6_addr[i] = 0;
379                                         else if (bits >= 8)
380                                                 mask6.sin6_addr.s6_addr[i] = 0xff;
381                                         else
382                                         {
383                                                 mask6.sin6_addr.s6_addr[i] =
384                                                         (0xff << (8 - (int) bits)) & 0xff;
385                                         }
386                                         bits -= 8;
387                                 }
388                                 memcpy(mask, &mask6, sizeof(mask6));
389                                 break;
390                         }
391 #endif
392                 default:
393                         return -1;
394         }
395
396         mask->ss_family = family;
397         return 0;
398 }
399
400
401 #ifdef HAVE_IPV6
402
403 /*
404  * pg_promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
405  *              the standard convention for IPv4 addresses mapped into IPv6 world
406  *
407  * The passed addr is modified in place; be sure it is large enough to
408  * hold the result!  Note that we only worry about setting the fields
409  * that pg_range_sockaddr will look at.
410  */
411 void
412 pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr)
413 {
414         struct sockaddr_in addr4;
415         struct sockaddr_in6 addr6;
416         uint32          ip4addr;
417
418         memcpy(&addr4, addr, sizeof(addr4));
419         ip4addr = ntohl(addr4.sin_addr.s_addr);
420
421         memset(&addr6, 0, sizeof(addr6));
422
423         addr6.sin6_family = AF_INET6;
424
425         addr6.sin6_addr.s6_addr[10] = 0xff;
426         addr6.sin6_addr.s6_addr[11] = 0xff;
427         addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
428         addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
429         addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
430         addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
431
432         memcpy(addr, &addr6, sizeof(addr6));
433 }
434
435 /*
436  * pg_promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
437  *              the standard convention for IPv4 addresses mapped into IPv6 world
438  *
439  * This must be different from pg_promote_v4_to_v6_addr because we want to
440  * set the high-order bits to 1's not 0's.
441  *
442  * The passed addr is modified in place; be sure it is large enough to
443  * hold the result!  Note that we only worry about setting the fields
444  * that pg_range_sockaddr will look at.
445  */
446 void
447 pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr)
448 {
449         struct sockaddr_in addr4;
450         struct sockaddr_in6 addr6;
451         uint32          ip4addr;
452         int                     i;
453
454         memcpy(&addr4, addr, sizeof(addr4));
455         ip4addr = ntohl(addr4.sin_addr.s_addr);
456
457         memset(&addr6, 0, sizeof(addr6));
458
459         addr6.sin6_family = AF_INET6;
460
461         for (i = 0; i < 12; i++)
462                 addr6.sin6_addr.s6_addr[i] = 0xff;
463
464         addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
465         addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
466         addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
467         addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
468
469         memcpy(addr, &addr6, sizeof(addr6));
470 }
471
472 #endif   /* HAVE_IPV6 */