Coverage Report

Created: 2026-04-04 06:13

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