Coverage Report

Created: 2025-07-01 06:25

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