Bug Summary

File:pr/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/pr/src/misc/../../../../pr/src/misc/prnetdb.c
Warning:line 2235, column 18
Access to field 'ai_next' results in a dereference of a null pointer (loaded from variable 'ai')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name prnetdb.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nspr/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/pr/src/misc -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nspr/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/pr/src/misc -resource-dir /usr/lib/llvm-18/lib/clang/18 -U NDEBUG -D DEBUG_jenkins -D PACKAGE_NAME="" -D PACKAGE_TARNAME="" -D PACKAGE_VERSION="" -D PACKAGE_STRING="" -D PACKAGE_BUGREPORT="" -D PACKAGE_URL="" -D DEBUG=1 -D HAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1 -D HAVE_VISIBILITY_PRAGMA=1 -D XP_UNIX=1 -D _GNU_SOURCE=1 -D HAVE_FCNTL_FILE_LOCKING=1 -D HAVE_POINTER_LOCALTIME_R=1 -D LINUX=1 -D HAVE_DLADDR=1 -D HAVE_GETTID=1 -D HAVE_LCHOWN=1 -D HAVE_SETPRIORITY=1 -D HAVE_STRERROR=1 -D HAVE_SYSCALL=1 -D HAVE_SECURE_GETENV=1 -D _REENTRANT=1 -D FORCE_PR_LOG -D _PR_PTHREADS -U HAVE_CVAR_BUILT_ON_SEM -D _NSPR_BUILD_ -I /var/lib/jenkins/workspace/nss-scan-build/nss/../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../../pr/include -I ../../../../pr/include/private -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -fno-inline -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c ../../../../pr/src/misc/prnetdb.c
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6#include "primpl.h"
7
8#include <string.h>
9
10#if defined(LINUX1)
11#include <sys/un.h>
12#endif
13
14/*
15 * On Unix, the error code for gethostbyname() and gethostbyaddr()
16 * is returned in the global variable h_errno, instead of the usual
17 * errno.
18 */
19#if defined(XP_UNIX1)
20#if defined(_PR_NEED_H_ERRNO)
21extern int h_errno(*__h_errno_location ());
22#endif
23#define _MD_GETHOST_ERRNO()(*__h_errno_location ()) h_errno(*__h_errno_location ())
24#else
25#define _MD_GETHOST_ERRNO()(*__h_errno_location ()) _MD_ERRNO()((*__errno_location ()))
26#endif
27
28/*
29 * The meaning of the macros related to gethostbyname, gethostbyaddr,
30 * and gethostbyname2 is defined below.
31 * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return
32 * the result in thread specific storage. For example, AIX, HP-UX.
33 * - _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next
34 * two macros.
35 * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an
36 * int. For example, Linux glibc.
37 * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return
38 * a struct hostent* pointer. For example, Solaris.
39 */
40#if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \
41 || defined(_PR_HAVE_THREADSAFE_GETHOST)
42#define _PR_NO_DNS_LOCK
43#endif
44
45#if defined(_PR_NO_DNS_LOCK)
46#define LOCK_DNS()
47#define UNLOCK_DNS()
48#else
49PRLock *_pr_dnsLock = NULL((void*)0);
50#define LOCK_DNS() PR_Lock(_pr_dnsLock)
51#define UNLOCK_DNS() PR_Unlock(_pr_dnsLock)
52#endif /* defined(_PR_NO_DNS_LOCK) */
53
54/*
55 * Some platforms have the reentrant getprotobyname_r() and
56 * getprotobynumber_r(). However, they come in three flavors.
57 * Some return a pointer to struct protoent, others return
58 * an int, and glibc's flavor takes five arguments.
59 */
60
61#if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT1)) \
62 || (defined(LINUX1) && defined(_REENTRANT1) \
63 && defined(__GLIBC__2) && __GLIBC__2 < 2)
64#define _PR_HAVE_GETPROTO_R
65#define _PR_HAVE_GETPROTO_R_POINTER
66#endif
67
68#if defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \
69 || (defined(HPUX10_10) && defined(_REENTRANT1)) \
70 || (defined(HPUX10_20) && defined(_REENTRANT1)) \
71 || defined(OPENBSD)
72#define _PR_HAVE_GETPROTO_R
73#define _PR_HAVE_GETPROTO_R_INT
74#endif
75
76#if __FreeBSD_version >= 602000
77#define _PR_HAVE_GETPROTO_R
78#define _PR_HAVE_5_ARG_GETPROTO_R
79#endif
80
81/* BeOS has glibc but not the glibc-style getprotobyxxx_r functions. */
82#if (defined(__GLIBC__2) && __GLIBC__2 >= 2)
83#define _PR_HAVE_GETPROTO_R
84#define _PR_HAVE_5_ARG_GETPROTO_R
85#endif
86
87#if !defined(_PR_HAVE_GETPROTO_R)
88PRLock* _getproto_lock = NULL((void*)0);
89#endif
90
91#if defined(_PR_INET6_PROBE)
92extern PRBool _pr_ipv6_is_present(void);
93#endif
94
95#define _PR_IN6_IS_ADDR_UNSPECIFIED(a)(((a)->_S6_un._S6_u32[0] == 0) && ((a)->_S6_un.
_S6_u32[1] == 0) && ((a)->_S6_un._S6_u32[2] == 0) &&
((a)->_S6_un._S6_u32[3] == 0))
\
96 (((a)->pr_s6_addr32_S6_un._S6_u32[0] == 0) && \
97 ((a)->pr_s6_addr32_S6_un._S6_u32[1] == 0) && \
98 ((a)->pr_s6_addr32_S6_un._S6_u32[2] == 0) && \
99 ((a)->pr_s6_addr32_S6_un._S6_u32[3] == 0))
100
101#define _PR_IN6_IS_ADDR_LOOPBACK(a)(((a)->_S6_un._S6_u32[0] == 0) && ((a)->_S6_un.
_S6_u32[1] == 0) && ((a)->_S6_un._S6_u32[2] == 0) &&
((a)->_S6_un._S6_u8[12] == 0) && ((a)->_S6_un.
_S6_u8[13] == 0) && ((a)->_S6_un._S6_u8[14] == 0) &&
((a)->_S6_un._S6_u8[15] == 0x1U))
\
102 (((a)->pr_s6_addr32_S6_un._S6_u32[0] == 0) && \
103 ((a)->pr_s6_addr32_S6_un._S6_u32[1] == 0) && \
104 ((a)->pr_s6_addr32_S6_un._S6_u32[2] == 0) && \
105 ((a)->pr_s6_addr_S6_un._S6_u8[12] == 0) && \
106 ((a)->pr_s6_addr_S6_un._S6_u8[13] == 0) && \
107 ((a)->pr_s6_addr_S6_un._S6_u8[14] == 0) && \
108 ((a)->pr_s6_addr_S6_un._S6_u8[15] == 0x1U))
109
110const PRIPv6Addr _pr_in6addr_any = {{{
111 0, 0, 0, 0,
112 0, 0, 0, 0,
113 0, 0, 0, 0,
114 0, 0, 0, 0
115 }
116 }
117};
118
119const PRIPv6Addr _pr_in6addr_loopback = {{{
120 0, 0, 0, 0,
121 0, 0, 0, 0,
122 0, 0, 0, 0,
123 0, 0, 0, 0x1U
124 }
125 }
126};
127/*
128 * The values at bytes 10 and 11 are compared using pointers to
129 * 8-bit fields, and not 32-bit fields, to make the comparison work on
130 * both big-endian and little-endian systems
131 */
132
133#define _PR_IN6_IS_ADDR_V4MAPPED(a)(((a)->_S6_un._S6_u32[0] == 0) && ((a)->_S6_un.
_S6_u32[1] == 0) && ((a)->_S6_un._S6_u8[8] == 0) &&
((a)->_S6_un._S6_u8[9] == 0) && ((a)->_S6_un._S6_u8
[10] == 0xff) && ((a)->_S6_un._S6_u8[11] == 0xff))
\
134 (((a)->pr_s6_addr32_S6_un._S6_u32[0] == 0) && \
135 ((a)->pr_s6_addr32_S6_un._S6_u32[1] == 0) && \
136 ((a)->pr_s6_addr_S6_un._S6_u8[8] == 0) && \
137 ((a)->pr_s6_addr_S6_un._S6_u8[9] == 0) && \
138 ((a)->pr_s6_addr_S6_un._S6_u8[10] == 0xff) && \
139 ((a)->pr_s6_addr_S6_un._S6_u8[11] == 0xff))
140
141#define _PR_IN6_IS_ADDR_V4COMPAT(a)(((a)->_S6_un._S6_u32[0] == 0) && ((a)->_S6_un.
_S6_u32[1] == 0) && ((a)->_S6_un._S6_u32[2] == 0))
\
142 (((a)->pr_s6_addr32_S6_un._S6_u32[0] == 0) && \
143 ((a)->pr_s6_addr32_S6_un._S6_u32[1] == 0) && \
144 ((a)->pr_s6_addr32_S6_un._S6_u32[2] == 0))
145
146#define _PR_IN6_V4MAPPED_TO_IPADDR(a)((a)->_S6_un._S6_u32[3]) ((a)->pr_s6_addr32_S6_un._S6_u32[3])
147
148#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
149
150/*
151 * The _pr_QueryNetIfs() function finds out if the system has
152 * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if
153 * and _pr_have_inet6_if accordingly.
154 *
155 * We have an implementation using SIOCGIFCONF ioctl and a
156 * default implementation that simply sets _pr_have_inet_if
157 * and _pr_have_inet6_if to true. A better implementation
158 * would be to use the routing sockets (see Chapter 17 of
159 * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.)
160 */
161
162static PRLock *_pr_query_ifs_lock = NULL((void*)0);
163static PRBool _pr_have_inet_if = PR_FALSE0;
164static PRBool _pr_have_inet6_if = PR_FALSE0;
165
166#undef DEBUG_QUERY_IFS
167
168#if defined(AIX) \
169 || (defined(DARWIN) && !defined(HAVE_GETIFADDRS))
170
171/*
172 * Use SIOCGIFCONF ioctl on platforms that don't have routing
173 * sockets. Warning: whether SIOCGIFCONF ioctl returns AF_INET6
174 * network interfaces is not portable.
175 *
176 * The _pr_QueryNetIfs() function is derived from the code in
177 * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in
178 * Section 16.6 of W. Richard Stevens' Unix Network Programming,
179 * Vol. 1, 2nd. Ed.
180 */
181
182#include <sys/ioctl.h>
183#include <sys/socket.h>
184#include <netinet/in.h>
185#include <net/if.h>
186
187#ifdef DEBUG_QUERY_IFS
188static void
189_pr_PrintIfreq(struct ifreq *ifr)
190{
191 PRNetAddr addr;
192 struct sockaddr *sa;
193 const char* family;
194 char addrstr[64];
195
196 sa = &ifr->ifr_addr;
197 if (sa->sa_family == AF_INET2) {
198 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
199 family = "inet";
200 memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr));
201 } else if (sa->sa_family == AF_INET610) {
202 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
203 family = "inet6";
204 memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
205 } else {
206 return; /* skip if not AF_INET or AF_INET6 */
207 }
208 addr.raw.family = sa->sa_family;
209 PR_NetAddrToString(&addr, addrstr, sizeof(addrstr));
210 printf("%s: %s %s\n", ifr->ifr_name, family, addrstr);
211}
212#endif
213
214static void
215_pr_QueryNetIfs(void)
216{
217 int sock;
218 int rv;
219 struct ifconf ifc;
220 struct ifreq *ifr;
221 struct ifreq *lifr;
222 PRUint32 len, lastlen;
223 char *buf;
224
225 if ((sock = socket(AF_INET2, SOCK_STREAMSOCK_STREAM, 0)) == -1) {
226 return;
227 }
228
229 /* Issue SIOCGIFCONF request in a loop. */
230 lastlen = 0;
231 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
232 for (;;) {
233 buf = (char *)PR_Malloc(len);
234 if (NULL((void*)0) == buf) {
235 close(sock);
236 return;
237 }
238 ifc.ifc_buf = buf;
239 ifc.ifc_len = len;
240 rv = ioctl(sock, SIOCGIFCONF, &ifc);
241 if (rv < 0) {
242 if (errno(*__errno_location ()) != EINVAL22 || lastlen != 0) {
243 close(sock);
244 PR_Free(buf);
245 return;
246 }
247 } else {
248 if (ifc.ifc_len == lastlen) {
249 break; /* success, len has not changed */
250 }
251 lastlen = ifc.ifc_len;
252 }
253 len += 10 * sizeof(struct ifreq); /* increment */
254 PR_Free(buf);
255 }
256 close(sock);
257
258 ifr = ifc.ifc_req;
259 lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
260
261 while (ifr < lifr) {
262 struct sockaddr *sa;
263 int sa_len;
264
265#ifdef DEBUG_QUERY_IFS
266 _pr_PrintIfreq(ifr);
267#endif
268 sa = &ifr->ifr_addr;
269 if (sa->sa_family == AF_INET2) {
270 struct sockaddr_in *sin = (struct sockaddr_in *) sa;
271 if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK((in_addr_t) 0x7f000001))) {
272 _pr_have_inet_if = PR_TRUE1;
273 }
274 } else if (sa->sa_family == AF_INET610) {
275 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
276 if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (&sin6->sin6_addr); __a->__in6_u.__u6_addr32[0]
== 0 && __a->__in6_u.__u6_addr32[1] == 0 &&
__a->__in6_u.__u6_addr32[2] == 0 && __a->__in6_u
.__u6_addr32[3] == htonl (1); }))
277 && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (&sin6->sin6_addr); (__a->__in6_u.__u6_addr32[0
] & htonl (0xffc00000)) == htonl (0xfe800000); }))
) {
278 _pr_have_inet6_if = PR_TRUE1;
279 }
280 }
281
282#ifdef _PR_HAVE_SOCKADDR_LEN
283 sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr))((sa->sa_len)>(sizeof(struct sockaddr))?(sa->sa_len)
:(sizeof(struct sockaddr)))
;
284#else
285 switch (sa->sa_family) {
286#ifdef AF_LINK
287 case AF_LINK:
288 sa_len = sizeof(struct sockaddr_dl);
289 break;
290#endif
291 case AF_INET610:
292 sa_len = sizeof(struct sockaddr_in6);
293 break;
294 default:
295 sa_len = sizeof(struct sockaddr);
296 break;
297 }
298#endif
299 ifr = (struct ifreq *)(((char *)sa) + sa_len);
300 }
301 PR_Free(buf);
302}
303
304#elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \
305 || defined(NETBSD) || defined(OPENBSD)
306
307/*
308 * Use the BSD getifaddrs function.
309 */
310
311#include <sys/types.h>
312#include <sys/socket.h>
313#include <ifaddrs.h>
314#include <netinet/in.h>
315
316#ifdef DEBUG_QUERY_IFS
317static void
318_pr_PrintIfaddrs(struct ifaddrs *ifa)
319{
320 struct sockaddr *sa;
321 const char* family;
322 void *addrp;
323 char addrstr[64];
324
325 sa = ifa->ifa_addr;
326 if (sa->sa_family == AF_INET2) {
327 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
328 family = "inet";
329 addrp = &sin->sin_addr;
330 } else if (sa->sa_family == AF_INET610) {
331 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
332 family = "inet6";
333 addrp = &sin6->sin6_addr;
334 } else {
335 return; /* skip if not AF_INET or AF_INET6 */
336 }
337 inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr));
338 printf("%s: %s %s\n", ifa->ifa_name, family, addrstr);
339}
340#endif
341
342static void
343_pr_QueryNetIfs(void)
344{
345 struct ifaddrs *ifp;
346 struct ifaddrs *ifa;
347
348 if (getifaddrs(&ifp) == -1) {
349 return;
350 }
351 for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
352 struct sockaddr *sa;
353
354#ifdef DEBUG_QUERY_IFS
355 _pr_PrintIfaddrs(ifa);
356#endif
357 sa = ifa->ifa_addr;
358 if (sa->sa_family == AF_INET2) {
359 struct sockaddr_in *sin = (struct sockaddr_in *) sa;
360 if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK((in_addr_t) 0x7f000001))) {
361 _pr_have_inet_if = 1;
362 }
363 } else if (sa->sa_family == AF_INET610) {
364 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
365 if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (&sin6->sin6_addr); __a->__in6_u.__u6_addr32[0]
== 0 && __a->__in6_u.__u6_addr32[1] == 0 &&
__a->__in6_u.__u6_addr32[2] == 0 && __a->__in6_u
.__u6_addr32[3] == htonl (1); }))
366 && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(__extension__ ({ const struct in6_addr *__a = (const struct in6_addr
*) (&sin6->sin6_addr); (__a->__in6_u.__u6_addr32[0
] & htonl (0xffc00000)) == htonl (0xfe800000); }))
) {
367 _pr_have_inet6_if = 1;
368 }
369 }
370 }
371 freeifaddrs(ifp);
372}
373
374#else /* default */
375
376/*
377 * Emulate the code in NSPR 4.2 or older. PR_GetIPNodeByName behaves
378 * as if the system had both IPv4 and IPv6 source addresses configured.
379 */
380static void
381_pr_QueryNetIfs(void)
382{
383 _pr_have_inet_if = PR_TRUE1;
384 _pr_have_inet6_if = PR_TRUE1;
385}
386
387#endif
388
389#endif /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */
390
391void _PR_InitNet(void)
392{
393#if defined(XP_UNIX1)
394#ifdef HAVE_NETCONFIG
395 /*
396 * This one-liner prevents the endless re-open's and re-read's of
397 * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc.
398 */
399 (void)setnetconfig();
400#endif
401#endif
402#if !defined(_PR_NO_DNS_LOCK)
403 _pr_dnsLock = PR_NewLock();
404#endif
405#if !defined(_PR_HAVE_GETPROTO_R)
406 _getproto_lock = PR_NewLock();
407#endif
408#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
409 _pr_query_ifs_lock = PR_NewLock();
410#endif
411}
412
413void _PR_CleanupNet(void)
414{
415#if !defined(_PR_NO_DNS_LOCK)
416 if (_pr_dnsLock) {
417 PR_DestroyLock(_pr_dnsLock);
418 _pr_dnsLock = NULL((void*)0);
419 }
420#endif
421#if !defined(_PR_HAVE_GETPROTO_R)
422 if (_getproto_lock) {
423 PR_DestroyLock(_getproto_lock);
424 _getproto_lock = NULL((void*)0);
425 }
426#endif
427#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
428 if (_pr_query_ifs_lock) {
429 PR_DestroyLock(_pr_query_ifs_lock);
430 _pr_query_ifs_lock = NULL((void*)0);
431 }
432#endif
433}
434
435/*
436** Allocate space from the buffer, aligning it to "align" before doing
437** the allocation. "align" must be a power of 2.
438*/
439static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
440{
441 char *buf = *bufp;
442 PRIntn buflen = *buflenp;
443
444 if (align && ((long)buf & (align - 1))) {
445 PRIntn skip = align - ((ptrdiff_t)buf & (align - 1));
446 if (buflen < skip) {
447 return 0;
448 }
449 buf += skip;
450 buflen -= skip;
451 }
452 if (buflen < amount) {
453 return 0;
454 }
455 *bufp = buf + amount;
456 *buflenp = buflen - amount;
457 return buf;
458}
459
460typedef enum _PRIPAddrConversion {
461 _PRIPAddrNoConversion,
462 _PRIPAddrIPv4Mapped,
463 _PRIPAddrIPv4Compat
464} _PRIPAddrConversion;
465
466/*
467** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).
468*/
469static void MakeIPv4MappedAddr(const char *v4, char *v6)
470{
471 memset(v6, 0, 10);
472 memset(v6 + 10, 0xff, 2);
473 memcpy(v6 + 12, v4, 4);
474}
475
476/*
477** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).
478*/
479static void MakeIPv4CompatAddr(const char *v4, char *v6)
480{
481 memset(v6, 0, 12);
482 memcpy(v6 + 12, v4, 4);
483}
484
485/*
486** Copy a hostent, and all of the memory that it refers to into
487** (hopefully) stacked buffers.
488*/
489static PRStatus CopyHostent(
490 struct hostent *from,
491 char **buf,
492 PRIntn *bufsize,
493 _PRIPAddrConversion conversion,
494 PRHostEnt *to)
495{
496 PRIntn len, na;
497 char **ap;
498
499 if (conversion != _PRIPAddrNoConversion
500 && from->h_addrtype == AF_INET2) {
501 PR_ASSERT(from->h_length == 4)((from->h_length == 4)?((void)0):PR_Assert("from->h_length == 4"
,"../../../../pr/src/misc/prnetdb.c",501))
;
502 to->h_addrtype = PR_AF_INET610;
503 to->h_length = 16;
504 } else {
505#if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
506 if (AF_INET610 == from->h_addrtype) {
507 to->h_addrtype = PR_AF_INET610;
508 }
509 else
510#endif
511 to->h_addrtype = from->h_addrtype;
512 to->h_length = from->h_length;
513 }
514
515 /* Copy the official name */
516 if (!from->h_name) {
517 return PR_FAILURE;
518 }
519 len = strlen(from->h_name) + 1;
520 to->h_name = Alloc(len, buf, bufsize, 0);
521 if (!to->h_name) {
522 return PR_FAILURE;
523 }
524 memcpy(to->h_name, from->h_name, len);
525
526 /* Count the aliases, then allocate storage for the pointers */
527 if (!from->h_aliases) {
528 na = 1;
529 } else {
530 for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++) {;} /* nothing to execute */
531 }
532 to->h_aliases = (char**)Alloc(
533 na * sizeof(char*), buf, bufsize, sizeof(char**));
534 if (!to->h_aliases) {
535 return PR_FAILURE;
536 }
537
538 /* Copy the aliases, one at a time */
539 if (!from->h_aliases) {
540 to->h_aliases[0] = 0;
541 } else {
542 for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) {
543 len = strlen(*ap) + 1;
544 to->h_aliases[na] = Alloc(len, buf, bufsize, 0);
545 if (!to->h_aliases[na]) {
546 return PR_FAILURE;
547 }
548 memcpy(to->h_aliases[na], *ap, len);
549 }
550 to->h_aliases[na] = 0;
551 }
552
553 /* Count the addresses, then allocate storage for the pointers */
554 for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++) {;} /* nothing to execute */
555 to->h_addr_list = (char**)Alloc(
556 na * sizeof(char*), buf, bufsize, sizeof(char**));
557 if (!to->h_addr_list) {
558 return PR_FAILURE;
559 }
560
561 /* Copy the addresses, one at a time */
562 for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
563 to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
564 if (!to->h_addr_list[na]) {
565 return PR_FAILURE;
566 }
567 if (conversion != _PRIPAddrNoConversion
568 && from->h_addrtype == AF_INET2) {
569 if (conversion == _PRIPAddrIPv4Mapped) {
570 MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
571 } else {
572 PR_ASSERT(conversion == _PRIPAddrIPv4Compat)((conversion == _PRIPAddrIPv4Compat)?((void)0):PR_Assert("conversion == _PRIPAddrIPv4Compat"
,"../../../../pr/src/misc/prnetdb.c",572))
;
573 MakeIPv4CompatAddr(*ap, to->h_addr_list[na]);
574 }
575 } else {
576 memcpy(to->h_addr_list[na], *ap, to->h_length);
577 }
578 }
579 to->h_addr_list[na] = 0;
580 return PR_SUCCESS;
581}
582
583#if !defined(_PR_HAVE_GETPROTO_R)
584/*
585** Copy a protoent, and all of the memory that it refers to into
586** (hopefully) stacked buffers.
587*/
588static PRStatus CopyProtoent(
589 struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to)
590{
591 PRIntn len, na;
592 char **ap;
593
594 /* Do the easy stuff */
595 to->p_num = from->p_proto;
596
597 /* Copy the official name */
598 if (!from->p_name) {
599 return PR_FAILURE;
600 }
601 len = strlen(from->p_name) + 1;
602 to->p_name = Alloc(len, &buf, &bufsize, 0);
603 if (!to->p_name) {
604 return PR_FAILURE;
605 }
606 memcpy(to->p_name, from->p_name, len);
607
608 /* Count the aliases, then allocate storage for the pointers */
609 for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++) {;} /* nothing to execute */
610 to->p_aliases = (char**)Alloc(
611 na * sizeof(char*), &buf, &bufsize, sizeof(char**));
612 if (!to->p_aliases) {
613 return PR_FAILURE;
614 }
615
616 /* Copy the aliases, one at a time */
617 for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) {
618 len = strlen(*ap) + 1;
619 to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0);
620 if (!to->p_aliases[na]) {
621 return PR_FAILURE;
622 }
623 memcpy(to->p_aliases[na], *ap, len);
624 }
625 to->p_aliases[na] = 0;
626
627 return PR_SUCCESS;
628}
629#endif /* !defined(_PR_HAVE_GETPROTO_R) */
630
631/*
632 * #################################################################
633 * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables
634 * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and
635 * PR_GetHostByAddr. DO NOT CHANGE THE NAMES OF THESE LOCAL
636 * VARIABLES OR ARGUMENTS.
637 * #################################################################
638 */
639#if defined(_PR_HAVE_GETHOST_R_INT)
640
641#define GETHOSTBYNAME(name)(gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &
h_err), h)
\
642 (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
643#define GETHOSTBYNAME2(name, af)(gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
\
644 (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h)
645#define GETHOSTBYADDR(addr, addrlen, af)(gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize
, &h, &h_err), h)
\
646 (gethostbyaddr_r(addr, addrlen, af, \
647 &tmphe, tmpbuf, bufsize, &h, &h_err), h)
648
649#elif defined(_PR_HAVE_GETHOST_R_POINTER)
650
651#define GETHOSTBYNAME(name)(gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &
h_err), h)
\
652 gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err)
653#define GETHOSTBYNAME2(name, af)(gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
\
654 gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err)
655#define GETHOSTBYADDR(addr, addrlen, af)(gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize
, &h, &h_err), h)
\
656 gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err)
657
658#else
659
660#define GETHOSTBYNAME(name)(gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &
h_err), h)
gethostbyname(name)
661#define GETHOSTBYNAME2(name, af)(gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
gethostbyname2(name, af)
662#define GETHOSTBYADDR(addr, addrlen, af)(gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize
, &h, &h_err), h)
gethostbyaddr(addr, addrlen, af)
663
664#endif /* definition of GETHOSTBYXXX */
665
666PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_GetHostByName(
667 const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp)
668{
669 struct hostent *h;
670 PRStatus rv = PR_FAILURE;
671#if defined(_PR_HAVE_GETHOST_R)
672 char localbuf[PR_NETDB_BUF_SIZE2048];
673 char *tmpbuf;
674 struct hostent tmphe;
675 int h_err;
676#endif
677
678 if (!_pr_initialized) {
679 _PR_ImplicitInitialization();
680 }
681
682#if defined(_PR_HAVE_GETHOST_R)
683 tmpbuf = localbuf;
684 if (bufsize > sizeof(localbuf))
685 {
686 tmpbuf = (char *)PR_Malloc(bufsize);
687 if (NULL((void*)0) == tmpbuf)
688 {
689 PR_SetError(PR_OUT_OF_MEMORY_ERROR(-6000L), 0);
690 return rv;
691 }
692 }
693#endif
694
695 LOCK_DNS();
696
697 h = GETHOSTBYNAME(name)(gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &
h_err), h)
;
698
699 if (NULL((void*)0) == h)
700 {
701 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_GETHOST_ERRNO()(*__h_errno_location ()));
702 }
703 else
704 {
705 _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
706 rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
707 if (PR_SUCCESS != rv) {
708 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR(-5974L), 0);
709 }
710 }
711 UNLOCK_DNS();
712#if defined(_PR_HAVE_GETHOST_R)
713 if (tmpbuf != localbuf) {
714 PR_Free(tmpbuf);
715 }
716#endif
717 return rv;
718}
719
720#if !defined(_PR_INET6) && \
721 defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
722typedef struct hostent * (*_pr_getipnodebyname_t)(const char *, int,
723 int, int *);
724typedef struct hostent * (*_pr_getipnodebyaddr_t)(const void *, size_t,
725 int, int *);
726typedef void (*_pr_freehostent_t)(struct hostent *);
727static void * _pr_getipnodebyname_fp;
728static void * _pr_getipnodebyaddr_fp;
729static void * _pr_freehostent_fp;
730
731/*
732 * Look up the addresses of getipnodebyname, getipnodebyaddr,
733 * and freehostent.
734 */
735PRStatus
736_pr_find_getipnodebyname(void)
737{
738 PRLibrary *lib;
739 PRStatus rv;
740#define GETIPNODEBYNAME "getipnodebyname"
741#define GETIPNODEBYADDR "getipnodebyaddr"
742#define FREEHOSTENT "freehostent"
743
744 _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib);
745 if (NULL((void*)0) != _pr_getipnodebyname_fp) {
746 _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT);
747 if (NULL((void*)0) != _pr_freehostent_fp) {
748 _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR);
749 if (NULL((void*)0) != _pr_getipnodebyaddr_fp) {
750 rv = PR_SUCCESS;
751 }
752 else {
753 rv = PR_FAILURE;
754 }
755 } else {
756 rv = PR_FAILURE;
757 }
758 (void)PR_UnloadLibrary(lib);
759 } else {
760 rv = PR_FAILURE;
761 }
762 return rv;
763}
764#endif
765
766#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
767/*
768** Append the V4 addresses to the end of the list
769*/
770static PRStatus AppendV4AddrsToHostent(
771 struct hostent *from,
772 char **buf,
773 PRIntn *bufsize,
774 PRHostEnt *to)
775{
776 PRIntn na, na_old;
777 char **ap;
778 char **new_addr_list;
779
780 /* Count the addresses, then grow storage for the pointers */
781 for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++)
782 {;} /* nothing to execute */
783 for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++)
784 {;} /* nothing to execute */
785 new_addr_list = (char**)Alloc(
786 na * sizeof(char*), buf, bufsize, sizeof(char**));
787 if (!new_addr_list) {
788 return PR_FAILURE;
789 }
790
791 /* Copy the V6 addresses, one at a time */
792 for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) {
793 new_addr_list[na] = to->h_addr_list[na];
794 }
795 to->h_addr_list = new_addr_list;
796
797 /* Copy the V4 addresses, one at a time */
798 for (ap = from->h_addr_list; *ap != 0; na++, ap++) {
799 to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0);
800 if (!to->h_addr_list[na]) {
801 return PR_FAILURE;
802 }
803 MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
804 }
805 to->h_addr_list[na] = 0;
806 return PR_SUCCESS;
807}
808#endif
809
810PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_GetIPNodeByName(
811 const char *name, PRUint16 af, PRIntn flags,
812 char *buf, PRIntn bufsize, PRHostEnt *hp)
813{
814 struct hostent *h = 0;
815 PRStatus rv = PR_FAILURE;
816#if defined(_PR_HAVE_GETHOST_R)
817 char localbuf[PR_NETDB_BUF_SIZE2048];
818 char *tmpbuf;
819 struct hostent tmphe;
820 int h_err;
821#endif
822#if defined(_PR_HAVE_GETIPNODEBYNAME)
823 PRUint16 md_af = af;
824 int error_num;
825 int tmp_flags = 0;
826#endif
827#if defined(_PR_HAVE_GETHOSTBYNAME2)
828 PRBool did_af_inet = PR_FALSE0;
829#endif
830
831 if (!_pr_initialized) {
832 _PR_ImplicitInitialization();
833 }
834
835 if (af != PR_AF_INET2 && af != PR_AF_INET610) {
836 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
837 return PR_FAILURE;
838 }
839
840#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
841 PR_Lock(_pr_query_ifs_lock);
842 /*
843 * Keep querying the presence of IPv4 and IPv6 interfaces until
844 * at least one is up. This allows us to detect the local
845 * machine going from offline to online.
846 */
847 if (!_pr_have_inet_if && !_pr_have_inet6_if) {
848 _pr_QueryNetIfs();
849#ifdef DEBUG_QUERY_IFS
850 if (_pr_have_inet_if) {
851 printf("Have IPv4 source address\n");
852 }
853 if (_pr_have_inet6_if) {
854 printf("Have IPv6 source address\n");
855 }
856#endif
857 }
858 PR_Unlock(_pr_query_ifs_lock);
859#endif
860
861#if defined(_PR_HAVE_GETIPNODEBYNAME)
862 if (flags & PR_AI_V4MAPPED0x10) {
863 tmp_flags |= AI_V4MAPPED0x0008;
864 }
865 if (flags & PR_AI_ADDRCONFIG0x20) {
866 tmp_flags |= AI_ADDRCONFIG0x0020;
867 }
868 if (flags & PR_AI_ALL0x08) {
869 tmp_flags |= AI_ALL0x0010;
870 }
871 if (af == PR_AF_INET610) {
872 md_af = AF_INET610;
873 }
874 else {
875 md_af = af;
876 }
877#endif
878
879#if defined(_PR_HAVE_GETHOST_R)
880 tmpbuf = localbuf;
881 if (bufsize > sizeof(localbuf))
882 {
883 tmpbuf = (char *)PR_Malloc(bufsize);
884 if (NULL((void*)0) == tmpbuf)
885 {
886 PR_SetError(PR_OUT_OF_MEMORY_ERROR(-6000L), 0);
887 return rv;
888 }
889 }
890#endif
891
892 /* Do not need to lock the DNS lock if getipnodebyname() is called */
893#ifdef _PR_INET6
894#ifdef _PR_HAVE_GETHOSTBYNAME2
895 LOCK_DNS();
896 if (af == PR_AF_INET610)
897 {
898 if ((flags & PR_AI_ADDRCONFIG0x20) == 0 || _pr_have_inet6_if)
899 {
900#ifdef _PR_INET6_PROBE
901 if (_pr_ipv6_is_present())
902#endif
903 h = GETHOSTBYNAME2(name, AF_INET6)(gethostbyname2_r(name, 10, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
;
904 }
905 if ((NULL((void*)0) == h) && (flags & PR_AI_V4MAPPED0x10)
906 && ((flags & PR_AI_ADDRCONFIG0x20) == 0 || _pr_have_inet_if))
907 {
908 did_af_inet = PR_TRUE1;
909 h = GETHOSTBYNAME2(name, AF_INET)(gethostbyname2_r(name, 2, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
;
910 }
911 }
912 else
913 {
914 if ((flags & PR_AI_ADDRCONFIG0x20) == 0 || _pr_have_inet_if)
915 {
916 did_af_inet = PR_TRUE1;
917 h = GETHOSTBYNAME2(name, af)(gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
;
918 }
919 }
920#elif defined(_PR_HAVE_GETIPNODEBYNAME)
921 h = getipnodebyname(name, md_af, tmp_flags, &error_num);
922#else
923#error "Unknown name-to-address translation function"
924#endif /* _PR_HAVE_GETHOSTBYNAME2 */
925#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
926 if (_pr_ipv6_is_present())
927 {
928#ifdef PR_GETIPNODE_NOT_THREADSAFE
929 LOCK_DNS();
930#endif
931 h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num);
932 }
933 else
934 {
935 LOCK_DNS();
936 h = GETHOSTBYNAME(name)(gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &
h_err), h)
;
937 }
938#else /* _PR_INET6 */
939 LOCK_DNS();
940 h = GETHOSTBYNAME(name)(gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &
h_err), h)
;
941#endif /* _PR_INET6 */
942
943 if (NULL((void*)0) == h)
944 {
945#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
946 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), error_num);
947#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
948 if (_pr_ipv6_is_present()) {
949 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), error_num);
950 }
951 else {
952 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_GETHOST_ERRNO()(*__h_errno_location ()));
953 }
954#else
955 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_GETHOST_ERRNO()(*__h_errno_location ()));
956#endif
957 }
958 else
959 {
960 _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
961
962 if (af == PR_AF_INET610) {
963 conversion = _PRIPAddrIPv4Mapped;
964 }
965 rv = CopyHostent(h, &buf, &bufsize, conversion, hp);
966 if (PR_SUCCESS != rv) {
967 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR(-5974L), 0);
968 }
969#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
970 freehostent(h);
971#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
972 if (_pr_ipv6_is_present()) {
973 (*((_pr_freehostent_t)_pr_freehostent_fp))(h);
974 }
975#endif
976#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2)
977 if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED0x10)
978 && ((flags & PR_AI_ALL0x08)
979 || ((flags & PR_AI_ADDRCONFIG0x20) && _pr_have_inet_if))
980 && !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)(gethostbyname2_r(name, 2, &tmphe, tmpbuf, bufsize, &
h, &h_err), h)
) != 0) {
981 rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp);
982 if (PR_SUCCESS != rv) {
983 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR(-5974L), 0);
984 }
985 }
986#endif
987 }
988
989 /* Must match the convoluted logic above for LOCK_DNS() */
990#ifdef _PR_INET6
991#ifdef _PR_HAVE_GETHOSTBYNAME2
992 UNLOCK_DNS();
993#endif /* _PR_HAVE_GETHOSTBYNAME2 */
994#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME)
995#ifdef PR_GETIPNODE_NOT_THREADSAFE
996 UNLOCK_DNS();
997#else
998 if (!_pr_ipv6_is_present()) {
999 UNLOCK_DNS();
1000 }
1001#endif
1002#else /* _PR_INET6 */
1003 UNLOCK_DNS();
1004#endif /* _PR_INET6 */
1005
1006#if defined(_PR_HAVE_GETHOST_R)
1007 if (tmpbuf != localbuf) {
1008 PR_Free(tmpbuf);
1009 }
1010#endif
1011
1012 return rv;
1013}
1014
1015PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_GetHostByAddr(
1016 const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry)
1017{
1018 struct hostent *h;
1019 PRStatus rv = PR_FAILURE;
1020 const void *addr;
1021 PRUint32 tmp_ip;
1022 int addrlen;
1023 PRInt32 af;
1024#if defined(_PR_HAVE_GETHOST_R)
1025 char localbuf[PR_NETDB_BUF_SIZE2048];
1026 char *tmpbuf;
1027 struct hostent tmphe;
1028 int h_err;
1029#endif
1030#if defined(_PR_HAVE_GETIPNODEBYADDR)
1031 int error_num;
1032#endif
1033
1034 if (!_pr_initialized) {
1035 _PR_ImplicitInitialization();
1036 }
1037
1038 if (hostaddr->raw.family == PR_AF_INET610)
1039 {
1040#if defined(_PR_INET6_PROBE)
1041 af = _pr_ipv6_is_present() ? AF_INET610 : AF_INET2;
1042#elif defined(_PR_INET6)
1043 af = AF_INET610;
1044#else
1045 af = AF_INET2;
1046#endif
1047#if defined(_PR_GHBA_DISALLOW_V4MAPPED)
1048 if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)(((&hostaddr->ipv6.ip)->_S6_un._S6_u32[0] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u32[1] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[8] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[9] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[10] == 0xff) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[11] == 0xff))
) {
1049 af = AF_INET2;
1050 }
1051#endif
1052 }
1053 else
1054 {
1055 PR_ASSERT(hostaddr->raw.family == AF_INET)((hostaddr->raw.family == 2)?((void)0):PR_Assert("hostaddr->raw.family == AF_INET"
,"../../../../pr/src/misc/prnetdb.c",1055))
;
1056 af = AF_INET2;
1057 }
1058 if (hostaddr->raw.family == PR_AF_INET610) {
1059#if defined(_PR_INET6) || defined(_PR_INET6_PROBE)
1060 if (af == AF_INET610) {
1061 addr = &hostaddr->ipv6.ip;
1062 addrlen = sizeof(hostaddr->ipv6.ip);
1063 }
1064 else
1065#endif
1066 {
1067 PR_ASSERT(af == AF_INET)((af == 2)?((void)0):PR_Assert("af == AF_INET","../../../../pr/src/misc/prnetdb.c"
,1067))
;
1068 if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)(((&hostaddr->ipv6.ip)->_S6_un._S6_u32[0] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u32[1] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[8] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[9] == 0) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[10] == 0xff) &&
((&hostaddr->ipv6.ip)->_S6_un._S6_u8[11] == 0xff))
) {
1069 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
1070 return rv;
1071 }
1072 tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)(((PRIPv6Addr *) &hostaddr->ipv6.ip)->_S6_un._S6_u32
[3])
1073 &hostaddr->ipv6.ip)(((PRIPv6Addr *) &hostaddr->ipv6.ip)->_S6_un._S6_u32
[3])
;
1074 addr = &tmp_ip;
1075 addrlen = sizeof(tmp_ip);
1076 }
1077 } else {
1078 PR_ASSERT(hostaddr->raw.family == AF_INET)((hostaddr->raw.family == 2)?((void)0):PR_Assert("hostaddr->raw.family == AF_INET"
,"../../../../pr/src/misc/prnetdb.c",1078))
;
1079 PR_ASSERT(af == AF_INET)((af == 2)?((void)0):PR_Assert("af == AF_INET","../../../../pr/src/misc/prnetdb.c"
,1079))
;
1080 addr = &hostaddr->inet.ip;
1081 addrlen = sizeof(hostaddr->inet.ip);
1082 }
1083
1084#if defined(_PR_HAVE_GETHOST_R)
1085 tmpbuf = localbuf;
1086 if (bufsize > sizeof(localbuf))
1087 {
1088 tmpbuf = (char *)PR_Malloc(bufsize);
1089 if (NULL((void*)0) == tmpbuf)
1090 {
1091 PR_SetError(PR_OUT_OF_MEMORY_ERROR(-6000L), 0);
1092 return rv;
1093 }
1094 }
1095#endif
1096
1097 /* Do not need to lock the DNS lock if getipnodebyaddr() is called */
1098#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
1099 h = getipnodebyaddr(addr, addrlen, af, &error_num);
1100#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
1101 if (_pr_ipv6_is_present())
1102 {
1103#ifdef PR_GETIPNODE_NOT_THREADSAFE
1104 LOCK_DNS();
1105#endif
1106 h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen,
1107 af, &error_num);
1108 }
1109 else
1110 {
1111 LOCK_DNS();
1112 h = GETHOSTBYADDR(addr, addrlen, af)(gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize
, &h, &h_err), h)
;
1113 }
1114#else /* _PR_HAVE_GETIPNODEBYADDR */
1115 LOCK_DNS();
1116 h = GETHOSTBYADDR(addr, addrlen, af)(gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize
, &h, &h_err), h)
;
1117#endif /* _PR_HAVE_GETIPNODEBYADDR */
1118 if (NULL((void*)0) == h)
1119 {
1120#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
1121 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), error_num);
1122#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
1123 if (_pr_ipv6_is_present()) {
1124 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), error_num);
1125 }
1126 else {
1127 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_GETHOST_ERRNO()(*__h_errno_location ()));
1128 }
1129#else
1130 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_GETHOST_ERRNO()(*__h_errno_location ()));
1131#endif
1132 }
1133 else
1134 {
1135 _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
1136 if (hostaddr->raw.family == PR_AF_INET610) {
1137 if (af == AF_INET2) {
1138 if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*)((((PRIPv6Addr*) &hostaddr->ipv6.ip)->_S6_un._S6_u32
[0] == 0) && (((PRIPv6Addr*) &hostaddr->ipv6.ip
)->_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr*) &
hostaddr->ipv6.ip)->_S6_un._S6_u8[8] == 0) && (
((PRIPv6Addr*) &hostaddr->ipv6.ip)->_S6_un._S6_u8[9
] == 0) && (((PRIPv6Addr*) &hostaddr->ipv6.ip)
->_S6_un._S6_u8[10] == 0xff) && (((PRIPv6Addr*) &
hostaddr->ipv6.ip)->_S6_un._S6_u8[11] == 0xff))
1139 &hostaddr->ipv6.ip)((((PRIPv6Addr*) &hostaddr->ipv6.ip)->_S6_un._S6_u32
[0] == 0) && (((PRIPv6Addr*) &hostaddr->ipv6.ip
)->_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr*) &
hostaddr->ipv6.ip)->_S6_un._S6_u8[8] == 0) && (
((PRIPv6Addr*) &hostaddr->ipv6.ip)->_S6_un._S6_u8[9
] == 0) && (((PRIPv6Addr*) &hostaddr->ipv6.ip)
->_S6_un._S6_u8[10] == 0xff) && (((PRIPv6Addr*) &
hostaddr->ipv6.ip)->_S6_un._S6_u8[11] == 0xff))
) {
1140 conversion = _PRIPAddrIPv4Mapped;
1141 } else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *)((((PRIPv6Addr *) &hostaddr->ipv6.ip)->_S6_un._S6_u32
[0] == 0) && (((PRIPv6Addr *) &hostaddr->ipv6.
ip)->_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *) &
hostaddr->ipv6.ip)->_S6_un._S6_u32[2] == 0))
1142 &hostaddr->ipv6.ip)((((PRIPv6Addr *) &hostaddr->ipv6.ip)->_S6_un._S6_u32
[0] == 0) && (((PRIPv6Addr *) &hostaddr->ipv6.
ip)->_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *) &
hostaddr->ipv6.ip)->_S6_un._S6_u32[2] == 0))
) {
1143 conversion = _PRIPAddrIPv4Compat;
1144 }
1145 }
1146 }
1147 rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry);
1148 if (PR_SUCCESS != rv) {
1149 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR(-5974L), 0);
1150 }
1151#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
1152 freehostent(h);
1153#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR)
1154 if (_pr_ipv6_is_present()) {
1155 (*((_pr_freehostent_t)_pr_freehostent_fp))(h);
1156 }
1157#endif
1158 }
1159
1160 /* Must match the convoluted logic above for LOCK_DNS() */
1161#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6)
1162#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE)
1163#ifdef PR_GETIPNODE_NOT_THREADSAFE
1164 UNLOCK_DNS();
1165#else
1166 if (!_pr_ipv6_is_present()) {
1167 UNLOCK_DNS();
1168 }
1169#endif
1170#else /* _PR_HAVE_GETIPNODEBYADDR */
1171 UNLOCK_DNS();
1172#endif /* _PR_HAVE_GETIPNODEBYADDR */
1173
1174#if defined(_PR_HAVE_GETHOST_R)
1175 if (tmpbuf != localbuf) {
1176 PR_Free(tmpbuf);
1177 }
1178#endif
1179
1180 return rv;
1181}
1182
1183/******************************************************************************/
1184/*
1185 * Some systems define a reentrant version of getprotobyname(). Too bad
1186 * the signature isn't always the same. But hey, they tried. If there
1187 * is such a definition, use it. Otherwise, grab a lock and do it here.
1188 */
1189/******************************************************************************/
1190
1191#if !defined(_PR_HAVE_GETPROTO_R)
1192/*
1193 * This may seem like a silly thing to do, but the compiler SHOULD
1194 * complain if getprotobyname_r() is implemented on some system and
1195 * we're not using it. For sure these signatures are different than
1196 * any usable implementation.
1197 */
1198
1199#if defined(ANDROID)
1200/* Android's Bionic libc system includes prototypes for these in netdb.h,
1201 * but doesn't actually include implementations. It uses the 5-arg form,
1202 * so these functions end up not matching the prototype. So just rename
1203 * them if not found.
1204 */
1205#define getprotobyname_r _pr_getprotobyname_r
1206#define getprotobynumber_r _pr_getprotobynumber_r
1207#endif
1208
1209static struct protoent *getprotobyname_r(const char* name)
1210{
1211 return getprotobyname(name);
1212} /* getprotobyname_r */
1213
1214static struct protoent *getprotobynumber_r(PRInt32 number)
1215{
1216 return getprotobynumber(number);
1217} /* getprotobynumber_r */
1218
1219#endif /* !defined(_PR_HAVE_GETPROTO_R) */
1220
1221PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_GetProtoByName(
1222 const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result)
1223{
1224 PRStatus rv = PR_SUCCESS;
1225#if defined(_PR_HAVE_GETPROTO_R)
1226 struct protoent* res = (struct protoent*)result;
1227#endif
1228
1229 if (!_pr_initialized) {
1230 _PR_ImplicitInitialization();
1231 }
1232
1233#if defined(_PR_HAVE_GETPROTO_R_INT)
1234 {
1235 /*
1236 ** The protoent_data has a pointer as the first field.
1237 ** That implies the buffer better be aligned, and char*
1238 ** doesn't promise much.
1239 */
1240 PRUptrdiff aligned = (PRUptrdiff)buffer;
1241 if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
1242 {
1243 aligned += sizeof(struct protoent_data*) - 1;
1244 aligned &= ~(sizeof(struct protoent_data*) - 1);
1245 buflen -= (aligned - (PRUptrdiff)buffer);
1246 buffer = (char*)aligned;
1247 }
1248 }
1249#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */
1250
1251 if (PR_MIN_NETDB_BUF_SIZE1024 > buflen)
1252 {
1253 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
1254 return PR_FAILURE;
1255 }
1256
1257#if defined(_PR_HAVE_GETPROTO_R_POINTER)
1258 if (NULL((void*)0) == getprotobyname_r(name, res, buffer, buflen))
1259 {
1260 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1261 return PR_FAILURE;
1262 }
1263#elif defined(_PR_HAVE_GETPROTO_R_INT)
1264 /*
1265 ** The buffer needs to be zero'd, and it should be
1266 ** at least the size of a struct protoent_data.
1267 */
1268 memset(buffer, 0, buflen);
1269 if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer))
1270 {
1271 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1272 return PR_FAILURE;
1273 }
1274#elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
1275 /* The 5th argument for getprotobyname_r() cannot be NULL */
1276 if (-1 == getprotobyname_r(name, res, buffer, buflen, &res))
1277 {
1278 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1279 return PR_FAILURE;
1280 }
1281#else /* do it the hard way */
1282 {
1283 struct protoent *staticBuf;
1284 PR_Lock(_getproto_lock);
1285 staticBuf = getprotobyname_r(name);
1286 if (NULL((void*)0) == staticBuf)
1287 {
1288 rv = PR_FAILURE;
1289 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1290 }
1291 else
1292 {
1293 rv = CopyProtoent(staticBuf, buffer, buflen, result);
1294 if (PR_FAILURE == rv) {
1295 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR(-5974L), 0);
1296 }
1297 }
1298 PR_Unlock(_getproto_lock);
1299 }
1300#endif /* all that */
1301 return rv;
1302}
1303
1304PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_GetProtoByNumber(
1305 PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result)
1306{
1307 PRStatus rv = PR_SUCCESS;
1308#if defined(_PR_HAVE_GETPROTO_R)
1309 struct protoent* res = (struct protoent*)result;
1310#endif
1311
1312 if (!_pr_initialized) {
1313 _PR_ImplicitInitialization();
1314 }
1315
1316#if defined(_PR_HAVE_GETPROTO_R_INT)
1317 {
1318 /*
1319 ** The protoent_data has a pointer as the first field.
1320 ** That implies the buffer better be aligned, and char*
1321 ** doesn't promise much.
1322 */
1323 PRUptrdiff aligned = (PRUptrdiff)buffer;
1324 if (0 != (aligned & (sizeof(struct protoent_data*) - 1)))
1325 {
1326 aligned += sizeof(struct protoent_data*) - 1;
1327 aligned &= ~(sizeof(struct protoent_data*) - 1);
1328 buflen -= (aligned - (PRUptrdiff)buffer);
1329 buffer = (char*)aligned;
1330 }
1331 }
1332#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */
1333
1334 if (PR_MIN_NETDB_BUF_SIZE1024 > buflen)
1335 {
1336 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
1337 return PR_FAILURE;
1338 }
1339
1340#if defined(_PR_HAVE_GETPROTO_R_POINTER)
1341 if (NULL((void*)0) == getprotobynumber_r(number, res, buffer, buflen))
1342 {
1343 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1344 return PR_FAILURE;
1345 }
1346
1347#elif defined(_PR_HAVE_GETPROTO_R_INT)
1348 /*
1349 ** The buffer needs to be zero'd for these OS's.
1350 */
1351 memset(buffer, 0, buflen);
1352 if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer))
1353 {
1354 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1355 return PR_FAILURE;
1356 }
1357#elif defined(_PR_HAVE_5_ARG_GETPROTO_R)
1358 /* The 5th argument for getprotobynumber_r() cannot be NULL */
1359 if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res))
1360 {
1361 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1362 return PR_FAILURE;
1363 }
1364#else /* do it the hard way */
1365 {
1366 struct protoent *staticBuf;
1367 PR_Lock(_getproto_lock);
1368 staticBuf = getprotobynumber_r(number);
1369 if (NULL((void*)0) == staticBuf)
1370 {
1371 rv = PR_FAILURE;
1372 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), _MD_ERRNO()((*__errno_location ())));
1373 }
1374 else
1375 {
1376 rv = CopyProtoent(staticBuf, buffer, buflen, result);
1377 if (PR_FAILURE == rv) {
1378 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR(-5974L), 0);
1379 }
1380 }
1381 PR_Unlock(_getproto_lock);
1382 }
1383#endif /* all that crap */
1384 return rv;
1385
1386}
1387
1388PRUintn _PR_NetAddrSize(const PRNetAddr* addr)
1389{
1390 PRUintn addrsize;
1391
1392 /*
1393 * RFC 2553 added a new field (sin6_scope_id) to
1394 * struct sockaddr_in6. PRNetAddr's ipv6 member has a
1395 * scope_id field to match the new field. In order to
1396 * work with older implementations supporting RFC 2133,
1397 * we take the size of struct sockaddr_in6 instead of
1398 * addr->ipv6.
1399 */
1400 if (AF_INET2 == addr->raw.family) {
1401 addrsize = sizeof(addr->inet);
1402 }
1403 else if (PR_AF_INET610 == addr->raw.family)
1404#if defined(_PR_INET6)
1405 addrsize = sizeof(struct sockaddr_in6);
1406#else
1407 addrsize = sizeof(addr->ipv6);
1408#endif
1409#if defined(XP_UNIX1) || defined(XP_OS2)
1410 else if (AF_UNIX1 == addr->raw.family)
1411 {
1412#if defined(LINUX1)
1413 if (addr->local.path[0] == 0)
1414 /* abstract socket address is supported on Linux only */
1415 addrsize = strnlen(addr->local.path + 1,
1416 sizeof(addr->local.path)) +
1417 offsetof(struct sockaddr_un, sun_path)__builtin_offsetof(struct sockaddr_un, sun_path) + 1;
1418 else
1419#endif
1420 addrsize = sizeof(addr->local);
1421 }
1422#endif
1423 else {
1424 addrsize = 0;
1425 }
1426
1427 return addrsize;
1428} /* _PR_NetAddrSize */
1429
1430PR_IMPLEMENT(PRIntn)__attribute__((visibility("default"))) PRIntn PR_EnumerateHostEnt(
1431 PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address)
1432{
1433 void *addr = hostEnt->h_addr_list[enumIndex++];
1434 memset(address, 0, sizeof(PRNetAddr));
1435 if (NULL((void*)0) == addr) {
1436 enumIndex = 0;
1437 }
1438 else
1439 {
1440 address->raw.family = hostEnt->h_addrtype;
1441 if (PR_AF_INET610 == hostEnt->h_addrtype)
1442 {
1443 address->ipv6.port = htons(port);
1444 address->ipv6.flowinfo = 0;
1445 address->ipv6.scope_id = 0;
1446 memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
1447 }
1448 else
1449 {
1450 PR_ASSERT(AF_INET == hostEnt->h_addrtype)((2 == hostEnt->h_addrtype)?((void)0):PR_Assert("AF_INET == hostEnt->h_addrtype"
,"../../../../pr/src/misc/prnetdb.c",1450))
;
1451 address->inet.port = htons(port);
1452 memcpy(&address->inet.ip, addr, hostEnt->h_length);
1453 }
1454 }
1455 return enumIndex;
1456} /* PR_EnumerateHostEnt */
1457
1458PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_InitializeNetAddr(
1459 PRNetAddrValue val, PRUint16 port, PRNetAddr *addr)
1460{
1461 PRStatus rv = PR_SUCCESS;
1462 if (!_pr_initialized) {
1463 _PR_ImplicitInitialization();
1464 }
1465
1466 if (val != PR_IpAddrNull) {
1467 memset(addr, 0, sizeof(*addr));
1468 }
1469 addr->inet.family = AF_INET2;
1470 addr->inet.port = htons(port);
1471 switch (val)
1472 {
1473 case PR_IpAddrNull:
1474 break; /* don't overwrite the address */
1475 case PR_IpAddrAny:
1476 addr->inet.ip = htonl(INADDR_ANY((in_addr_t) 0x00000000));
1477 break;
1478 case PR_IpAddrLoopback:
1479 addr->inet.ip = htonl(INADDR_LOOPBACK((in_addr_t) 0x7f000001));
1480 break;
1481 default:
1482 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
1483 rv = PR_FAILURE;
1484 }
1485 return rv;
1486} /* PR_InitializeNetAddr */
1487
1488PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_SetNetAddr(
1489 PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
1490{
1491 PRStatus rv = PR_SUCCESS;
1492 if (!_pr_initialized) {
1493 _PR_ImplicitInitialization();
1494 }
1495
1496 if (af == PR_AF_INET610)
1497 {
1498 if (val != PR_IpAddrNull) {
1499 memset(addr, 0, sizeof(addr->ipv6));
1500 }
1501 addr->ipv6.family = af;
1502 addr->ipv6.port = htons(port);
1503 addr->ipv6.flowinfo = 0;
1504 addr->ipv6.scope_id = 0;
1505 switch (val)
1506 {
1507 case PR_IpAddrNull:
1508 break; /* don't overwrite the address */
1509 case PR_IpAddrAny:
1510 addr->ipv6.ip = _pr_in6addr_any;
1511 break;
1512 case PR_IpAddrLoopback:
1513 addr->ipv6.ip = _pr_in6addr_loopback;
1514 break;
1515 default:
1516 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
1517 rv = PR_FAILURE;
1518 }
1519 }
1520 else
1521 {
1522 if (val != PR_IpAddrNull) {
1523 memset(addr, 0, sizeof(addr->inet));
1524 }
1525 addr->inet.family = af;
1526 addr->inet.port = htons(port);
1527 switch (val)
1528 {
1529 case PR_IpAddrNull:
1530 break; /* don't overwrite the address */
1531 case PR_IpAddrAny:
1532 addr->inet.ip = htonl(INADDR_ANY((in_addr_t) 0x00000000));
1533 break;
1534 case PR_IpAddrLoopback:
1535 addr->inet.ip = htonl(INADDR_LOOPBACK((in_addr_t) 0x7f000001));
1536 break;
1537 default:
1538 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
1539 rv = PR_FAILURE;
1540 }
1541 }
1542 return rv;
1543} /* PR_SetNetAddr */
1544
1545PR_IMPLEMENT(PRBool)__attribute__((visibility("default"))) PRBool
1546PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
1547{
1548 if (addr->raw.family == PR_AF_INET610) {
1549 if (val == PR_IpAddrAny) {
1550 if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)((((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[0]
== 0) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *)&addr->
ipv6.ip)->_S6_un._S6_u32[2] == 0) && (((PRIPv6Addr
*)&addr->ipv6.ip)->_S6_un._S6_u32[3] == 0))
) {
1551 return PR_TRUE1;
1552 }
1553 if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)((((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[0]
== 0) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *)&addr->
ipv6.ip)->_S6_un._S6_u8[8] == 0) && (((PRIPv6Addr *
)&addr->ipv6.ip)->_S6_un._S6_u8[9] == 0) &&
(((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u8[10]
== 0xff) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u8[11] == 0xff))
1554 && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)(((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[3])
1555 == htonl(INADDR_ANY((in_addr_t) 0x00000000))) {
1556 return PR_TRUE1;
1557 }
1558 } else if (val == PR_IpAddrLoopback) {
1559 if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)((((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[0]
== 0) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *)&addr->
ipv6.ip)->_S6_un._S6_u32[2] == 0) && (((PRIPv6Addr
*)&addr->ipv6.ip)->_S6_un._S6_u8[12] == 0) &&
(((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u8[13]
== 0) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u8[14] == 0) && (((PRIPv6Addr *)&addr->
ipv6.ip)->_S6_un._S6_u8[15] == 0x1U))
) {
1560 return PR_TRUE1;
1561 }
1562 if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)((((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[0]
== 0) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *)&addr->
ipv6.ip)->_S6_un._S6_u8[8] == 0) && (((PRIPv6Addr *
)&addr->ipv6.ip)->_S6_un._S6_u8[9] == 0) &&
(((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u8[10]
== 0xff) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u8[11] == 0xff))
1563 && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip)(((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[3])
1564 == htonl(INADDR_LOOPBACK((in_addr_t) 0x7f000001))) {
1565 return PR_TRUE1;
1566 }
1567 } else if (val == PR_IpAddrV4Mapped
1568 && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)((((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u32[0]
== 0) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u32[1] == 0) && (((PRIPv6Addr *)&addr->
ipv6.ip)->_S6_un._S6_u8[8] == 0) && (((PRIPv6Addr *
)&addr->ipv6.ip)->_S6_un._S6_u8[9] == 0) &&
(((PRIPv6Addr *)&addr->ipv6.ip)->_S6_un._S6_u8[10]
== 0xff) && (((PRIPv6Addr *)&addr->ipv6.ip)->
_S6_un._S6_u8[11] == 0xff))
) {
1569 return PR_TRUE1;
1570 }
1571 } else {
1572 if (addr->raw.family == AF_INET2) {
1573 if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY((in_addr_t) 0x00000000))) {
1574 return PR_TRUE1;
1575 }
1576 if (val == PR_IpAddrLoopback
1577 && addr->inet.ip == htonl(INADDR_LOOPBACK((in_addr_t) 0x7f000001))) {
1578 return PR_TRUE1;
1579 }
1580 }
1581 }
1582 return PR_FALSE0;
1583}
1584
1585extern int pr_inet_aton(const char *cp, PRUint32 *addr);
1586
1587#define XX 127
1588static const unsigned char index_hex[256] = {
1589 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1590 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1591 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1592 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX,
1593 XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1594 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1595 XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1596 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1597 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1598 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1599 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1600 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1601 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1602 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1603 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1604 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
1605};
1606
1607/*
1608 * StringToV6Addr() returns 1 if the conversion succeeds,
1609 * or 0 if the input is not a valid IPv6 address string.
1610 * (Same as inet_pton(AF_INET6, string, addr).)
1611 */
1612static int StringToV6Addr(const char *string, PRIPv6Addr *addr)
1613{
1614 const unsigned char *s = (const unsigned char *)string;
1615 int section = 0; /* index of the current section (a 16-bit
1616 * piece of the address */
1617 int double_colon = -1; /* index of the section after the first
1618 * 16-bit group of zeros represented by
1619 * the double colon */
1620 unsigned int val;
1621 int len;
1622
1623 /* Handle initial (double) colon */
1624 if (*s == ':') {
1625 if (s[1] != ':') {
1626 return 0;
1627 }
1628 s += 2;
1629 addr->pr_s6_addr16_S6_un._S6_u16[0] = 0;
1630 section = double_colon = 1;
1631 }
1632
1633 while (*s) {
1634 if (section == 8) {
1635 return 0; /* too long */
1636 }
1637 if (*s == ':') {
1638 if (double_colon != -1) {
1639 return 0; /* two double colons */
1640 }
1641 addr->pr_s6_addr16_S6_un._S6_u16[section++] = 0;
1642 double_colon = section;
1643 s++;
1644 continue;
1645 }
1646 for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) {
1647 val = (val << 4) + index_hex[*s++];
1648 }
1649 if (*s == '.') {
1650 if (len == 0) {
1651 return 0; /* nothing between : and . */
1652 }
1653 break;
1654 }
1655 if (*s == ':') {
1656 s++;
1657 if (!*s) {
1658 return 0; /* cannot end with single colon */
1659 }
1660 } else if (*s) {
1661 return 0; /* bad character */
1662 }
1663 addr->pr_s6_addr16_S6_un._S6_u16[section++] = htons((unsigned short)val);
1664 }
1665
1666 if (*s == '.') {
1667 /* Have a trailing v4 format address */
1668 if (section > 6) {
1669 return 0; /* not enough room */
1670 }
1671
1672 /*
1673 * The number before the '.' is decimal, but we parsed it
1674 * as hex. That means it is in BCD. Check it for validity
1675 * and convert it to binary.
1676 */
1677 if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) {
1678 return 0;
1679 }
1680 val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf);
1681 addr->pr_s6_addr_S6_un._S6_u8[2 * section] = val;
1682
1683 s++;
1684 val = index_hex[*s++];
1685 if (val > 9) {
1686 return 0;
1687 }
1688 while (*s >= '0' && *s <= '9') {
1689 val = val * 10 + *s++ - '0';
1690 if (val > 255) {
1691 return 0;
1692 }
1693 }
1694 if (*s != '.') {
1695 return 0; /* must have exactly 4 decimal numbers */
1696 }
1697 addr->pr_s6_addr_S6_un._S6_u8[2 * section + 1] = val;
1698 section++;
1699
1700 s++;
1701 val = index_hex[*s++];
1702 if (val > 9) {
1703 return 0;
1704 }
1705 while (*s >= '0' && *s <= '9') {
1706 val = val * 10 + *s++ - '0';
1707 if (val > 255) {
1708 return 0;
1709 }
1710 }
1711 if (*s != '.') {
1712 return 0; /* must have exactly 4 decimal numbers */
1713 }
1714 addr->pr_s6_addr_S6_un._S6_u8[2 * section] = val;
1715
1716 s++;
1717 val = index_hex[*s++];
1718 if (val > 9) {
1719 return 0;
1720 }
1721 while (*s >= '0' && *s <= '9') {
1722 val = val * 10 + *s++ - '0';
1723 if (val > 255) {
1724 return 0;
1725 }
1726 }
1727 if (*s) {
1728 return 0; /* must have exactly 4 decimal numbers */
1729 }
1730 addr->pr_s6_addr_S6_un._S6_u8[2 * section + 1] = val;
1731 section++;
1732 }
1733
1734 if (double_colon != -1) {
1735 /* Stretch the double colon */
1736 int tosection;
1737 int ncopy = section - double_colon;
1738 for (tosection = 7; ncopy--; tosection--) {
1739 addr->pr_s6_addr16_S6_un._S6_u16[tosection] =
1740 addr->pr_s6_addr16_S6_un._S6_u16[double_colon + ncopy];
1741 }
1742 while (tosection >= double_colon) {
1743 addr->pr_s6_addr16_S6_un._S6_u16[tosection--] = 0;
1744 }
1745 } else if (section != 8) {
1746 return 0; /* too short */
1747 }
1748 return 1;
1749}
1750#undef XX
1751
1752#ifndef _PR_HAVE_INET_NTOP
1753static const char *basis_hex = "0123456789abcdef";
1754
1755/*
1756 * V6AddrToString() returns a pointer to the buffer containing
1757 * the text string if the conversion succeeds, and NULL otherwise.
1758 * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno
1759 * is not set on failure.)
1760 */
1761static const char *V6AddrToString(
1762 const PRIPv6Addr *addr, char *buf, PRUint32 size)
1763{
1764#define STUFF(c) do { \
1765 if (!size--) return NULL((void*)0); \
1766 *buf++ = (c); \
1767} while (0)
1768
1769 int double_colon = -1; /* index of the first 16-bit
1770 * group of zeros represented
1771 * by the double colon */
1772 int double_colon_length = 1; /* use double colon only if
1773 * there are two or more 16-bit
1774 * groups of zeros */
1775 int zero_length;
1776 int section;
1777 unsigned int val;
1778 const char *bufcopy = buf;
1779
1780 /* Scan to find the placement of the double colon */
1781 for (section = 0; section < 8; section++) {
1782 if (addr->pr_s6_addr16_S6_un._S6_u16[section] == 0) {
1783 zero_length = 1;
1784 section++;
1785 while (section < 8 && addr->pr_s6_addr16_S6_un._S6_u16[section] == 0) {
1786 zero_length++;
1787 section++;
1788 }
1789 /* Select the longest sequence of zeros */
1790 if (zero_length > double_colon_length) {
1791 double_colon = section - zero_length;
1792 double_colon_length = zero_length;
1793 }
1794 }
1795 }
1796
1797 /* Now start converting to a string */
1798 section = 0;
1799
1800 if (double_colon == 0) {
1801 if (double_colon_length == 6 ||
1802 (double_colon_length == 5 && addr->pr_s6_addr16_S6_un._S6_u16[5] == 0xffff)) {
1803 /* ipv4 format address */
1804 STUFF(':');
1805 STUFF(':');
1806 if (double_colon_length == 5) {
1807 STUFF('f');
1808 STUFF('f');
1809 STUFF('f');
1810 STUFF('f');
1811 STUFF(':');
1812 }
1813 if (addr->pr_s6_addr_S6_un._S6_u8[12] > 99) {
1814 STUFF(addr->pr_s6_addr_S6_un._S6_u8[12]/100 + '0');
1815 }
1816 if (addr->pr_s6_addr_S6_un._S6_u8[12] > 9) {
1817 STUFF((addr->pr_s6_addr_S6_un._S6_u8[12]%100)/10 + '0');
1818 }
1819 STUFF(addr->pr_s6_addr_S6_un._S6_u8[12]%10 + '0');
1820 STUFF('.');
1821 if (addr->pr_s6_addr_S6_un._S6_u8[13] > 99) {
1822 STUFF(addr->pr_s6_addr_S6_un._S6_u8[13]/100 + '0');
1823 }
1824 if (addr->pr_s6_addr_S6_un._S6_u8[13] > 9) {
1825 STUFF((addr->pr_s6_addr_S6_un._S6_u8[13]%100)/10 + '0');
1826 }
1827 STUFF(addr->pr_s6_addr_S6_un._S6_u8[13]%10 + '0');
1828 STUFF('.');
1829 if (addr->pr_s6_addr_S6_un._S6_u8[14] > 99) {
1830 STUFF(addr->pr_s6_addr_S6_un._S6_u8[14]/100 + '0');
1831 }
1832 if (addr->pr_s6_addr_S6_un._S6_u8[14] > 9) {
1833 STUFF((addr->pr_s6_addr_S6_un._S6_u8[14]%100)/10 + '0');
1834 }
1835 STUFF(addr->pr_s6_addr_S6_un._S6_u8[14]%10 + '0');
1836 STUFF('.');
1837 if (addr->pr_s6_addr_S6_un._S6_u8[15] > 99) {
1838 STUFF(addr->pr_s6_addr_S6_un._S6_u8[15]/100 + '0');
1839 }
1840 if (addr->pr_s6_addr_S6_un._S6_u8[15] > 9) {
1841 STUFF((addr->pr_s6_addr_S6_un._S6_u8[15]%100)/10 + '0');
1842 }
1843 STUFF(addr->pr_s6_addr_S6_un._S6_u8[15]%10 + '0');
1844 STUFF('\0');
1845 return bufcopy;
1846 }
1847 }
1848
1849 while (section < 8) {
1850 if (section == double_colon) {
1851 STUFF(':');
1852 STUFF(':');
1853 section += double_colon_length;
1854 continue;
1855 }
1856 val = ntohs(addr->pr_s6_addr16_S6_un._S6_u16[section]);
1857 if (val > 0xfff) {
1858 STUFF(basis_hex[val >> 12]);
1859 }
1860 if (val > 0xff) {
1861 STUFF(basis_hex[(val >> 8) & 0xf]);
1862 }
1863 if (val > 0xf) {
1864 STUFF(basis_hex[(val >> 4) & 0xf]);
1865 }
1866 STUFF(basis_hex[val & 0xf]);
1867 section++;
1868 if (section < 8 && section != double_colon) {
1869 STUFF(':');
1870 }
1871 }
1872 STUFF('\0');
1873 return bufcopy;
1874#undef STUFF
1875}
1876#endif /* !_PR_HAVE_INET_NTOP */
1877
1878/*
1879 * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr
1880 */
1881PR_IMPLEMENT(void)__attribute__((visibility("default"))) void PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr)
1882{
1883 PRUint8 *dstp;
1884 dstp = v6addr->pr_s6_addr_S6_un._S6_u8;
1885 memset(dstp, 0, 10);
1886 memset(dstp + 10, 0xff, 2);
1887 memcpy(dstp + 12,(char *) &v4addr, 4);
1888}
1889
1890PR_IMPLEMENT(PRUint16)__attribute__((visibility("default"))) PRUint16 PR_ntohs(PRUint16 n) {
1891 return ntohs(n);
1892}
1893PR_IMPLEMENT(PRUint32)__attribute__((visibility("default"))) PRUint32 PR_ntohl(PRUint32 n) {
1894 return ntohl(n);
1895}
1896PR_IMPLEMENT(PRUint16)__attribute__((visibility("default"))) PRUint16 PR_htons(PRUint16 n) {
1897 return htons(n);
1898}
1899PR_IMPLEMENT(PRUint32)__attribute__((visibility("default"))) PRUint32 PR_htonl(PRUint32 n) {
1900 return htonl(n);
1901}
1902PR_IMPLEMENT(PRUint64)__attribute__((visibility("default"))) PRUint64 PR_ntohll(PRUint64 n)
1903{
1904#ifdef IS_BIG_ENDIAN
1905 return n;
1906#else
1907 PRUint32 hi, lo;
1908 lo = (PRUint32)n;
1909 hi = (PRUint32)(n >> 32);
1910 hi = PR_ntohl(hi);
1911 lo = PR_ntohl(lo);
1912 return ((PRUint64)lo << 32) + (PRUint64)hi;
1913#endif
1914} /* ntohll */
1915
1916PR_IMPLEMENT(PRUint64)__attribute__((visibility("default"))) PRUint64 PR_htonll(PRUint64 n)
1917{
1918#ifdef IS_BIG_ENDIAN
1919 return n;
1920#else
1921 PRUint32 hi, lo;
1922 lo = (PRUint32)n;
1923 hi = (PRUint32)(n >> 32);
1924 hi = htonl(hi);
1925 lo = htonl(lo);
1926 return ((PRUint64)lo << 32) + (PRUint64)hi;
1927#endif
1928} /* htonll */
1929
1930
1931/*
1932 * Implementation of PR_GetAddrInfoByName and friends
1933 *
1934 * Compile-time options:
1935 *
1936 * _PR_HAVE_GETADDRINFO Define this macro if the target system provides
1937 * getaddrinfo. With this defined, NSPR will require
1938 * getaddrinfo at run time. If this if not defined,
1939 * then NSPR will attempt to dynamically resolve
1940 * getaddrinfo, falling back to PR_GetHostByName if
1941 * getaddrinfo does not exist on the target system.
1942 *
1943 * Since getaddrinfo is a relatively new system call on many systems,
1944 * we are forced to dynamically resolve it at run time in most cases.
1945 * The exception includes any system (such as Mac OS X) that is known to
1946 * provide getaddrinfo in all versions that NSPR cares to support.
1947 */
1948
1949#if defined(_PR_HAVE_GETADDRINFO)
1950
1951#if defined(_PR_INET6)
1952
1953typedef struct addrinfo PRADDRINFO;
1954#define GETADDRINFOgetaddrinfo getaddrinfo
1955#define FREEADDRINFOfreeaddrinfo freeaddrinfo
1956#define GETNAMEINFOgetnameinfo getnameinfo
1957
1958#elif defined(_PR_INET6_PROBE)
1959
1960typedef struct addrinfo PRADDRINFO;
1961
1962/* getaddrinfo/freeaddrinfo/getnameinfo prototypes */
1963#if defined(WIN32)
1964#define FUNC_MODIFIER __stdcall
1965#else
1966#define FUNC_MODIFIER
1967#endif
1968typedef int (FUNC_MODIFIER * FN_GETADDRINFO)
1969(const char *nodename,
1970 const char *servname,
1971 const PRADDRINFO *hints,
1972 PRADDRINFO **res);
1973typedef int (FUNC_MODIFIER * FN_FREEADDRINFO)
1974(PRADDRINFO *ai);
1975typedef int (FUNC_MODIFIER * FN_GETNAMEINFO)
1976(const struct sockaddr *addr, int addrlen,
1977 char *host, int hostlen,
1978 char *serv, int servlen, int flags);
1979
1980/* global state */
1981static FN_GETADDRINFO _pr_getaddrinfo = NULL((void*)0);
1982static FN_FREEADDRINFO _pr_freeaddrinfo = NULL((void*)0);
1983static FN_GETNAMEINFO _pr_getnameinfo = NULL((void*)0);
1984
1985#define GETADDRINFO_SYMBOL "getaddrinfo"
1986#define FREEADDRINFO_SYMBOL "freeaddrinfo"
1987#define GETNAMEINFO_SYMBOL "getnameinfo"
1988
1989PRStatus
1990_pr_find_getaddrinfo(void)
1991{
1992 PRLibrary *lib;
1993#ifdef WIN32
1994 /*
1995 * On windows, we need to search ws2_32.dll or wship6.dll
1996 * (Microsoft IPv6 Technology Preview for Windows 2000) for
1997 * getaddrinfo and freeaddrinfo. These libraries might not
1998 * be loaded yet.
1999 */
2000 const char *libname[] = { "ws2_32.dll", "wship6.dll" };
2001 int i;
2002
2003 for (i = 0; i < sizeof(libname)/sizeof(libname[0]); i++) {
2004 lib = PR_LoadLibrary(libname[i]);
2005 if (!lib) {
2006 continue;
2007 }
2008 _pr_getaddrinfo = (FN_GETADDRINFO)
2009 PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL);
2010 if (!_pr_getaddrinfo) {
2011 PR_UnloadLibrary(lib);
2012 continue;
2013 }
2014 _pr_freeaddrinfo = (FN_FREEADDRINFO)
2015 PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
2016 _pr_getnameinfo = (FN_GETNAMEINFO)
2017 PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL);
2018 if (!_pr_freeaddrinfo || !_pr_getnameinfo) {
2019 PR_UnloadLibrary(lib);
2020 continue;
2021 }
2022 /* Keep the library loaded. */
2023 return PR_SUCCESS;
2024 }
2025 return PR_FAILURE;
2026#else
2027 /*
2028 * Resolve getaddrinfo by searching all loaded libraries. Then
2029 * search library containing getaddrinfo for freeaddrinfo.
2030 */
2031 _pr_getaddrinfo = (FN_GETADDRINFO)
2032 PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib);
2033 if (!_pr_getaddrinfo) {
2034 return PR_FAILURE;
2035 }
2036 _pr_freeaddrinfo = (FN_FREEADDRINFO)
2037 PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL);
2038 _pr_getnameinfo = (FN_GETNAMEINFO)
2039 PR_FindFunctionSymbol(lib, GETNAMEINFO_SYMBOL);
2040 PR_UnloadLibrary(lib);
2041 if (!_pr_freeaddrinfo || !_pr_getnameinfo) {
2042 return PR_FAILURE;
2043 }
2044 return PR_SUCCESS;
2045#endif
2046}
2047
2048#define GETADDRINFOgetaddrinfo (*_pr_getaddrinfo)
2049#define FREEADDRINFOfreeaddrinfo (*_pr_freeaddrinfo)
2050#define GETNAMEINFOgetnameinfo (*_pr_getnameinfo)
2051
2052#endif /* _PR_INET6 */
2053
2054#endif /* _PR_HAVE_GETADDRINFO */
2055
2056#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE)
2057/*
2058 * If getaddrinfo does not exist, then we will fall back on
2059 * PR_GetHostByName, which requires that we allocate a buffer for the
2060 * PRHostEnt data structure and its members.
2061 */
2062typedef struct PRAddrInfoFB {
2063 char buf[PR_NETDB_BUF_SIZE2048];
2064 PRHostEnt hostent;
2065 PRBool has_cname;
2066} PRAddrInfoFB;
2067
2068static PRAddrInfo *
2069pr_GetAddrInfoByNameFB(const char *hostname,
2070 PRUint16 af,
2071 PRIntn flags)
2072{
2073 PRStatus rv;
2074 PRAddrInfoFB *ai;
2075 /* fallback on PR_GetHostByName */
2076 ai = PR_NEW(PRAddrInfoFB)((PRAddrInfoFB *) (PR_Malloc((sizeof(PRAddrInfoFB)))));
2077 if (!ai) {
2078 PR_SetError(PR_OUT_OF_MEMORY_ERROR(-6000L), 0);
2079 return NULL((void*)0);
2080 }
2081 rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent);
2082 if (rv == PR_FAILURE) {
2083 PR_Free(ai);
2084 return NULL((void*)0);
2085 }
2086 ai->has_cname = !(flags & PR_AI_NOCANONNAME0x8000);
2087
2088 return (PRAddrInfo *) ai;
2089}
2090#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */
2091
2092PR_IMPLEMENT(PRAddrInfo *)__attribute__((visibility("default"))) PRAddrInfo * PR_GetAddrInfoByName(const char *hostname,
2093 PRUint16 af,
2094 PRIntn flags)
2095{
2096 /* restrict input to supported values */
2097 if ((af != PR_AF_INET2 && af != PR_AF_UNSPEC0) ||
2098 (flags & ~ PR_AI_NOCANONNAME0x8000) != PR_AI_ADDRCONFIG0x20) {
2099 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
2100 return NULL((void*)0);
2101 }
2102
2103 if (!_pr_initialized) {
2104 _PR_ImplicitInitialization();
2105 }
2106
2107#if !defined(_PR_HAVE_GETADDRINFO)
2108 return pr_GetAddrInfoByNameFB(hostname, af, flags);
2109#else
2110#if defined(_PR_INET6_PROBE)
2111 if (!_pr_ipv6_is_present()) {
2112 return pr_GetAddrInfoByNameFB(hostname, af, flags);
2113 }
2114#endif
2115 {
2116 PRADDRINFO *res, hints;
2117 int rv;
2118
2119 /*
2120 * we assume a RFC 2553 compliant getaddrinfo. this may at some
2121 * point need to be customized as platforms begin to adopt the
2122 * RFC 3493.
2123 */
2124
2125 memset(&hints, 0, sizeof(hints));
2126 if (!(flags & PR_AI_NOCANONNAME0x8000)) {
2127 hints.ai_flags |= AI_CANONNAME0x0002;
2128 }
2129#ifdef AI_ADDRCONFIG0x0020
2130 /*
2131 * Propagate AI_ADDRCONFIG to the GETADDRINFO call if PR_AI_ADDRCONFIG
2132 * is set.
2133 *
2134 * Need a workaround for loopback host addresses:
2135 * The problem is that in glibc and Windows, AI_ADDRCONFIG applies the
2136 * existence of an outgoing network interface to IP addresses of the
2137 * loopback interface, due to a strict interpretation of the
2138 * specification. For example, if a computer does not have any
2139 * outgoing IPv6 network interface, but its loopback network interface
2140 * supports IPv6, a getaddrinfo call on "localhost" with AI_ADDRCONFIG
2141 * won't return the IPv6 loopback address "::1", because getaddrinfo
2142 * thinks the computer cannot connect to any IPv6 destination,
2143 * ignoring the remote vs. local/loopback distinction.
2144 */
2145 if ((flags & PR_AI_ADDRCONFIG0x20) &&
2146 strcmp(hostname, "localhost") != 0 &&
2147 strcmp(hostname, "localhost.localdomain") != 0 &&
2148 strcmp(hostname, "localhost6") != 0 &&
2149 strcmp(hostname, "localhost6.localdomain6") != 0) {
2150 hints.ai_flags |= AI_ADDRCONFIG0x0020;
2151 }
2152#endif
2153 hints.ai_family = (af == PR_AF_INET2) ? AF_INET2 : AF_UNSPEC0;
2154
2155 /*
2156 * it is important to select a socket type in the hints, otherwise we
2157 * will get back repetitive entries: one for each socket type. since
2158 * we do not expose ai_socktype through our API, it is okay to do this
2159 * here. the application may still choose to create a socket of some
2160 * other type.
2161 */
2162 hints.ai_socktype = SOCK_STREAMSOCK_STREAM;
2163
2164 rv = GETADDRINFOgetaddrinfo(hostname, NULL((void*)0), &hints, &res);
2165#ifdef AI_ADDRCONFIG0x0020
2166 if (rv == EAI_BADFLAGS-1 && (hints.ai_flags & AI_ADDRCONFIG0x0020)) {
2167 hints.ai_flags &= ~AI_ADDRCONFIG0x0020;
2168 rv = GETADDRINFOgetaddrinfo(hostname, NULL((void*)0), &hints, &res);
2169 }
2170#endif
2171 if (rv == 0) {
2172 return (PRAddrInfo *) res;
2173 }
2174
2175 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), rv);
2176 }
2177 return NULL((void*)0);
2178#endif
2179}
2180
2181PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus
2182PR_GetPrefLoopbackAddrInfo(PRNetAddr *result,
2183 PRUint16 port)
2184{
2185 char tmpBuf[ 40 ];
2186 const int tmpBufSize = sizeof( tmpBuf );
2187
2188 if (!result) {
1
Assuming 'result' is non-null
2
Taking false branch
2189 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
2190 return PR_FAILURE;
2191 }
2192
2193 if (!_pr_initialized) _PR_ImplicitInitialization();
3
Assuming '_pr_initialized' is not equal to 0
4
Taking false branch
2194
2195 PR_snprintf(tmpBuf, tmpBufSize, "%u", port );
2196
2197#if !defined(_PR_HAVE_GETADDRINFO) || !defined(AI_PASSIVE0x0001)
2198 PR_SetError(PR_NOT_IMPLEMENTED_ERROR(-5992L), 0);
2199 return PR_FAILURE;
2200#else
2201
2202 PRADDRINFO *res, hints;
2203 PRStatus rv;
2204
2205 memset(&hints, 0, sizeof(hints));
2206
2207 rv = GETADDRINFOgetaddrinfo(NULL((void*)0), tmpBuf, &hints, &res);
5
Value assigned to 'res'
2208 if (rv == 0) {
6
Assuming 'rv' is equal to 0
7
Taking true branch
2209 PRBool result_still_empty = PR_TRUE1;
2210 PRADDRINFO *ai = res;
8
'ai' initialized to the value of 'res'
2211 do {
2212 PRNetAddr aNetAddr;
2213
2214 while (ai && ai->ai_addrlen > sizeof(PRNetAddr))
9
Assuming 'ai' is null
2215 ai = ai->ai_next;
2216
2217 if (ai
9.1
'ai' is null
) {
2218 /* copy sockaddr to PRNetAddr */
2219 memcpy(&aNetAddr, ai->ai_addr, ai->ai_addrlen);
2220 aNetAddr.raw.family = ai->ai_addr->sa_family;
2221#ifdef _PR_INET6
2222 if (AF_INET610 == aNetAddr.raw.family)
2223 aNetAddr.raw.family = PR_AF_INET610;
2224#endif
2225 if (ai->ai_addrlen < sizeof(PRNetAddr))
2226 memset(((char*)result)+ai->ai_addrlen, 0,
2227 sizeof(PRNetAddr) - ai->ai_addrlen);
2228 }
2229
2230 /* If we obtain more than one result, prefer IPv6. */
2231 if (result_still_empty
9.2
'result_still_empty' is 1
|| aNetAddr.raw.family == PR_AF_INET610) {
2232 memcpy(result, &aNetAddr, sizeof(PRNetAddr));
2233 }
2234 result_still_empty = PR_FALSE0;
2235 ai = ai->ai_next;
10
Access to field 'ai_next' results in a dereference of a null pointer (loaded from variable 'ai')
2236 }
2237 while (ai);
2238
2239 FREEADDRINFOfreeaddrinfo(res);
2240 return PR_SUCCESS;
2241 }
2242
2243 PR_SetError(PR_DIRECTORY_LOOKUP_ERROR(-5973L), rv);
2244 return PR_FAILURE;
2245#endif
2246}
2247
2248PR_IMPLEMENT(void)__attribute__((visibility("default"))) void PR_FreeAddrInfo(PRAddrInfo *ai)
2249{
2250#if defined(_PR_HAVE_GETADDRINFO)
2251#if defined(_PR_INET6_PROBE)
2252 if (!_pr_ipv6_is_present()) {
2253 PR_Free((PRAddrInfoFB *) ai);
2254 }
2255 else
2256#endif
2257 FREEADDRINFOfreeaddrinfo((PRADDRINFO *) ai);
2258#else
2259 PR_Free((PRAddrInfoFB *) ai);
2260#endif
2261}
2262
2263PR_IMPLEMENT(void *)__attribute__((visibility("default"))) void * PR_EnumerateAddrInfo(void *iterPtr,
2264 const PRAddrInfo *base,
2265 PRUint16 port,
2266 PRNetAddr *result)
2267{
2268#if defined(_PR_HAVE_GETADDRINFO)
2269 PRADDRINFO *ai;
2270#if defined(_PR_INET6_PROBE)
2271 if (!_pr_ipv6_is_present()) {
2272 /* using PRAddrInfoFB */
2273 PRIntn iter = (PRIntn)(PRPtrdiff) iterPtr;
2274 iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
2275 if (iter < 0) {
2276 iter = 0;
2277 }
2278 return (void *)(PRPtrdiff) iter;
2279 }
2280#endif
2281
2282 if (iterPtr) {
2283 ai = ((PRADDRINFO *) iterPtr)->ai_next;
2284 }
2285 else {
2286 ai = (PRADDRINFO *) base;
2287 }
2288
2289 while (ai && ai->ai_addrlen > sizeof(PRNetAddr)) {
2290 ai = ai->ai_next;
2291 }
2292
2293 if (ai) {
2294 /* copy sockaddr to PRNetAddr */
2295 memcpy(result, ai->ai_addr, ai->ai_addrlen);
2296 result->raw.family = ai->ai_addr->sa_family;
2297#ifdef _PR_INET6
2298 if (AF_INET610 == result->raw.family) {
2299 result->raw.family = PR_AF_INET610;
2300 }
2301#endif
2302 if (ai->ai_addrlen < sizeof(PRNetAddr)) {
2303 memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen);
2304 }
2305
2306 if (result->raw.family == PR_AF_INET2) {
2307 result->inet.port = htons(port);
2308 }
2309 else {
2310 result->ipv6.port = htons(port);
2311 }
2312 }
2313
2314 return ai;
2315#else
2316 /* using PRAddrInfoFB */
2317 PRIntn iter = (PRIntn) iterPtr;
2318 iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result);
2319 if (iter < 0) {
2320 iter = 0;
2321 }
2322 return (void *) iter;
2323#endif
2324}
2325
2326PR_IMPLEMENT(const char *)__attribute__((visibility("default"))) const char * PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai)
2327{
2328#if defined(_PR_HAVE_GETADDRINFO)
2329#if defined(_PR_INET6_PROBE)
2330 if (!_pr_ipv6_is_present()) {
2331 const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
2332 return fb->has_cname ? fb->hostent.h_name : NULL((void*)0);
2333 }
2334#endif
2335 return ((const PRADDRINFO *) ai)->ai_canonname;
2336#else
2337 const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai;
2338 return fb->has_cname ? fb->hostent.h_name : NULL((void*)0);
2339#endif
2340}
2341
2342#if defined(_PR_HAVE_GETADDRINFO)
2343static PRStatus pr_StringToNetAddrGAI(const char *string, PRNetAddr *addr)
2344{
2345 PRADDRINFO *res, hints;
2346 int rv; /* 0 for success, or the error code EAI_xxx */
2347 PRNetAddr laddr;
2348 PRStatus status = PR_SUCCESS;
2349
2350 memset(&hints, 0, sizeof(hints));
2351 hints.ai_flags = AI_NUMERICHOST0x0004;
2352 hints.ai_family = AF_UNSPEC0;
2353 hints.ai_socktype = SOCK_STREAMSOCK_STREAM;
2354
2355 rv = GETADDRINFOgetaddrinfo(string, NULL((void*)0), &hints, &res);
2356 if (rv != 0)
2357 {
2358 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), rv);
2359 return PR_FAILURE;
2360 }
2361
2362 /* pick up the first addr */
2363 memcpy(&laddr, res->ai_addr, res->ai_addrlen);
2364 if (AF_INET610 == res->ai_addr->sa_family)
2365 {
2366 addr->ipv6.family = PR_AF_INET610;
2367 addr->ipv6.ip = laddr.ipv6.ip;
2368 addr->ipv6.scope_id = laddr.ipv6.scope_id;
2369 }
2370 else if (AF_INET2 == res->ai_addr->sa_family)
2371 {
2372 addr->inet.family = PR_AF_INET2;
2373 addr->inet.ip = laddr.inet.ip;
2374 }
2375 else
2376 {
2377 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
2378 status = PR_FAILURE;
2379 }
2380
2381 FREEADDRINFOfreeaddrinfo(res);
2382 return status;
2383}
2384#endif /* _PR_HAVE_GETADDRINFO */
2385
2386static PRStatus pr_StringToNetAddrFB(const char *string, PRNetAddr *addr)
2387{
2388 PRIntn rv;
2389
2390 rv = pr_inet_aton(string, &addr->inet.ip);
2391 if (1 == rv)
2392 {
2393 addr->raw.family = AF_INET2;
2394 return PR_SUCCESS;
2395 }
2396
2397 PR_ASSERT(0 == rv)((0 == rv)?((void)0):PR_Assert("0 == rv","../../../../pr/src/misc/prnetdb.c"
,2397))
;
2398 /* clean up after the failed call */
2399 memset(&addr->inet.ip, 0, sizeof(addr->inet.ip));
2400
2401 rv = StringToV6Addr(string, &addr->ipv6.ip);
2402 if (1 == rv)
2403 {
2404 addr->raw.family = PR_AF_INET610;
2405 return PR_SUCCESS;
2406 }
2407
2408 PR_ASSERT(0 == rv)((0 == rv)?((void)0):PR_Assert("0 == rv","../../../../pr/src/misc/prnetdb.c"
,2408))
;
2409 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
2410 return PR_FAILURE;
2411}
2412
2413PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_StringToNetAddr(const char *string, PRNetAddr *addr)
2414{
2415 if (!_pr_initialized) {
2416 _PR_ImplicitInitialization();
2417 }
2418
2419 if (!addr || !string || !*string)
2420 {
2421 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
2422 return PR_FAILURE;
2423 }
2424
2425#if !defined(_PR_HAVE_GETADDRINFO)
2426 return pr_StringToNetAddrFB(string, addr);
2427#else
2428 /*
2429 * getaddrinfo with AI_NUMERICHOST is much slower than pr_inet_aton on some
2430 * platforms, such as Mac OS X (bug 404399), Linux glibc 2.10 (bug 344809),
2431 * and most likely others. So we only use it to convert literal IP addresses
2432 * that contain IPv6 scope IDs, which pr_inet_aton cannot convert.
2433 */
2434 if (!strchr(string, '%')) {
2435 return pr_StringToNetAddrFB(string, addr);
2436 }
2437
2438#if defined(_PR_INET6_PROBE)
2439 if (!_pr_ipv6_is_present()) {
2440 return pr_StringToNetAddrFB(string, addr);
2441 }
2442#endif
2443
2444 return pr_StringToNetAddrGAI(string, addr);
2445#endif
2446}
2447
2448#if defined(_PR_HAVE_GETADDRINFO)
2449static PRStatus pr_NetAddrToStringGNI(
2450 const PRNetAddr *addr, char *string, PRUint32 size)
2451{
2452 int addrlen;
2453 const PRNetAddr *addrp = addr;
2454#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
2455 PRUint16 md_af = addr->raw.family;
2456 PRNetAddr addrcopy;
2457#endif
2458 int rv; /* 0 for success, or the error code EAI_xxx */
2459
2460#ifdef _PR_INET6
2461 if (addr->raw.family == PR_AF_INET610)
2462 {
2463 md_af = AF_INET610;
2464#ifndef _PR_HAVE_SOCKADDR_LEN
2465 addrcopy = *addr;
2466 addrcopy.raw.family = md_af;
2467 addrp = &addrcopy;
2468#endif
2469 }
2470#endif
2471
2472 addrlen = PR_NETADDR_SIZE(addr)_PR_NetAddrSize(addr);
2473#ifdef _PR_HAVE_SOCKADDR_LEN
2474 addrcopy = *addr;
2475 ((struct sockaddr*)&addrcopy)->sa_len = addrlen;
2476 ((struct sockaddr*)&addrcopy)->sa_family = md_af;
2477 addrp = &addrcopy;
2478#endif
2479 rv = GETNAMEINFOgetnameinfo((const struct sockaddr *)addrp, addrlen,
2480 string, size, NULL((void*)0), 0, NI_NUMERICHOST1);
2481 if (rv != 0)
2482 {
2483 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), rv);
2484 return PR_FAILURE;
2485 }
2486 return PR_SUCCESS;
2487}
2488#endif /* _PR_HAVE_GETADDRINFO */
2489
2490#if !defined(_PR_HAVE_GETADDRINFO) || defined(_PR_INET6_PROBE)
2491static PRStatus pr_NetAddrToStringFB(
2492 const PRNetAddr *addr, char *string, PRUint32 size)
2493{
2494 if (PR_AF_INET610 == addr->raw.family)
2495 {
2496#if defined(_PR_HAVE_INET_NTOP)
2497 if (NULL((void*)0) == inet_ntop(AF_INET610, &addr->ipv6.ip, string, size))
2498#else
2499 if (NULL((void*)0) == V6AddrToString(&addr->ipv6.ip, string, size))
2500#endif
2501 {
2502 /* the size of the result buffer is inadequate */
2503 PR_SetError(PR_BUFFER_OVERFLOW_ERROR(-5962L), 0);
2504 return PR_FAILURE;
2505 }
2506 }
2507 else
2508 {
2509 if (size < 16) {
2510 goto failed;
2511 }
2512 if (AF_INET2 != addr->raw.family) {
2513 goto failed;
2514 }
2515 else
2516 {
2517 unsigned char *byte = (unsigned char*)&addr->inet.ip;
2518 PR_snprintf(string, size, "%u.%u.%u.%u",
2519 byte[0], byte[1], byte[2], byte[3]);
2520 }
2521 }
2522
2523 return PR_SUCCESS;
2524
2525failed:
2526 PR_SetError(PR_INVALID_ARGUMENT_ERROR(-5987L), 0);
2527 return PR_FAILURE;
2528
2529} /* pr_NetAddrToStringFB */
2530#endif /* !_PR_HAVE_GETADDRINFO || _PR_INET6_PROBE */
2531
2532PR_IMPLEMENT(PRStatus)__attribute__((visibility("default"))) PRStatus PR_NetAddrToString(
2533 const PRNetAddr *addr, char *string, PRUint32 size)
2534{
2535 if (!_pr_initialized) {
2536 _PR_ImplicitInitialization();
2537 }
2538
2539#if !defined(_PR_HAVE_GETADDRINFO)
2540 return pr_NetAddrToStringFB(addr, string, size);
2541#else
2542#if defined(_PR_INET6_PROBE)
2543 if (!_pr_ipv6_is_present()) {
2544 return pr_NetAddrToStringFB(addr, string, size);
2545 }
2546#endif
2547 return pr_NetAddrToStringGNI(addr, string, size);
2548#endif
2549} /* PR_NetAddrToString */