00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
00078 rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
00079 servname, hintp, result);
00080
00081 return rc;
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
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
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
00112 {
00113
00114 if (ai != NULL)
00115 freeaddrinfo(ai);
00116 }
00117 }
00118
00119
00120
00121
00122
00123
00124
00125
00126
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
00165
00166
00167
00168
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
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
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
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
00267
00268
00269
00270
00271
00272
00273
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
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
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
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
00414
00415
00416
00417
00418
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
00446
00447
00448
00449
00450
00451
00452
00453
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
00481
00482
00483
00484
00485
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
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
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
00534
00535
00536
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;
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
00591
00592 #ifdef HAVE_IFADDRS_H
00593 #include <ifaddrs.h>
00594 #endif
00595
00596
00597
00598
00599
00600
00601
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
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
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 #if defined(SIOCGLIFCONF) && !defined(__hpux)
00645
00646
00647
00648
00649
00650
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
00704
00705
00706
00707 if (lifc.lifc_len < n_buffer - 1024)
00708 break;
00709 }
00710
00711 #ifdef HAVE_IPV6
00712
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
00751
00752
00753
00754
00755
00756
00757
00758 #ifndef _SIZEOF_ADDR_IFREQ
00759
00760
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
00768 #else
00769 #define _SIZEOF_ADDR_IFREQ(ifr) \
00770 sizeof (struct ifreq)
00771 #endif
00772 #endif
00773
00774
00775
00776
00777
00778
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
00824
00825
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
00848
00849
00850
00851
00852
00853
00854
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
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
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
00891
00892 #endif