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