Coverage Report

Created: 2018-09-25 14:53

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