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