]> granicus.if.org Git - postgresql/blob - src/backend/libpq/ip.c
Reduce hash size for compute_array_stats, compute_tsvector_stats.
[postgresql] / src / backend / libpq / ip.c
1 /*-------------------------------------------------------------------------
2  *
3  * ip.c
4  *        IPv6-aware network access.
5  *
6  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/libpq/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 /* 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         int                     rc;
68
69         /* not all versions of getaddrinfo() zero *result on failure */
70         *result = NULL;
71
72 #ifdef HAVE_UNIX_SOCKETS
73         if (hintp->ai_family == AF_UNIX)
74                 return getaddrinfo_unix(servname, hintp, result);
75 #endif
76
77         /* NULL has special meaning to getaddrinfo(). */
78         rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
79                                          servname, hintp, result);
80
81         return rc;
82 }
83
84
85 /*
86  *      pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
87  *
88  * Note: the ai_family field of the original hint structure must be passed
89  * so that we can tell whether the addrinfo struct was built by the system's
90  * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
91  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
92  * not safe to look at ai_family in the addrinfo itself.
93  */
94 void
95 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
96 {
97 #ifdef HAVE_UNIX_SOCKETS
98         if (hint_ai_family == AF_UNIX)
99         {
100                 /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
101                 while (ai != NULL)
102                 {
103                         struct addrinfo *p = ai;
104
105                         ai = ai->ai_next;
106                         free(p->ai_addr);
107                         free(p);
108                 }
109         }
110         else
111 #endif   /* HAVE_UNIX_SOCKETS */
112         {
113                 /* struct was built by getaddrinfo() */
114                 if (ai != NULL)
115                         freeaddrinfo(ai);
116         }
117 }
118
119
120 /*
121  *      pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
122  *
123  * The API of this routine differs from the standard getnameinfo() definition
124  * in two ways: first, the addr parameter is declared as sockaddr_storage
125  * rather than struct sockaddr, and second, the node and service fields are
126  * guaranteed to be filled with something even on failure return.
127  */
128 int
129 pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen,
130                                    char *node, int nodelen,
131                                    char *service, int servicelen,
132                                    int flags)
133 {
134         int                     rc;
135
136 #ifdef HAVE_UNIX_SOCKETS
137         if (addr && addr->ss_family == AF_UNIX)
138                 rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
139                                                           node, nodelen,
140                                                           service, servicelen,
141                                                           flags);
142         else
143 #endif
144                 rc = getnameinfo((const struct sockaddr *) addr, salen,
145                                                  node, nodelen,
146                                                  service, servicelen,
147                                                  flags);
148
149         if (rc != 0)
150         {
151                 if (node)
152                         strlcpy(node, "???", nodelen);
153                 if (service)
154                         strlcpy(service, "???", servicelen);
155         }
156
157         return rc;
158 }
159
160
161 #if defined(HAVE_UNIX_SOCKETS)
162
163 /* -------
164  *      getaddrinfo_unix - get unix socket info using IPv6-compatible API
165  *
166  *      Bugs: only one addrinfo is set even though hintsp is NULL or
167  *                ai_socktype is 0
168  *                AI_CANONNAME is not supported.
169  * -------
170  */
171 static int
172 getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
173                                  struct addrinfo ** result)
174 {
175         struct addrinfo hints;
176         struct addrinfo *aip;
177         struct sockaddr_un *unp;
178
179         *result = NULL;
180
181         MemSet(&hints, 0, sizeof(hints));
182
183         if (strlen(path) >= sizeof(unp->sun_path))
184                 return EAI_FAIL;
185
186         if (hintsp == NULL)
187         {
188                 hints.ai_family = AF_UNIX;
189                 hints.ai_socktype = SOCK_STREAM;
190         }
191         else
192                 memcpy(&hints, hintsp, sizeof(hints));
193
194         if (hints.ai_socktype == 0)
195                 hints.ai_socktype = SOCK_STREAM;
196
197         if (hints.ai_family != AF_UNIX)
198         {
199                 /* shouldn't have been called */
200                 return EAI_FAIL;
201         }
202
203         aip = calloc(1, sizeof(struct addrinfo));
204         if (aip == NULL)
205                 return EAI_MEMORY;
206
207         unp = calloc(1, sizeof(struct sockaddr_un));
208         if (unp == NULL)
209         {
210                 free(aip);
211                 return EAI_MEMORY;
212         }
213
214         aip->ai_family = AF_UNIX;
215         aip->ai_socktype = hints.ai_socktype;
216         aip->ai_protocol = hints.ai_protocol;
217         aip->ai_next = NULL;
218         aip->ai_canonname = NULL;
219         *result = aip;
220
221         unp->sun_family = AF_UNIX;
222         aip->ai_addr = (struct sockaddr *) unp;
223         aip->ai_addrlen = sizeof(struct sockaddr_un);
224
225         strcpy(unp->sun_path, path);
226
227 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
228         unp->sun_len = sizeof(struct sockaddr_un);
229 #endif
230
231         return 0;
232 }
233
234 /*
235  * Convert an address to a hostname.
236  */
237 static int
238 getnameinfo_unix(const struct sockaddr_un * sa, int salen,
239                                  char *node, int nodelen,
240                                  char *service, int servicelen,
241                                  int flags)
242 {
243         int                     ret = -1;
244
245         /* Invalid arguments. */
246         if (sa == NULL || sa->sun_family != AF_UNIX ||
247                 (node == NULL && service == NULL))
248                 return EAI_FAIL;
249
250         /* We don't support those. */
251         if ((node && !(flags & NI_NUMERICHOST))
252                 || (service && !(flags & NI_NUMERICSERV)))
253                 return EAI_FAIL;
254
255         if (node)
256         {
257                 ret = snprintf(node, nodelen, "%s", "[local]");
258                 if (ret == -1 || ret > nodelen)
259                         return EAI_MEMORY;
260         }
261
262         if (service)
263         {
264                 ret = snprintf(service, servicelen, "%s", sa->sun_path);
265                 if (ret == -1 || ret > servicelen)
266                         return EAI_MEMORY;
267         }
268
269         return 0;
270 }
271 #endif   /* HAVE_UNIX_SOCKETS */
272
273
274 /*
275  * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ?
276  *
277  * Note: caller must already have verified that all three addresses are
278  * in the same address family; and AF_UNIX addresses are not supported.
279  */
280 int
281 pg_range_sockaddr(const struct sockaddr_storage * addr,
282                                   const struct sockaddr_storage * netaddr,
283                                   const struct sockaddr_storage * netmask)
284 {
285         if (addr->ss_family == AF_INET)
286                 return range_sockaddr_AF_INET((const struct sockaddr_in *) addr,
287                                                                           (const struct sockaddr_in *) netaddr,
288                                                                           (const struct sockaddr_in *) netmask);
289 #ifdef HAVE_IPV6
290         else if (addr->ss_family == AF_INET6)
291                 return range_sockaddr_AF_INET6((const struct sockaddr_in6 *) addr,
292                                                                            (const struct sockaddr_in6 *) netaddr,
293                                                                            (const struct sockaddr_in6 *) netmask);
294 #endif
295         else
296                 return 0;
297 }
298
299 static int
300 range_sockaddr_AF_INET(const struct sockaddr_in * addr,
301                                            const struct sockaddr_in * netaddr,
302                                            const struct sockaddr_in * netmask)
303 {
304         if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
305                  netmask->sin_addr.s_addr) == 0)
306                 return 1;
307         else
308                 return 0;
309 }
310
311
312 #ifdef HAVE_IPV6
313
314 static int
315 range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr,
316                                                 const struct sockaddr_in6 * netaddr,
317                                                 const struct sockaddr_in6 * netmask)
318 {
319         int                     i;
320
321         for (i = 0; i < 16; i++)
322         {
323                 if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
324                          netmask->sin6_addr.s6_addr[i]) != 0)
325                         return 0;
326         }
327
328         return 1;
329 }
330 #endif   /* HAVE_IPV6 */
331
332 /*
333  *      pg_sockaddr_cidr_mask - make a network mask of the appropriate family
334  *        and required number of significant bits
335  *
336  * numbits can be null, in which case the mask is fully set.
337  *
338  * The resulting mask is placed in *mask, which had better be big enough.
339  *
340  * Return value is 0 if okay, -1 if not.
341  */
342 int
343 pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
344 {
345         long            bits;
346         char       *endptr;
347
348         if (numbits == NULL)
349         {
350                 bits = (family == AF_INET) ? 32 : 128;
351         }
352         else
353         {
354                 bits = strtol(numbits, &endptr, 10);
355                 if (*numbits == '\0' || *endptr != '\0')
356                         return -1;
357         }
358
359         switch (family)
360         {
361                 case AF_INET:
362                         {
363                                 struct sockaddr_in mask4;
364                                 long            maskl;
365
366                                 if (bits < 0 || bits > 32)
367                                         return -1;
368                                 memset(&mask4, 0, sizeof(mask4));
369                                 /* avoid "x << 32", which is not portable */
370                                 if (bits > 0)
371                                         maskl = (0xffffffffUL << (32 - (int) bits))
372                                                 & 0xffffffffUL;
373                                 else
374                                         maskl = 0;
375                                 mask4.sin_addr.s_addr = htonl(maskl);
376                                 memcpy(mask, &mask4, sizeof(mask4));
377                                 break;
378                         }
379
380 #ifdef HAVE_IPV6
381                 case AF_INET6:
382                         {
383                                 struct sockaddr_in6 mask6;
384                                 int                     i;
385
386                                 if (bits < 0 || bits > 128)
387                                         return -1;
388                                 memset(&mask6, 0, sizeof(mask6));
389                                 for (i = 0; i < 16; i++)
390                                 {
391                                         if (bits <= 0)
392                                                 mask6.sin6_addr.s6_addr[i] = 0;
393                                         else if (bits >= 8)
394                                                 mask6.sin6_addr.s6_addr[i] = 0xff;
395                                         else
396                                         {
397                                                 mask6.sin6_addr.s6_addr[i] =
398                                                         (0xff << (8 - (int) bits)) & 0xff;
399                                         }
400                                         bits -= 8;
401                                 }
402                                 memcpy(mask, &mask6, sizeof(mask6));
403                                 break;
404                         }
405 #endif
406                 default:
407                         return -1;
408         }
409
410         mask->ss_family = family;
411         return 0;
412 }
413
414
415 #ifdef HAVE_IPV6
416
417 /*
418  * pg_promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
419  *              the standard convention for IPv4 addresses mapped into IPv6 world
420  *
421  * The passed addr is modified in place; be sure it is large enough to
422  * hold the result!  Note that we only worry about setting the fields
423  * that pg_range_sockaddr will look at.
424  */
425 void
426 pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr)
427 {
428         struct sockaddr_in addr4;
429         struct sockaddr_in6 addr6;
430         uint32          ip4addr;
431
432         memcpy(&addr4, addr, sizeof(addr4));
433         ip4addr = ntohl(addr4.sin_addr.s_addr);
434
435         memset(&addr6, 0, sizeof(addr6));
436
437         addr6.sin6_family = AF_INET6;
438
439         addr6.sin6_addr.s6_addr[10] = 0xff;
440         addr6.sin6_addr.s6_addr[11] = 0xff;
441         addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
442         addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
443         addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
444         addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
445
446         memcpy(addr, &addr6, sizeof(addr6));
447 }
448
449 /*
450  * pg_promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
451  *              the standard convention for IPv4 addresses mapped into IPv6 world
452  *
453  * This must be different from pg_promote_v4_to_v6_addr because we want to
454  * set the high-order bits to 1's not 0's.
455  *
456  * The passed addr is modified in place; be sure it is large enough to
457  * hold the result!  Note that we only worry about setting the fields
458  * that pg_range_sockaddr will look at.
459  */
460 void
461 pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr)
462 {
463         struct sockaddr_in addr4;
464         struct sockaddr_in6 addr6;
465         uint32          ip4addr;
466         int                     i;
467
468         memcpy(&addr4, addr, sizeof(addr4));
469         ip4addr = ntohl(addr4.sin_addr.s_addr);
470
471         memset(&addr6, 0, sizeof(addr6));
472
473         addr6.sin6_family = AF_INET6;
474
475         for (i = 0; i < 12; i++)
476                 addr6.sin6_addr.s6_addr[i] = 0xff;
477
478         addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
479         addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
480         addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
481         addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
482
483         memcpy(addr, &addr6, sizeof(addr6));
484 }
485 #endif   /* HAVE_IPV6 */
486
487
488 /*
489  * Run the callback function for the addr/mask, after making sure the
490  * mask is sane for the addr.
491  */
492 static void
493 run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data,
494                                         struct sockaddr * addr, struct sockaddr * mask)
495 {
496         struct sockaddr_storage fullmask;
497
498         if (!addr)
499                 return;
500
501         /* Check that the mask is valid */
502         if (mask)
503         {
504                 if (mask->sa_family != addr->sa_family)
505                 {
506                         mask = NULL;
507                 }
508                 else if (mask->sa_family == AF_INET)
509                 {
510                         if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY)
511                                 mask = NULL;
512                 }
513 #ifdef HAVE_IPV6
514                 else if (mask->sa_family == AF_INET6)
515                 {
516                         if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr))
517                                 mask = NULL;
518                 }
519 #endif
520         }
521
522         /* If mask is invalid, generate our own fully-set mask */
523         if (!mask)
524         {
525                 pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family);
526                 mask = (struct sockaddr *) & fullmask;
527         }
528
529         (*callback) (addr, mask, cb_data);
530 }
531
532 #ifdef WIN32
533
534 #include <winsock2.h>
535 #include <ws2tcpip.h>
536
537 /*
538  * Enumerate the system's network interface addresses and call the callback
539  * for each one.  Returns 0 if successful, -1 if trouble.
540  *
541  * This version is for Win32.  Uses the Winsock 2 functions (ie: ws2_32.dll)
542  */
543 int
544 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
545 {
546         INTERFACE_INFO *ptr,
547                            *ii = NULL;
548         unsigned long length,
549                                 i;
550         unsigned long n_ii = 0;
551         SOCKET          sock;
552         int                     error;
553
554         sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
555         if (sock == SOCKET_ERROR)
556                 return -1;
557
558         while (n_ii < 1024)
559         {
560                 n_ii += 64;
561                 ptr = realloc(ii, sizeof(INTERFACE_INFO) * n_ii);
562                 if (!ptr)
563                 {
564                         free(ii);
565                         closesocket(sock);
566                         errno = ENOMEM;
567                         return -1;
568                 }
569
570                 ii = ptr;
571                 if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0,
572                                          ii, n_ii * sizeof(INTERFACE_INFO),
573                                          &length, 0, 0) == SOCKET_ERROR)
574                 {
575                         error = WSAGetLastError();
576                         if (error == WSAEFAULT || error == WSAENOBUFS)
577                                 continue;               /* need to make the buffer bigger */
578                         closesocket(sock);
579                         free(ii);
580                         return -1;
581                 }
582
583                 break;
584         }
585
586         for (i = 0; i < length / sizeof(INTERFACE_INFO); ++i)
587                 run_ifaddr_callback(callback, cb_data,
588                                                         (struct sockaddr *) & ii[i].iiAddress,
589                                                         (struct sockaddr *) & ii[i].iiNetmask);
590
591         closesocket(sock);
592         free(ii);
593         return 0;
594 }
595 #elif HAVE_GETIFADDRS                   /* && !WIN32 */
596
597 #ifdef HAVE_IFADDRS_H
598 #include <ifaddrs.h>
599 #endif
600
601 /*
602  * Enumerate the system's network interface addresses and call the callback
603  * for each one.  Returns 0 if successful, -1 if trouble.
604  *
605  * This version uses the getifaddrs() interface, which is available on
606  * BSDs, AIX, and modern Linux.
607  */
608 int
609 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
610 {
611         struct ifaddrs *ifa,
612                            *l;
613
614         if (getifaddrs(&ifa) < 0)
615                 return -1;
616
617         for (l = ifa; l; l = l->ifa_next)
618                 run_ifaddr_callback(callback, cb_data,
619                                                         l->ifa_addr, l->ifa_netmask);
620
621         freeifaddrs(ifa);
622         return 0;
623 }
624 #else                                                   /* !HAVE_GETIFADDRS && !WIN32 */
625
626 #ifdef HAVE_SYS_IOCTL_H
627 #include <sys/ioctl.h>
628 #endif
629
630 #ifdef HAVE_NET_IF_H
631 #include <net/if.h>
632 #endif
633
634 #ifdef HAVE_SYS_SOCKIO_H
635 #include <sys/sockio.h>
636 #endif
637
638 /*
639  * SIOCGIFCONF does not return IPv6 addresses on Solaris
640  * and HP/UX. So we prefer SIOCGLIFCONF if it's available.
641  *
642  * On HP/UX, however, it *only* returns IPv6 addresses,
643  * and the structs are named slightly differently too.
644  * We'd have to do another call with SIOCGIFCONF to get the
645  * IPv4 addresses as well. We don't currently bother, just
646  * fall back to SIOCGIFCONF on HP/UX.
647  */
648
649 #if defined(SIOCGLIFCONF) && !defined(__hpux)
650
651 /*
652  * Enumerate the system's network interface addresses and call the callback
653  * for each one.  Returns 0 if successful, -1 if trouble.
654  *
655  * This version uses ioctl(SIOCGLIFCONF).
656  */
657 int
658 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
659 {
660         struct lifconf lifc;
661         struct lifreq *lifr,
662                                 lmask;
663         struct sockaddr *addr,
664                            *mask;
665         char       *ptr,
666                            *buffer = NULL;
667         size_t          n_buffer = 1024;
668         pgsocket        sock,
669                                 fd;
670
671 #ifdef HAVE_IPV6
672         pgsocket        sock6;
673 #endif
674         int                     i,
675                                 total;
676
677         sock = socket(AF_INET, SOCK_DGRAM, 0);
678         if (sock == -1)
679                 return -1;
680
681         while (n_buffer < 1024 * 100)
682         {
683                 n_buffer += 1024;
684                 ptr = realloc(buffer, n_buffer);
685                 if (!ptr)
686                 {
687                         free(buffer);
688                         close(sock);
689                         errno = ENOMEM;
690                         return -1;
691                 }
692
693                 memset(&lifc, 0, sizeof(lifc));
694                 lifc.lifc_family = AF_UNSPEC;
695                 lifc.lifc_buf = buffer = ptr;
696                 lifc.lifc_len = n_buffer;
697
698                 if (ioctl(sock, SIOCGLIFCONF, &lifc) < 0)
699                 {
700                         if (errno == EINVAL)
701                                 continue;
702                         free(buffer);
703                         close(sock);
704                         return -1;
705                 }
706
707                 /*
708                  * Some Unixes try to return as much data as possible, with no
709                  * indication of whether enough space allocated. Don't believe we have
710                  * it all unless there's lots of slop.
711                  */
712                 if (lifc.lifc_len < n_buffer - 1024)
713                         break;
714         }
715
716 #ifdef HAVE_IPV6
717         /* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */
718         sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
719         if (sock6 == -1)
720         {
721                 free(buffer);
722                 close(sock);
723                 return -1;
724         }
725 #endif
726
727         total = lifc.lifc_len / sizeof(struct lifreq);
728         lifr = lifc.lifc_req;
729         for (i = 0; i < total; ++i)
730         {
731                 addr = (struct sockaddr *) & lifr[i].lifr_addr;
732                 memcpy(&lmask, &lifr[i], sizeof(struct lifreq));
733 #ifdef HAVE_IPV6
734                 fd = (addr->sa_family == AF_INET6) ? sock6 : sock;
735 #else
736                 fd = sock;
737 #endif
738                 if (ioctl(fd, SIOCGLIFNETMASK, &lmask) < 0)
739                         mask = NULL;
740                 else
741                         mask = (struct sockaddr *) & lmask.lifr_addr;
742                 run_ifaddr_callback(callback, cb_data, addr, mask);
743         }
744
745         free(buffer);
746         close(sock);
747 #ifdef HAVE_IPV6
748         close(sock6);
749 #endif
750         return 0;
751 }
752 #elif defined(SIOCGIFCONF)
753
754 /*
755  * Remaining Unixes use SIOCGIFCONF. Some only return IPv4 information
756  * here, so this is the least preferred method. Note that there is no
757  * standard way to iterate the struct ifreq returned in the array.
758  * On some OSs the structures are padded large enough for any address,
759  * on others you have to calculate the size of the struct ifreq.
760  */
761
762 /* Some OSs have _SIZEOF_ADDR_IFREQ, so just use that */
763 #ifndef _SIZEOF_ADDR_IFREQ
764
765 /* Calculate based on sockaddr.sa_len */
766 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
767 #define _SIZEOF_ADDR_IFREQ(ifr) \
768                 ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
769                  (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
770                   (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
771
772 /* Padded ifreq structure, simple */
773 #else
774 #define _SIZEOF_ADDR_IFREQ(ifr) \
775         sizeof (struct ifreq)
776 #endif
777 #endif   /* !_SIZEOF_ADDR_IFREQ */
778
779 /*
780  * Enumerate the system's network interface addresses and call the callback
781  * for each one.  Returns 0 if successful, -1 if trouble.
782  *
783  * This version uses ioctl(SIOCGIFCONF).
784  */
785 int
786 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
787 {
788         struct ifconf ifc;
789         struct ifreq *ifr,
790                            *end,
791                                 addr,
792                                 mask;
793         char       *ptr,
794                            *buffer = NULL;
795         size_t          n_buffer = 1024;
796         int                     sock;
797
798         sock = socket(AF_INET, SOCK_DGRAM, 0);
799         if (sock == -1)
800                 return -1;
801
802         while (n_buffer < 1024 * 100)
803         {
804                 n_buffer += 1024;
805                 ptr = realloc(buffer, n_buffer);
806                 if (!ptr)
807                 {
808                         free(buffer);
809                         close(sock);
810                         errno = ENOMEM;
811                         return -1;
812                 }
813
814                 memset(&ifc, 0, sizeof(ifc));
815                 ifc.ifc_buf = buffer = ptr;
816                 ifc.ifc_len = n_buffer;
817
818                 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
819                 {
820                         if (errno == EINVAL)
821                                 continue;
822                         free(buffer);
823                         close(sock);
824                         return -1;
825                 }
826
827                 /*
828                  * Some Unixes try to return as much data as possible, with no
829                  * indication of whether enough space allocated. Don't believe we have
830                  * it all unless there's lots of slop.
831                  */
832                 if (ifc.ifc_len < n_buffer - 1024)
833                         break;
834         }
835
836         end = (struct ifreq *) (buffer + ifc.ifc_len);
837         for (ifr = ifc.ifc_req; ifr < end;)
838         {
839                 memcpy(&addr, ifr, sizeof(addr));
840                 memcpy(&mask, ifr, sizeof(mask));
841                 if (ioctl(sock, SIOCGIFADDR, &addr, sizeof(addr)) == 0 &&
842                         ioctl(sock, SIOCGIFNETMASK, &mask, sizeof(mask)) == 0)
843                         run_ifaddr_callback(callback, cb_data,
844                                                                 &addr.ifr_addr, &mask.ifr_addr);
845                 ifr = (struct ifreq *) ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr));
846         }
847
848         free(buffer);
849         close(sock);
850         return 0;
851 }
852 #else                                                   /* !defined(SIOCGIFCONF) */
853
854 /*
855  * Enumerate the system's network interface addresses and call the callback
856  * for each one.  Returns 0 if successful, -1 if trouble.
857  *
858  * This version is our fallback if there's no known way to get the
859  * interface addresses.  Just return the standard loopback addresses.
860  */
861 int
862 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
863 {
864         struct sockaddr_in addr;
865         struct sockaddr_storage mask;
866
867 #ifdef HAVE_IPV6
868         struct sockaddr_in6 addr6;
869 #endif
870
871         /* addr 127.0.0.1/8 */
872         memset(&addr, 0, sizeof(addr));
873         addr.sin_family = AF_INET;
874         addr.sin_addr.s_addr = ntohl(0x7f000001);
875         memset(&mask, 0, sizeof(mask));
876         pg_sockaddr_cidr_mask(&mask, "8", AF_INET);
877         run_ifaddr_callback(callback, cb_data,
878                                                 (struct sockaddr *) & addr,
879                                                 (struct sockaddr *) & mask);
880
881 #ifdef HAVE_IPV6
882         /* addr ::1/128 */
883         memset(&addr6, 0, sizeof(addr6));
884         addr6.sin6_family = AF_INET6;
885         addr6.sin6_addr.s6_addr[15] = 1;
886         memset(&mask, 0, sizeof(mask));
887         pg_sockaddr_cidr_mask(&mask, "128", AF_INET6);
888         run_ifaddr_callback(callback, cb_data,
889                                                 (struct sockaddr *) & addr6,
890                                                 (struct sockaddr *) & mask);
891 #endif
892
893         return 0;
894 }
895 #endif   /* !defined(SIOCGIFCONF) */
896
897 #endif   /* !HAVE_GETIFADDRS */