Header And Logo

PostgreSQL
| The world's most advanced open source database.

ip.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * ip.c
00004  *    IPv6-aware network access.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/libpq/ip.c
00012  *
00013  * This file and the IPV6 implementation were initially provided by
00014  * Nigel Kukard <[email protected]>, Linux Based Systems Design
00015  * http://www.lbsd.net.
00016  *
00017  *-------------------------------------------------------------------------
00018  */
00019 
00020 /* This is intended to be used in both frontend and backend, so use c.h */
00021 #include "c.h"
00022 
00023 #include <unistd.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <sys/socket.h>
00027 #include <netdb.h>
00028 #include <netinet/in.h>
00029 #ifdef HAVE_NETINET_TCP_H
00030 #include <netinet/tcp.h>
00031 #endif
00032 #include <arpa/inet.h>
00033 #include <sys/file.h>
00034 
00035 #include "libpq/ip.h"
00036 
00037 
00038 static int range_sockaddr_AF_INET(const struct sockaddr_in * addr,
00039                        const struct sockaddr_in * netaddr,
00040                        const struct sockaddr_in * netmask);
00041 
00042 #ifdef HAVE_IPV6
00043 static int range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr,
00044                         const struct sockaddr_in6 * netaddr,
00045                         const struct sockaddr_in6 * netmask);
00046 #endif
00047 
00048 #ifdef  HAVE_UNIX_SOCKETS
00049 static int getaddrinfo_unix(const char *path,
00050                  const struct addrinfo * hintsp,
00051                  struct addrinfo ** result);
00052 
00053 static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
00054                  char *node, int nodelen,
00055                  char *service, int servicelen,
00056                  int flags);
00057 #endif
00058 
00059 
00060 /*
00061  *  pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
00062  */
00063 int
00064 pg_getaddrinfo_all(const char *hostname, const char *servname,
00065                    const struct addrinfo * hintp, struct addrinfo ** result)
00066 {
00067     int         rc;
00068 
00069     /* not all versions of getaddrinfo() zero *result on failure */
00070     *result = NULL;
00071 
00072 #ifdef HAVE_UNIX_SOCKETS
00073     if (hintp->ai_family == AF_UNIX)
00074         return getaddrinfo_unix(servname, hintp, result);
00075 #endif
00076 
00077     /* NULL has special meaning to getaddrinfo(). */
00078     rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
00079                      servname, hintp, result);
00080 
00081     return rc;
00082 }
00083 
00084 
00085 /*
00086  *  pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
00087  *
00088  * Note: the ai_family field of the original hint structure must be passed
00089  * so that we can tell whether the addrinfo struct was built by the system's
00090  * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
00091  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
00092  * not safe to look at ai_family in the addrinfo itself.
00093  */
00094 void
00095 pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
00096 {
00097 #ifdef HAVE_UNIX_SOCKETS
00098     if (hint_ai_family == AF_UNIX)
00099     {
00100         /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
00101         while (ai != NULL)
00102         {
00103             struct addrinfo *p = ai;
00104 
00105             ai = ai->ai_next;
00106             free(p->ai_addr);
00107             free(p);
00108         }
00109     }
00110     else
00111 #endif   /* HAVE_UNIX_SOCKETS */
00112     {
00113         /* struct was built by getaddrinfo() */
00114         if (ai != NULL)
00115             freeaddrinfo(ai);
00116     }
00117 }
00118 
00119 
00120 /*
00121  *  pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
00122  *
00123  * The API of this routine differs from the standard getnameinfo() definition
00124  * in two ways: first, the addr parameter is declared as sockaddr_storage
00125  * rather than struct sockaddr, and second, the node and service fields are
00126  * guaranteed to be filled with something even on failure return.
00127  */
00128 int
00129 pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen,
00130                    char *node, int nodelen,
00131                    char *service, int servicelen,
00132                    int flags)
00133 {
00134     int         rc;
00135 
00136 #ifdef HAVE_UNIX_SOCKETS
00137     if (addr && addr->ss_family == AF_UNIX)
00138         rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
00139                               node, nodelen,
00140                               service, servicelen,
00141                               flags);
00142     else
00143 #endif
00144         rc = getnameinfo((const struct sockaddr *) addr, salen,
00145                          node, nodelen,
00146                          service, servicelen,
00147                          flags);
00148 
00149     if (rc != 0)
00150     {
00151         if (node)
00152             strlcpy(node, "???", nodelen);
00153         if (service)
00154             strlcpy(service, "???", servicelen);
00155     }
00156 
00157     return rc;
00158 }
00159 
00160 
00161 #if defined(HAVE_UNIX_SOCKETS)
00162 
00163 /* -------
00164  *  getaddrinfo_unix - get unix socket info using IPv6-compatible API
00165  *
00166  *  Bugs: only one addrinfo is set even though hintsp is NULL or
00167  *        ai_socktype is 0
00168  *        AI_CANONNAME is not supported.
00169  * -------
00170  */
00171 static int
00172 getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
00173                  struct addrinfo ** result)
00174 {
00175     struct addrinfo hints;
00176     struct addrinfo *aip;
00177     struct sockaddr_un *unp;
00178 
00179     *result = NULL;
00180 
00181     MemSet(&hints, 0, sizeof(hints));
00182 
00183     if (strlen(path) >= sizeof(unp->sun_path))
00184         return EAI_FAIL;
00185 
00186     if (hintsp == NULL)
00187     {
00188         hints.ai_family = AF_UNIX;
00189         hints.ai_socktype = SOCK_STREAM;
00190     }
00191     else
00192         memcpy(&hints, hintsp, sizeof(hints));
00193 
00194     if (hints.ai_socktype == 0)
00195         hints.ai_socktype = SOCK_STREAM;
00196 
00197     if (hints.ai_family != AF_UNIX)
00198     {
00199         /* shouldn't have been called */
00200         return EAI_FAIL;
00201     }
00202 
00203     aip = calloc(1, sizeof(struct addrinfo));
00204     if (aip == NULL)
00205         return EAI_MEMORY;
00206 
00207     unp = calloc(1, sizeof(struct sockaddr_un));
00208     if (unp == NULL)
00209     {
00210         free(aip);
00211         return EAI_MEMORY;
00212     }
00213 
00214     aip->ai_family = AF_UNIX;
00215     aip->ai_socktype = hints.ai_socktype;
00216     aip->ai_protocol = hints.ai_protocol;
00217     aip->ai_next = NULL;
00218     aip->ai_canonname = NULL;
00219     *result = aip;
00220 
00221     unp->sun_family = AF_UNIX;
00222     aip->ai_addr = (struct sockaddr *) unp;
00223     aip->ai_addrlen = sizeof(struct sockaddr_un);
00224 
00225     strcpy(unp->sun_path, path);
00226 
00227 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
00228     unp->sun_len = sizeof(struct sockaddr_un);
00229 #endif
00230 
00231     return 0;
00232 }
00233 
00234 /*
00235  * Convert an address to a hostname.
00236  */
00237 static int
00238 getnameinfo_unix(const struct sockaddr_un * sa, int salen,
00239                  char *node, int nodelen,
00240                  char *service, int servicelen,
00241                  int flags)
00242 {
00243     int         ret = -1;
00244 
00245     /* Invalid arguments. */
00246     if (sa == NULL || sa->sun_family != AF_UNIX ||
00247         (node == NULL && service == NULL))
00248         return EAI_FAIL;
00249 
00250     if (node)
00251     {
00252         ret = snprintf(node, nodelen, "%s", "[local]");
00253         if (ret == -1 || ret > nodelen)
00254             return EAI_MEMORY;
00255     }
00256 
00257     if (service)
00258     {
00259         ret = snprintf(service, servicelen, "%s", sa->sun_path);
00260         if (ret == -1 || ret > servicelen)
00261             return EAI_MEMORY;
00262     }
00263 
00264     return 0;
00265 }
00266 #endif   /* HAVE_UNIX_SOCKETS */
00267 
00268 
00269 /*
00270  * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ?
00271  *
00272  * Note: caller must already have verified that all three addresses are
00273  * in the same address family; and AF_UNIX addresses are not supported.
00274  */
00275 int
00276 pg_range_sockaddr(const struct sockaddr_storage * addr,
00277                   const struct sockaddr_storage * netaddr,
00278                   const struct sockaddr_storage * netmask)
00279 {
00280     if (addr->ss_family == AF_INET)
00281         return range_sockaddr_AF_INET((const struct sockaddr_in *) addr,
00282                                       (const struct sockaddr_in *) netaddr,
00283                                       (const struct sockaddr_in *) netmask);
00284 #ifdef HAVE_IPV6
00285     else if (addr->ss_family == AF_INET6)
00286         return range_sockaddr_AF_INET6((const struct sockaddr_in6 *) addr,
00287                                        (const struct sockaddr_in6 *) netaddr,
00288                                        (const struct sockaddr_in6 *) netmask);
00289 #endif
00290     else
00291         return 0;
00292 }
00293 
00294 static int
00295 range_sockaddr_AF_INET(const struct sockaddr_in * addr,
00296                        const struct sockaddr_in * netaddr,
00297                        const struct sockaddr_in * netmask)
00298 {
00299     if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
00300          netmask->sin_addr.s_addr) == 0)
00301         return 1;
00302     else
00303         return 0;
00304 }
00305 
00306 
00307 #ifdef HAVE_IPV6
00308 
00309 static int
00310 range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr,
00311                         const struct sockaddr_in6 * netaddr,
00312                         const struct sockaddr_in6 * netmask)
00313 {
00314     int         i;
00315 
00316     for (i = 0; i < 16; i++)
00317     {
00318         if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
00319              netmask->sin6_addr.s6_addr[i]) != 0)
00320             return 0;
00321     }
00322 
00323     return 1;
00324 }
00325 #endif   /* HAVE_IPV6 */
00326 
00327 /*
00328  *  pg_sockaddr_cidr_mask - make a network mask of the appropriate family
00329  *    and required number of significant bits
00330  *
00331  * numbits can be null, in which case the mask is fully set.
00332  *
00333  * The resulting mask is placed in *mask, which had better be big enough.
00334  *
00335  * Return value is 0 if okay, -1 if not.
00336  */
00337 int
00338 pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
00339 {
00340     long        bits;
00341     char       *endptr;
00342 
00343     if (numbits == NULL)
00344     {
00345         bits = (family == AF_INET) ? 32 : 128;
00346     }
00347     else
00348     {
00349         bits = strtol(numbits, &endptr, 10);
00350         if (*numbits == '\0' || *endptr != '\0')
00351             return -1;
00352     }
00353 
00354     switch (family)
00355     {
00356         case AF_INET:
00357             {
00358                 struct sockaddr_in mask4;
00359                 long        maskl;
00360 
00361                 if (bits < 0 || bits > 32)
00362                     return -1;
00363                 memset(&mask4, 0, sizeof(mask4));
00364                 /* avoid "x << 32", which is not portable */
00365                 if (bits > 0)
00366                     maskl = (0xffffffffUL << (32 - (int) bits))
00367                         & 0xffffffffUL;
00368                 else
00369                     maskl = 0;
00370                 mask4.sin_addr.s_addr = htonl(maskl);
00371                 memcpy(mask, &mask4, sizeof(mask4));
00372                 break;
00373             }
00374 
00375 #ifdef HAVE_IPV6
00376         case AF_INET6:
00377             {
00378                 struct sockaddr_in6 mask6;
00379                 int         i;
00380 
00381                 if (bits < 0 || bits > 128)
00382                     return -1;
00383                 memset(&mask6, 0, sizeof(mask6));
00384                 for (i = 0; i < 16; i++)
00385                 {
00386                     if (bits <= 0)
00387                         mask6.sin6_addr.s6_addr[i] = 0;
00388                     else if (bits >= 8)
00389                         mask6.sin6_addr.s6_addr[i] = 0xff;
00390                     else
00391                     {
00392                         mask6.sin6_addr.s6_addr[i] =
00393                             (0xff << (8 - (int) bits)) & 0xff;
00394                     }
00395                     bits -= 8;
00396                 }
00397                 memcpy(mask, &mask6, sizeof(mask6));
00398                 break;
00399             }
00400 #endif
00401         default:
00402             return -1;
00403     }
00404 
00405     mask->ss_family = family;
00406     return 0;
00407 }
00408 
00409 
00410 #ifdef HAVE_IPV6
00411 
00412 /*
00413  * pg_promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
00414  *      the standard convention for IPv4 addresses mapped into IPv6 world
00415  *
00416  * The passed addr is modified in place; be sure it is large enough to
00417  * hold the result!  Note that we only worry about setting the fields
00418  * that pg_range_sockaddr will look at.
00419  */
00420 void
00421 pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr)
00422 {
00423     struct sockaddr_in addr4;
00424     struct sockaddr_in6 addr6;
00425     uint32      ip4addr;
00426 
00427     memcpy(&addr4, addr, sizeof(addr4));
00428     ip4addr = ntohl(addr4.sin_addr.s_addr);
00429 
00430     memset(&addr6, 0, sizeof(addr6));
00431 
00432     addr6.sin6_family = AF_INET6;
00433 
00434     addr6.sin6_addr.s6_addr[10] = 0xff;
00435     addr6.sin6_addr.s6_addr[11] = 0xff;
00436     addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
00437     addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
00438     addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
00439     addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
00440 
00441     memcpy(addr, &addr6, sizeof(addr6));
00442 }
00443 
00444 /*
00445  * pg_promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
00446  *      the standard convention for IPv4 addresses mapped into IPv6 world
00447  *
00448  * This must be different from pg_promote_v4_to_v6_addr because we want to
00449  * set the high-order bits to 1's not 0's.
00450  *
00451  * The passed addr is modified in place; be sure it is large enough to
00452  * hold the result!  Note that we only worry about setting the fields
00453  * that pg_range_sockaddr will look at.
00454  */
00455 void
00456 pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr)
00457 {
00458     struct sockaddr_in addr4;
00459     struct sockaddr_in6 addr6;
00460     uint32      ip4addr;
00461     int         i;
00462 
00463     memcpy(&addr4, addr, sizeof(addr4));
00464     ip4addr = ntohl(addr4.sin_addr.s_addr);
00465 
00466     memset(&addr6, 0, sizeof(addr6));
00467 
00468     addr6.sin6_family = AF_INET6;
00469 
00470     for (i = 0; i < 12; i++)
00471         addr6.sin6_addr.s6_addr[i] = 0xff;
00472 
00473     addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
00474     addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
00475     addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
00476     addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
00477 
00478     memcpy(addr, &addr6, sizeof(addr6));
00479 }
00480 #endif   /* HAVE_IPV6 */
00481 
00482 
00483 /*
00484  * Run the callback function for the addr/mask, after making sure the
00485  * mask is sane for the addr.
00486  */
00487 static void
00488 run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data,
00489                     struct sockaddr * addr, struct sockaddr * mask)
00490 {
00491     struct sockaddr_storage fullmask;
00492 
00493     if (!addr)
00494         return;
00495 
00496     /* Check that the mask is valid */
00497     if (mask)
00498     {
00499         if (mask->sa_family != addr->sa_family)
00500         {
00501             mask = NULL;
00502         }
00503         else if (mask->sa_family == AF_INET)
00504         {
00505             if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY)
00506                 mask = NULL;
00507         }
00508 #ifdef HAVE_IPV6
00509         else if (mask->sa_family == AF_INET6)
00510         {
00511             if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr))
00512                 mask = NULL;
00513         }
00514 #endif
00515     }
00516 
00517     /* If mask is invalid, generate our own fully-set mask */
00518     if (!mask)
00519     {
00520         pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family);
00521         mask = (struct sockaddr *) & fullmask;
00522     }
00523 
00524     (*callback) (addr, mask, cb_data);
00525 }
00526 
00527 #ifdef WIN32
00528 
00529 #include <winsock2.h>
00530 #include <ws2tcpip.h>
00531 
00532 /*
00533  * Enumerate the system's network interface addresses and call the callback
00534  * for each one.  Returns 0 if successful, -1 if trouble.
00535  *
00536  * This version is for Win32.  Uses the Winsock 2 functions (ie: ws2_32.dll)
00537  */
00538 int
00539 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
00540 {
00541     INTERFACE_INFO *ptr,
00542                *ii = NULL;
00543     unsigned long length,
00544                 i;
00545     unsigned long n_ii = 0;
00546     SOCKET      sock;
00547     int         error;
00548 
00549     sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
00550     if (sock == SOCKET_ERROR)
00551         return -1;
00552 
00553     while (n_ii < 1024)
00554     {
00555         n_ii += 64;
00556         ptr = realloc(ii, sizeof(INTERFACE_INFO) * n_ii);
00557         if (!ptr)
00558         {
00559             free(ii);
00560             closesocket(sock);
00561             errno = ENOMEM;
00562             return -1;
00563         }
00564 
00565         ii = ptr;
00566         if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0,
00567                      ii, n_ii * sizeof(INTERFACE_INFO),
00568                      &length, 0, 0) == SOCKET_ERROR)
00569         {
00570             error = WSAGetLastError();
00571             if (error == WSAEFAULT || error == WSAENOBUFS)
00572                 continue;       /* need to make the buffer bigger */
00573             closesocket(sock);
00574             free(ii);
00575             return -1;
00576         }
00577 
00578         break;
00579     }
00580 
00581     for (i = 0; i < length / sizeof(INTERFACE_INFO); ++i)
00582         run_ifaddr_callback(callback, cb_data,
00583                             (struct sockaddr *) & ii[i].iiAddress,
00584                             (struct sockaddr *) & ii[i].iiNetmask);
00585 
00586     closesocket(sock);
00587     free(ii);
00588     return 0;
00589 }
00590 #elif HAVE_GETIFADDRS           /* && !WIN32 */
00591 
00592 #ifdef HAVE_IFADDRS_H
00593 #include <ifaddrs.h>
00594 #endif
00595 
00596 /*
00597  * Enumerate the system's network interface addresses and call the callback
00598  * for each one.  Returns 0 if successful, -1 if trouble.
00599  *
00600  * This version uses the getifaddrs() interface, which is available on
00601  * BSDs, AIX, and modern Linux.
00602  */
00603 int
00604 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
00605 {
00606     struct ifaddrs *ifa,
00607                *l;
00608 
00609     if (getifaddrs(&ifa) < 0)
00610         return -1;
00611 
00612     for (l = ifa; l; l = l->ifa_next)
00613         run_ifaddr_callback(callback, cb_data,
00614                             l->ifa_addr, l->ifa_netmask);
00615 
00616     freeifaddrs(ifa);
00617     return 0;
00618 }
00619 #else                           /* !HAVE_GETIFADDRS && !WIN32 */
00620 
00621 #ifdef HAVE_SYS_IOCTL_H
00622 #include <sys/ioctl.h>
00623 #endif
00624 
00625 #ifdef HAVE_NET_IF_H
00626 #include <net/if.h>
00627 #endif
00628 
00629 #ifdef HAVE_SYS_SOCKIO_H
00630 #include <sys/sockio.h>
00631 #endif
00632 
00633 /*
00634  * SIOCGIFCONF does not return IPv6 addresses on Solaris
00635  * and HP/UX. So we prefer SIOCGLIFCONF if it's available.
00636  *
00637  * On HP/UX, however, it *only* returns IPv6 addresses,
00638  * and the structs are named slightly differently too.
00639  * We'd have to do another call with SIOCGIFCONF to get the
00640  * IPv4 addresses as well. We don't currently bother, just
00641  * fall back to SIOCGIFCONF on HP/UX.
00642  */
00643 
00644 #if defined(SIOCGLIFCONF) && !defined(__hpux)
00645 
00646 /*
00647  * Enumerate the system's network interface addresses and call the callback
00648  * for each one.  Returns 0 if successful, -1 if trouble.
00649  *
00650  * This version uses ioctl(SIOCGLIFCONF).
00651  */
00652 int
00653 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
00654 {
00655     struct lifconf lifc;
00656     struct lifreq *lifr,
00657                 lmask;
00658     struct sockaddr *addr,
00659                *mask;
00660     char       *ptr,
00661                *buffer = NULL;
00662     size_t      n_buffer = 1024;
00663     pgsocket    sock,
00664                 fd;
00665 
00666 #ifdef HAVE_IPV6
00667     pgsocket    sock6;
00668 #endif
00669     int         i,
00670                 total;
00671 
00672     sock = socket(AF_INET, SOCK_DGRAM, 0);
00673     if (sock == -1)
00674         return -1;
00675 
00676     while (n_buffer < 1024 * 100)
00677     {
00678         n_buffer += 1024;
00679         ptr = realloc(buffer, n_buffer);
00680         if (!ptr)
00681         {
00682             free(buffer);
00683             close(sock);
00684             errno = ENOMEM;
00685             return -1;
00686         }
00687 
00688         memset(&lifc, 0, sizeof(lifc));
00689         lifc.lifc_family = AF_UNSPEC;
00690         lifc.lifc_buf = buffer = ptr;
00691         lifc.lifc_len = n_buffer;
00692 
00693         if (ioctl(sock, SIOCGLIFCONF, &lifc) < 0)
00694         {
00695             if (errno == EINVAL)
00696                 continue;
00697             free(buffer);
00698             close(sock);
00699             return -1;
00700         }
00701 
00702         /*
00703          * Some Unixes try to return as much data as possible, with no
00704          * indication of whether enough space allocated. Don't believe we have
00705          * it all unless there's lots of slop.
00706          */
00707         if (lifc.lifc_len < n_buffer - 1024)
00708             break;
00709     }
00710 
00711 #ifdef HAVE_IPV6
00712     /* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */
00713     sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
00714     if (sock6 == -1)
00715     {
00716         free(buffer);
00717         close(sock);
00718         return -1;
00719     }
00720 #endif
00721 
00722     total = lifc.lifc_len / sizeof(struct lifreq);
00723     lifr = lifc.lifc_req;
00724     for (i = 0; i < total; ++i)
00725     {
00726         addr = (struct sockaddr *) & lifr[i].lifr_addr;
00727         memcpy(&lmask, &lifr[i], sizeof(struct lifreq));
00728 #ifdef HAVE_IPV6
00729         fd = (addr->sa_family == AF_INET6) ? sock6 : sock;
00730 #else
00731         fd = sock;
00732 #endif
00733         if (ioctl(fd, SIOCGLIFNETMASK, &lmask) < 0)
00734             mask = NULL;
00735         else
00736             mask = (struct sockaddr *) & lmask.lifr_addr;
00737         run_ifaddr_callback(callback, cb_data, addr, mask);
00738     }
00739 
00740     free(buffer);
00741     close(sock);
00742 #ifdef HAVE_IPV6
00743     close(sock6);
00744 #endif
00745     return 0;
00746 }
00747 #elif defined(SIOCGIFCONF)
00748 
00749 /*
00750  * Remaining Unixes use SIOCGIFCONF. Some only return IPv4 information
00751  * here, so this is the least preferred method. Note that there is no
00752  * standard way to iterate the struct ifreq returned in the array.
00753  * On some OSs the structures are padded large enough for any address,
00754  * on others you have to calculate the size of the struct ifreq.
00755  */
00756 
00757 /* Some OSs have _SIZEOF_ADDR_IFREQ, so just use that */
00758 #ifndef _SIZEOF_ADDR_IFREQ
00759 
00760 /* Calculate based on sockaddr.sa_len */
00761 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
00762 #define _SIZEOF_ADDR_IFREQ(ifr) \
00763         ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
00764          (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
00765           (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
00766 
00767 /* Padded ifreq structure, simple */
00768 #else
00769 #define _SIZEOF_ADDR_IFREQ(ifr) \
00770     sizeof (struct ifreq)
00771 #endif
00772 #endif   /* !_SIZEOF_ADDR_IFREQ */
00773 
00774 /*
00775  * Enumerate the system's network interface addresses and call the callback
00776  * for each one.  Returns 0 if successful, -1 if trouble.
00777  *
00778  * This version uses ioctl(SIOCGIFCONF).
00779  */
00780 int
00781 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
00782 {
00783     struct ifconf ifc;
00784     struct ifreq *ifr,
00785                *end,
00786                 addr,
00787                 mask;
00788     char       *ptr,
00789                *buffer = NULL;
00790     size_t      n_buffer = 1024;
00791     int         sock;
00792 
00793     sock = socket(AF_INET, SOCK_DGRAM, 0);
00794     if (sock == -1)
00795         return -1;
00796 
00797     while (n_buffer < 1024 * 100)
00798     {
00799         n_buffer += 1024;
00800         ptr = realloc(buffer, n_buffer);
00801         if (!ptr)
00802         {
00803             free(buffer);
00804             close(sock);
00805             errno = ENOMEM;
00806             return -1;
00807         }
00808 
00809         memset(&ifc, 0, sizeof(ifc));
00810         ifc.ifc_buf = buffer = ptr;
00811         ifc.ifc_len = n_buffer;
00812 
00813         if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
00814         {
00815             if (errno == EINVAL)
00816                 continue;
00817             free(buffer);
00818             close(sock);
00819             return -1;
00820         }
00821 
00822         /*
00823          * Some Unixes try to return as much data as possible, with no
00824          * indication of whether enough space allocated. Don't believe we have
00825          * it all unless there's lots of slop.
00826          */
00827         if (ifc.ifc_len < n_buffer - 1024)
00828             break;
00829     }
00830 
00831     end = (struct ifreq *) (buffer + ifc.ifc_len);
00832     for (ifr = ifc.ifc_req; ifr < end;)
00833     {
00834         memcpy(&addr, ifr, sizeof(addr));
00835         memcpy(&mask, ifr, sizeof(mask));
00836         if (ioctl(sock, SIOCGIFADDR, &addr, sizeof(addr)) == 0 &&
00837             ioctl(sock, SIOCGIFNETMASK, &mask, sizeof(mask)) == 0)
00838             run_ifaddr_callback(callback, cb_data,
00839                                 &addr.ifr_addr, &mask.ifr_addr);
00840         ifr = (struct ifreq *) ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr));
00841     }
00842 
00843     free(buffer);
00844     close(sock);
00845     return 0;
00846 }
00847 #else                           /* !defined(SIOCGIFCONF) */
00848 
00849 /*
00850  * Enumerate the system's network interface addresses and call the callback
00851  * for each one.  Returns 0 if successful, -1 if trouble.
00852  *
00853  * This version is our fallback if there's no known way to get the
00854  * interface addresses.  Just return the standard loopback addresses.
00855  */
00856 int
00857 pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
00858 {
00859     struct sockaddr_in addr;
00860     struct sockaddr_storage mask;
00861 
00862 #ifdef HAVE_IPV6
00863     struct sockaddr_in6 addr6;
00864 #endif
00865 
00866     /* addr 127.0.0.1/8 */
00867     memset(&addr, 0, sizeof(addr));
00868     addr.sin_family = AF_INET;
00869     addr.sin_addr.s_addr = ntohl(0x7f000001);
00870     memset(&mask, 0, sizeof(mask));
00871     pg_sockaddr_cidr_mask(&mask, "8", AF_INET);
00872     run_ifaddr_callback(callback, cb_data,
00873                         (struct sockaddr *) & addr,
00874                         (struct sockaddr *) & mask);
00875 
00876 #ifdef HAVE_IPV6
00877     /* addr ::1/128 */
00878     memset(&addr6, 0, sizeof(addr6));
00879     addr6.sin6_family = AF_INET6;
00880     addr6.sin6_addr.s6_addr[15] = 1;
00881     memset(&mask, 0, sizeof(mask));
00882     pg_sockaddr_cidr_mask(&mask, "128", AF_INET6);
00883     run_ifaddr_callback(callback, cb_data,
00884                         (struct sockaddr *) & addr6,
00885                         (struct sockaddr *) & mask);
00886 #endif
00887 
00888     return 0;
00889 }
00890 #endif   /* !defined(SIOCGIFCONF) */
00891 
00892 #endif   /* !HAVE_GETIFADDRS */