OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [newlib-1.18.0/] [newlib-1.18.0-or32-1.0rc2/] [newlib/] [libc/] [sys/] [linux/] [net/] [getaddrinfo.c] - Blame information for rev 520

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* The Inner Net License, Version 2.00
2
 
3
  The author(s) grant permission for redistribution and use in source and
4
binary forms, with or without modification, of the software and documentation
5
provided that the following conditions are met:
6
 
7
0. If you receive a version of the software that is specifically labelled
8
   as not being for redistribution (check the version message and/or README),
9
   you are not permitted to redistribute that version of the software in any
10
   way or form.
11
1. All terms of the all other applicable copyrights and licenses must be
12
   followed.
13
2. Redistributions of source code must retain the authors' copyright
14
   notice(s), this list of conditions, and the following disclaimer.
15
3. Redistributions in binary form must reproduce the authors' copyright
16
   notice(s), this list of conditions, and the following disclaimer in the
17
   documentation and/or other materials provided with the distribution.
18
4. [The copyright holder has authorized the removal of this clause.]
19
5. Neither the name(s) of the author(s) nor the names of its contributors
20
   may be used to endorse or promote products derived from this software
21
   without specific prior written permission.
22
 
23
THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
 
34
  If these license terms cause you a real problem, contact the author.  */
35
 
36
/* This software is Copyright 1996 by Craig Metz, All Rights Reserved.  */
37
 
38
#include <alloca.h>
39
#include <sys/types.h>
40
#include <assert.h>
41
#include <errno.h>
42
#include <ifaddrs.h>
43
#include <netdb.h>
44
#include <resolv.h>
45
#include <stdbool.h>
46
#include <stdio.h>
47
#include <stdlib.h>
48
#include <string.h>
49
#include <unistd.h>
50
#include <arpa/inet.h>
51
#include <sys/socket.h>
52
#include <netinet/in.h>
53
#include <sys/un.h>
54
#include <sys/utsname.h>
55
#include <net/if.h>
56
#include <nsswitch.h>
57
#include <not-cancel.h>
58
#include <nscd/nscd-client.h>
59
#include <nscd/nscd_proto.h>
60
#include <limits.h>
61
#include "local.h"
62
 
63
#ifdef HAVE_LIBIDN
64
extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
65
extern int __idna_to_unicode_lzlz (const char *input, char **output,
66
                                   int flags);
67
# include <libidn/idna.h>
68
#endif
69
 
70
#define GAIH_OKIFUNSPEC 0x0100
71
#define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
72
 
73
#ifndef UNIX_PATH_MAX
74
#define UNIX_PATH_MAX  108
75
#endif
76
 
77
struct gaih_service
78
  {
79
    const char *name;
80
    int num;
81
  };
82
 
83
struct gaih_servtuple
84
  {
85
    struct gaih_servtuple *next;
86
    int socktype;
87
    int protocol;
88
    int port;
89
  };
90
 
91
static const struct gaih_servtuple nullserv;
92
 
93
struct gaih_addrtuple
94
  {
95
    struct gaih_addrtuple *next;
96
    char *name;
97
    int family;
98
    uint32_t addr[4];
99
    uint32_t scopeid;
100
  };
101
 
102
struct gaih_typeproto
103
  {
104
    int socktype;
105
    int protocol;
106
    char name[4];
107
    int protoflag;
108
  };
109
 
110
/* Values for `protoflag'.  */
111
#define GAI_PROTO_NOSERVICE     1
112
#define GAI_PROTO_PROTOANY      2
113
 
114
static const struct gaih_typeproto gaih_inet_typeproto[] =
115
{
116
  { 0, 0, "", 0 },
117
  { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
118
  { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
119
  { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
120
  { 0, 0, "", 0 }
121
};
122
 
123
struct gaih
124
  {
125
    int family;
126
    int (*gaih)(const char *name, const struct gaih_service *service,
127
                const struct addrinfo *req, struct addrinfo **pai);
128
  };
129
 
130
static const struct addrinfo default_hints =
131
  {
132
    .ai_flags = AI_DEFAULT,
133
    .ai_family = PF_UNSPEC,
134
    .ai_socktype = 0,
135
    .ai_protocol = 0,
136
    .ai_addrlen = 0,
137
    .ai_addr = NULL,
138
    .ai_canonname = NULL,
139
    .ai_next = NULL
140
  };
141
 
142
#define s6_addr32 __u6_addr.__u6_addr32
143
 
144
#if 0
145
/* Using Unix sockets this way is a security risk.  */
146
static int
147
gaih_local (const char *name, const struct gaih_service *service,
148
            const struct addrinfo *req, struct addrinfo **pai)
149
{
150
  struct utsname utsname;
151
 
152
  if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
153
    return GAIH_OKIFUNSPEC | -EAI_NONAME;
154
 
155
  if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
156
    if (uname (&utsname) < 0)
157
      return -EAI_SYSTEM;
158
 
159
  if (name != NULL)
160
    {
161
      if (strcmp(name, "localhost") &&
162
          strcmp(name, "local") &&
163
          strcmp(name, "unix") &&
164
          strcmp(name, utsname.nodename))
165
        return GAIH_OKIFUNSPEC | -EAI_NONAME;
166
    }
167
 
168
  if (req->ai_protocol || req->ai_socktype)
169
    {
170
      const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
171
 
172
      while (tp->name[0]
173
             && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
174
                 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
175
                 || (req->ai_protocol != 0
176
                     && !(tp->protoflag & GAI_PROTO_PROTOANY)
177
                     && req->ai_protocol != tp->protocol)))
178
        ++tp;
179
 
180
      if (! tp->name[0])
181
        {
182
          if (req->ai_socktype)
183
            return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
184
          else
185
            return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
186
        }
187
    }
188
 
189
  *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
190
                 + ((req->ai_flags & AI_CANONNAME)
191
                    ? (strlen(utsname.nodename) + 1): 0));
192
  if (*pai == NULL)
193
    return -EAI_MEMORY;
194
 
195
  (*pai)->ai_next = NULL;
196
  (*pai)->ai_flags = req->ai_flags;
197
  (*pai)->ai_family = AF_LOCAL;
198
  (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
199
  (*pai)->ai_protocol = req->ai_protocol;
200
  (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
201
  (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
202
 
203
#if SALEN
204
  ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
205
    sizeof (struct sockaddr_un);
206
#endif /* SALEN */
207
 
208
  ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
209
  memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
210
 
211
  if (service)
212
    {
213
      struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
214
 
215
      if (strchr (service->name, '/') != NULL)
216
        {
217
          if (strlen (service->name) >= sizeof (sunp->sun_path))
218
            return GAIH_OKIFUNSPEC | -EAI_SERVICE;
219
 
220
          strcpy (sunp->sun_path, service->name);
221
        }
222
      else
223
        {
224
          if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
225
              sizeof (sunp->sun_path))
226
            return GAIH_OKIFUNSPEC | -EAI_SERVICE;
227
 
228
          __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
229
        }
230
    }
231
  else
232
    {
233
      /* This is a dangerous use of the interface since there is a time
234
         window between the test for the file and the actual creation
235
         (done by the caller) in which a file with the same name could
236
         be created.  */
237
      char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
238
 
239
      if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
240
                            0) != 0
241
          || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
242
        return -EAI_SYSTEM;
243
    }
244
 
245
  if (req->ai_flags & AI_CANONNAME)
246
    (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
247
                                   + sizeof (struct sockaddr_un),
248
                                   utsname.nodename);
249
  else
250
    (*pai)->ai_canonname = NULL;
251
  return 0;
252
}
253
#endif  /* 0 */
254
 
255
static int
256
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
257
               const struct addrinfo *req, struct gaih_servtuple *st)
258
{
259
  struct servent *s;
260
  size_t tmpbuflen = 1024;
261
  struct servent ts;
262
  char *tmpbuf;
263
  int r;
264
 
265
  do
266
    {
267
      tmpbuf = alloca (tmpbuflen);
268
 
269
      r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
270
                             &s);
271
      if (r != 0 || s == NULL)
272
        {
273
          if (r == ERANGE)
274
            tmpbuflen *= 2;
275
          else
276
            return GAIH_OKIFUNSPEC | -EAI_SERVICE;
277
        }
278
    }
279
  while (r);
280
 
281
  st->next = NULL;
282
  st->socktype = tp->socktype;
283
  st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
284
                  ? req->ai_protocol : tp->protocol);
285
  st->port = s->s_port;
286
 
287
  return 0;
288
}
289
 
290
#define gethosts(_family, _type) \
291
 {                                                                            \
292
  int i;                                                                      \
293
  int herrno;                                                                 \
294
  struct hostent th;                                                          \
295
  struct hostent *h;                                                          \
296
  char *localcanon = NULL;                                                    \
297
  no_data = 0;                                                                 \
298
  while (1) {                                                                 \
299
    rc = 0;                                                                    \
300
    status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, tmpbuflen,        \
301
                                &rc, &herrno, NULL, &localcanon));            \
302
    if (rc != ERANGE || herrno != NETDB_INTERNAL)                             \
303
      break;                                                                  \
304
    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);                \
305
  }                                                                           \
306
  if (status == NSS_STATUS_SUCCESS && rc == 0)                                 \
307
    h = &th;                                                                  \
308
  else                                                                        \
309
    h = NULL;                                                                 \
310
  if (rc != 0)                                                                 \
311
    {                                                                         \
312
      if (herrno == NETDB_INTERNAL)                                           \
313
        {                                                                     \
314
          h_errno = (herrno);                                         \
315
          return -EAI_SYSTEM;                                                 \
316
        }                                                                     \
317
      if (herrno == TRY_AGAIN)                                                \
318
        no_data = EAI_AGAIN;                                                  \
319
      else                                                                    \
320
        no_data = herrno == NO_DATA;                                          \
321
    }                                                                         \
322
  else if (h != NULL)                                                         \
323
    {                                                                         \
324
      for (i = 0; h->h_addr_list[i]; i++)                                      \
325
        {                                                                     \
326
          if (*pat == NULL)                                                   \
327
            {                                                                 \
328
              *pat = alloca (sizeof (struct gaih_addrtuple));                 \
329
              (*pat)->scopeid = 0;                                             \
330
            }                                                                 \
331
          uint32_t *addr = (*pat)->addr;                                      \
332
          (*pat)->next = NULL;                                                \
333
          if (i == 0)                                                          \
334
            {                                                                 \
335
              (*pat)->name = alloca (strlen (h->h_name) + 1);                 \
336
              strcpy ((*pat)->name, h->h_name);                               \
337
            }                                                                 \
338
          else                                                                \
339
              (*pat)->name = NULL;                                            \
340
          if (_family == AF_INET && req->ai_family == AF_INET6)               \
341
            {                                                                 \
342
              (*pat)->family = AF_INET6;                                      \
343
              addr[3] = *(uint32_t *) h->h_addr_list[i];                      \
344
              addr[2] = htonl (0xffff);                                       \
345
              addr[1] = 0;                                                     \
346
              addr[0] = 0;                                                      \
347
            }                                                                 \
348
          else                                                                \
349
            {                                                                 \
350
              (*pat)->family = _family;                                       \
351
              memcpy (addr, h->h_addr_list[i], sizeof(_type));                \
352
            }                                                                 \
353
          pat = &((*pat)->next);                                              \
354
        }                                                                     \
355
                                                                              \
356
      if (localcanon != NULL && canon == NULL)                                \
357
        {                                                                     \
358
          canon = alloca (strlen (localcanon) + 1);                           \
359
          strcpy (canon, localcanon);                                         \
360
        }                                                                     \
361
                                                                              \
362
      if (_family == AF_INET6 && i > 0)                                        \
363
        got_ipv6 = true;                                                      \
364
    }                                                                         \
365
 }
366
 
367
 
368
typedef enum nss_status (*nss_gethostbyname3_r)
369
  (const char *name, int af, struct hostent *host,
370
   char *buffer, size_t buflen, int *errnop,
371
   int *h_errnop, int32_t *ttlp, char **canonp);
372
typedef enum nss_status (*nss_getcanonname_r)
373
  (const char *name, char *buffer, size_t buflen, char **result,
374
   int *errnop, int *h_errnop);
375
extern service_user *__nss_hosts_database attribute_hidden;
376
 
377
static int
378
gaih_inet (const char *name, const struct gaih_service *service,
379
           const struct addrinfo *req, struct addrinfo **pai)
380
{
381
  const struct gaih_typeproto *tp = gaih_inet_typeproto;
382
  struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
383
  struct gaih_addrtuple *at = NULL;
384
  int rc;
385
  bool got_ipv6 = false;
386
  const char *canon = NULL;
387
  const char *orig_name = name;
388
 
389
  if (req->ai_protocol || req->ai_socktype)
390
    {
391
      ++tp;
392
 
393
      while (tp->name[0]
394
             && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
395
                 || (req->ai_protocol != 0
396
                     && !(tp->protoflag & GAI_PROTO_PROTOANY)
397
                     && req->ai_protocol != tp->protocol)))
398
        ++tp;
399
 
400
      if (! tp->name[0])
401
        {
402
          if (req->ai_socktype)
403
            return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
404
          else
405
            return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
406
        }
407
    }
408
 
409
  if (service != NULL)
410
    {
411
      if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
412
        return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
413
 
414
      if (service->num < 0)
415
        {
416
          if (tp->name[0])
417
            {
418
              st = (struct gaih_servtuple *)
419
                alloca (sizeof (struct gaih_servtuple));
420
 
421
              if ((rc = gaih_inet_serv (service->name, tp, req, st)))
422
                return rc;
423
            }
424
          else
425
            {
426
              struct gaih_servtuple **pst = &st;
427
              for (tp++; tp->name[0]; tp++)
428
                {
429
                  struct gaih_servtuple *newp;
430
 
431
                  if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
432
                    continue;
433
 
434
                  if (req->ai_socktype != 0
435
                      && req->ai_socktype != tp->socktype)
436
                    continue;
437
                  if (req->ai_protocol != 0
438
                      && !(tp->protoflag & GAI_PROTO_PROTOANY)
439
                      && req->ai_protocol != tp->protocol)
440
                    continue;
441
 
442
                  newp = (struct gaih_servtuple *)
443
                    alloca (sizeof (struct gaih_servtuple));
444
 
445
                  if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
446
                    {
447
                      if (rc & GAIH_OKIFUNSPEC)
448
                        continue;
449
                      return rc;
450
                    }
451
 
452
                  *pst = newp;
453
                  pst = &(newp->next);
454
                }
455
              if (st == (struct gaih_servtuple *) &nullserv)
456
                return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
457
            }
458
        }
459
      else
460
        {
461
          if (req->ai_socktype || req->ai_protocol)
462
            {
463
              st = alloca (sizeof (struct gaih_servtuple));
464
              st->next = NULL;
465
              st->socktype = tp->socktype;
466
              st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
467
                              ? req->ai_protocol : tp->protocol);
468
              st->port = htons (service->num);
469
            }
470
          else
471
            {
472
              /* Neither socket type nor protocol is set.  Return all
473
                 socket types we know about.  */
474
              struct gaih_servtuple **lastp = &st;
475
              for (tp = gaih_inet_typeproto + 1; tp->name[0]; ++tp)
476
                if ((tp->protoflag & GAI_PROTO_NOSERVICE) == 0)
477
                  {
478
                    struct gaih_servtuple *newp;
479
 
480
                    newp = alloca (sizeof (struct gaih_servtuple));
481
                    newp->next = NULL;
482
                    newp->socktype = tp->socktype;
483
                    newp->protocol = tp->protocol;
484
                    newp->port = htons (service->num);
485
 
486
                    *lastp = newp;
487
                    lastp = &newp->next;
488
                  }
489
            }
490
        }
491
    }
492
  else if (req->ai_socktype || req->ai_protocol)
493
    {
494
      st = alloca (sizeof (struct gaih_servtuple));
495
      st->next = NULL;
496
      st->socktype = tp->socktype;
497
      st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
498
                      ? req->ai_protocol : tp->protocol);
499
      st->port = 0;
500
    }
501
  else
502
    {
503
      /* Neither socket type nor protocol is set.  Return all socket types
504
         we know about.  */
505
      struct gaih_servtuple **lastp = &st;
506
      for (++tp; tp->name[0]; ++tp)
507
        {
508
          struct gaih_servtuple *newp;
509
 
510
          newp = alloca (sizeof (struct gaih_servtuple));
511
          newp->next = NULL;
512
          newp->socktype = tp->socktype;
513
          newp->protocol = tp->protocol;
514
          newp->port = 0;
515
 
516
          *lastp = newp;
517
          lastp = &newp->next;
518
        }
519
    }
520
 
521
  if (name != NULL)
522
    {
523
      at = alloca (sizeof (struct gaih_addrtuple));
524
 
525
      at->family = AF_UNSPEC;
526
      at->scopeid = 0;
527
      at->next = NULL;
528
 
529
#ifdef HAVE_LIBIDN
530
      if (req->ai_flags & AI_IDN)
531
        {
532
          int idn_flags = 0;
533
          if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)
534
            idn_flags |= IDNA_ALLOW_UNASSIGNED;
535
          if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)
536
            idn_flags |= IDNA_USE_STD3_ASCII_RULES;
537
 
538
          char *p = NULL;
539
          rc = __idna_to_ascii_lz (name, &p, idn_flags);
540
          if (rc != IDNA_SUCCESS)
541
            {
542
              if (rc == IDNA_MALLOC_ERROR)
543
                return -EAI_MEMORY;
544
              if (rc == IDNA_DLOPEN_ERROR)
545
                return -EAI_SYSTEM;
546
              return -EAI_IDN_ENCODE;
547
            }
548
          /* In case the output string is the same as the input string
549
             no new string has been allocated.  */
550
          if (p != name)
551
            {
552
              name = alloca (strlen (p) + 1);
553
              strcpy (name, p);
554
              free (p);
555
            }
556
        }
557
#endif
558
 
559
      if (inet_aton (name, (struct in_addr *) at->addr) != 0)
560
        {
561
          if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
562
            at->family = AF_INET;
563
          else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED)
564
            {
565
              at->addr[3] = at->addr[0];
566
              at->addr[2] = htonl (0xffff);
567
              at->addr[1] = 0;
568
              at->addr[0] = 0;
569
              at->family = AF_INET6;
570
            }
571
          else
572
            return -EAI_ADDRFAMILY;
573
 
574
        dupname:
575
          if (req->ai_flags & AI_CANONNAME)
576
            {
577
              canon = strdup (name);
578
              if (canon == NULL)
579
                return -EAI_MEMORY;
580
            }
581
        }
582
 
583
      if (at->family == AF_UNSPEC)
584
        {
585
          char *scope_delim;
586
          char *namebuf = alloca (strlen (name) + 1);
587
          strcpy (namebuf, name);
588
 
589
          scope_delim = strchr (namebuf, SCOPE_DELIMITER);
590
          if (scope_delim != NULL)
591
            *scope_delim = '\0';
592
 
593
          if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
594
            {
595
              if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
596
                at->family = AF_INET6;
597
              else if (req->ai_family == AF_INET
598
                       && IN6_IS_ADDR_V4MAPPED ((struct in6_addr *)at->addr))
599
                {
600
                  at->addr[0] = at->addr[3];
601
                  at->family = AF_INET;
602
                }
603
              else
604
                return -EAI_ADDRFAMILY;
605
 
606
              if (scope_delim != NULL)
607
                {
608
                  int try_numericscope = 0;
609
                  if (IN6_IS_ADDR_LINKLOCAL ((struct in6_addr *)at->addr)
610
                      || IN6_IS_ADDR_MC_LINKLOCAL ((struct in6_addr *)at->addr))
611
                    {
612
                      at->scopeid = if_nametoindex (scope_delim + 1);
613
                      if (at->scopeid == 0)
614
                        try_numericscope = 1;
615
                    }
616
                  else
617
                    try_numericscope = 1;
618
 
619
                  if (try_numericscope != 0)
620
                    {
621
                      char *end;
622
                      assert (sizeof (uint32_t) <= sizeof (unsigned long));
623
                      at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
624
                                                        10);
625
                      if (*end != '\0')
626
                        return GAIH_OKIFUNSPEC | -EAI_NONAME;
627
                    }
628
                }
629
 
630
              goto dupname;
631
            }
632
        }
633
 
634
      if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
635
        {
636
          struct gaih_addrtuple **pat = &at;
637
          int no_data = 0;
638
          int no_inet6_data = 0;
639
          service_user *nip = NULL;
640
          enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
641
          enum nss_status status = NSS_STATUS_UNAVAIL;
642
          int no_more;
643
          int old_res_options;
644
 
645
          /* If we do not have to look for IPv4 and IPv6 together, use
646
             the simple, old functions.  */
647
          if (req->ai_family == AF_INET || req->ai_family == AF_INET6)
648
            {
649
              int family = req->ai_family;
650
              size_t tmpbuflen = 512;
651
              char *tmpbuf = alloca (tmpbuflen);
652
              int rc;
653
              struct hostent th;
654
              struct hostent *h;
655
              int herrno;
656
 
657
            simple_again:
658
              while (1)
659
                {
660
                  rc = __gethostbyname2_r (name, family, &th, tmpbuf,
661
                                           tmpbuflen, &h, &herrno);
662
                  if (rc != ERANGE || herrno != NETDB_INTERNAL)
663
                    break;
664
                  tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
665
                }
666
 
667
              if (rc == 0)
668
                {
669
                  if (h == NULL)
670
                    {
671
                      if (req->ai_family == AF_INET6
672
                          && (req->ai_flags & AI_V4MAPPED)
673
                          && family == AF_INET6)
674
                        {
675
                          /* Try again, this time looking for IPv4
676
                             addresses.  */
677
                          family = AF_INET;
678
                          goto simple_again;
679
                        }
680
                    }
681
                  else
682
                    {
683
                      /* We found data, now convert it into the list.  */
684
                      int i = 0;
685
                      for (i = 0; h->h_addr_list[i]; ++i)
686
                        {
687
                          if (*pat == NULL)
688
                            {
689
                              *pat = alloca (sizeof (struct gaih_addrtuple));
690
                              (*pat)->scopeid = 0;
691
                            }
692
                          (*pat)->next = NULL;
693
                          (*pat)->family = req->ai_family;
694
                          if (family == req->ai_family)
695
                            memcpy ((*pat)->addr, h->h_addr_list[i],
696
                                    h->h_length);
697
                          else
698
                            {
699
                              int32_t *addr = (uint32_t *) (*pat)->addr;
700
                              addr[3] = *(uint32_t *) h->h_addr_list[i];
701
                              addr[2] = htonl (0xffff);
702
                              addr[1] = 0;
703
                              addr[0] = 0;
704
                            }
705
                          pat = &((*pat)->next);
706
                        }
707
                    }
708
                }
709
              else
710
                {
711
                  if (herrno == NETDB_INTERNAL)
712
                    {
713
                      h_errno = (herrno);
714
                      return -EAI_SYSTEM;
715
                    }
716
                  if (herrno == TRY_AGAIN)
717
                    {
718
                      return -EAI_AGAIN;
719
                    }
720
                  /* We made requests but they turned out no data.
721
                     The name is known, though.  */
722
                  return (GAIH_OKIFUNSPEC | -EAI_NODATA);
723
                }
724
 
725
              goto process_list;
726
            }
727
 
728
#ifdef USE_NSCD
729
          if (__nss_not_use_nscd_hosts > 0
730
              && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
731
            __nss_not_use_nscd_hosts = 0;
732
 
733
          if (!__nss_not_use_nscd_hosts)
734
            {
735
              /* Try to use nscd.  */
736
              struct nscd_ai_result *air = NULL;
737
              int herrno;
738
              int err = __nscd_getai (name, &air, &herrno);
739
              if (air != NULL)
740
                {
741
                  /* Transform into gaih_addrtuple list.  */
742
                  bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
743
                  char *addrs = air->addrs;
744
 
745
                  for (int i = 0; i < air->naddrs; ++i)
746
                    {
747
                      socklen_t size = (air->family[i] == AF_INET
748
                                        ? INADDRSZ : IN6ADDRSZ);
749
                      if (*pat == NULL)
750
                        {
751
                          *pat = alloca (sizeof (struct gaih_addrtuple));
752
                          (*pat)->scopeid = 0;
753
                        }
754
                      uint32_t *pataddr = (*pat)->addr;
755
                      (*pat)->next = NULL;
756
                      if (added_canon || air->canon == NULL)
757
                        (*pat)->name = NULL;
758
                      else {
759
                        canon = (*pat)->name = alloca (strlen (air->canon) + 1);
760
                        strcpy (canon, air->canon);
761
                      }
762
 
763
                      if (air->family[i] == AF_INET
764
                          && req->ai_family == AF_INET6
765
                          && (req->ai_flags & AI_V4MAPPED))
766
                        {
767
                          (*pat)->family = AF_INET6;
768
                          pataddr[3] = *(uint32_t *) addrs;
769
                          pataddr[2] = htonl (0xffff);
770
                          pataddr[1] = 0;
771
                          pataddr[0] = 0;
772
                          pat = &((*pat)->next);
773
                          added_canon = true;
774
                        }
775
                      else if (req->ai_family == AF_UNSPEC
776
                               || air->family[i] == req->ai_family)
777
                        {
778
                          (*pat)->family = air->family[i];
779
                          memcpy (pataddr, addrs, size);
780
                          pat = &((*pat)->next);
781
                          added_canon = true;
782
                          if (air->family[i] == AF_INET6)
783
                            got_ipv6 = true;
784
                        }
785
                      addrs += size;
786
                    }
787
 
788
                  free (air);
789
 
790
                  if (at->family == AF_UNSPEC)
791
                    return (GAIH_OKIFUNSPEC | -EAI_NONAME);
792
 
793
                  goto process_list;
794
                }
795
              else if (err != 0 && __nss_not_use_nscd_hosts == 0)
796
                {
797
                  if (herrno == NETDB_INTERNAL && errno == ENOMEM)
798
                    return -EAI_MEMORY;
799
                  if (herrno == TRY_AGAIN)
800
                    return -EAI_AGAIN;
801
                  return -EAI_SYSTEM;
802
                }
803
            }
804
#endif
805
 
806
          if (__nss_hosts_database != NULL)
807
            {
808
              no_more = 0;
809
              nip = __nss_hosts_database;
810
            }
811
          else
812
            no_more = __nss_database_lookup ("hosts", NULL,
813
                                             "dns [!UNAVAIL=return] files",
814
                                             &nip);
815
 
816
          if (__res_maybe_init (&_res, 0) == -1)
817
            no_more = 1;
818
 
819
          /* If we are looking for both IPv4 and IPv6 address we don't
820
             want the lookup functions to automatically promote IPv4
821
             addresses to IPv6 addresses.  Currently this is decided
822
             by setting the RES_USE_INET6 bit in _res.options.  */
823
          old_res_options = _res.options;
824
          _res.options &= ~RES_USE_INET6;
825
 
826
          size_t tmpbuflen = 512;
827
          char *tmpbuf = alloca (tmpbuflen);
828
 
829
          while (!no_more)
830
            {
831
              nss_gethostbyname3_r fct = NULL;
832
              if (req->ai_flags & AI_CANONNAME)
833
                /* No need to use this function if we do not look for
834
                   the canonical name.  The function does not exist in
835
                   all NSS modules and therefore the lookup would
836
                   often fail.  */
837
                fct = __nss_lookup_function (nip, "gethostbyname3_r");
838
              if (fct == NULL)
839
                /* We are cheating here.  The gethostbyname2_r function does
840
                   not have the same interface as gethostbyname3_r but the
841
                   extra arguments the latter takes are added at the end.
842
                   So the gethostbyname2_r code will just ignore them.  */
843
                fct = __nss_lookup_function (nip, "gethostbyname2_r");
844
 
845
              if (fct != NULL)
846
                {
847
                  if (req->ai_family == AF_INET6
848
                      || req->ai_family == AF_UNSPEC)
849
                    {
850
                      gethosts (AF_INET6, struct in6_addr);
851
                      no_inet6_data = no_data;
852
                      inet6_status = status;
853
                    }
854
                  if (req->ai_family == AF_INET
855
                      || req->ai_family == AF_UNSPEC
856
                      || (req->ai_family == AF_INET6
857
                          && (req->ai_flags & AI_V4MAPPED)
858
                          /* Avoid generating the mapped addresses if we
859
                             know we are not going to need them.  */
860
                          && ((req->ai_flags & AI_ALL) || !got_ipv6)))
861
                    {
862
                      gethosts (AF_INET, struct in_addr);
863
 
864
                      if (req->ai_family == AF_INET)
865
                        {
866
                          no_inet6_data = no_data;
867
                          inet6_status = status;
868
                        }
869
                    }
870
 
871
                  /* If we found one address for AF_INET or AF_INET6,
872
                     don't continue the search.  */
873
                  if (inet6_status == NSS_STATUS_SUCCESS
874
                      || status == NSS_STATUS_SUCCESS)
875
                    {
876
                      if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
877
                        {
878
                          /* If we need the canonical name, get it
879
                             from the same service as the result.  */
880
                          nss_getcanonname_r cfct;
881
                          int herrno;
882
 
883
                          cfct = __nss_lookup_function (nip, "getcanonname_r");
884
                          if (cfct != NULL)
885
                            {
886
                              const size_t max_fqdn_len = 256;
887
                              char *buf = alloca (max_fqdn_len);
888
                              char *s;
889
 
890
                              if (DL_CALL_FCT (cfct, (at->name ?: name, buf,
891
                                                      max_fqdn_len, &s, &rc,
892
                                                      &herrno))
893
                                  == NSS_STATUS_SUCCESS)
894
                                canon = s;
895
                              else
896
                                /* Set to name now to avoid using
897
                                   gethostbyaddr.  */
898
                                canon = name;
899
                            }
900
                        }
901
 
902
                      break;
903
                    }
904
 
905
                  /* We can have different states for AF_INET and
906
                     AF_INET6.  Try to find a useful one for both.  */
907
                  if (inet6_status == NSS_STATUS_TRYAGAIN)
908
                    status = NSS_STATUS_TRYAGAIN;
909
                  else if (status == NSS_STATUS_UNAVAIL &&
910
                           inet6_status != NSS_STATUS_UNAVAIL)
911
                    status = inet6_status;
912
                }
913
 
914
              if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
915
                break;
916
 
917
              if (nip->next == NULL)
918
                no_more = -1;
919
              else
920
                nip = nip->next;
921
            }
922
 
923
          _res.options = old_res_options;
924
 
925
          if (no_data != 0 && no_inet6_data != 0)
926
            {
927
              /* If both requests timed out report this.  */
928
              if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
929
                return -EAI_AGAIN;
930
 
931
              /* We made requests but they turned out no data.  The name
932
                 is known, though.  */
933
              return (GAIH_OKIFUNSPEC | -EAI_NODATA);
934
            }
935
        }
936
 
937
    process_list:
938
      if (at->family == AF_UNSPEC)
939
        return (GAIH_OKIFUNSPEC | -EAI_NONAME);
940
    }
941
  else
942
    {
943
      struct gaih_addrtuple *atr;
944
      atr = at = alloca (sizeof (struct gaih_addrtuple));
945
      memset (at, '\0', sizeof (struct gaih_addrtuple));
946
 
947
      if (req->ai_family == AF_UNSPEC)
948
        {
949
          at->next = alloca (sizeof (struct gaih_addrtuple));
950
          memset (at->next, '\0', sizeof (struct gaih_addrtuple));
951
        }
952
 
953
      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
954
        {
955
          at->family = AF_INET6;
956
          if ((req->ai_flags & AI_PASSIVE) == 0)
957
            memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
958
          atr = at->next;
959
        }
960
 
961
      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
962
        {
963
          atr->family = AF_INET;
964
          if ((req->ai_flags & AI_PASSIVE) == 0)
965
            atr->addr[0] = htonl (INADDR_LOOPBACK);
966
        }
967
    }
968
 
969
  if (pai == NULL)
970
    return 0;
971
 
972
  {
973
    struct gaih_servtuple *st2;
974
    struct gaih_addrtuple *at2 = at;
975
    size_t socklen;
976
    sa_family_t family;
977
 
978
    /*
979
      buffer is the size of an unformatted IPv6 address in printable format.
980
     */
981
    while (at2 != NULL)
982
      {
983
        /* Only the first entry gets the canonical name.  */
984
        if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
985
          {
986
            if (canon == NULL)
987
              {
988
                struct hostent *h = NULL;
989
                int herrno;
990
                struct hostent th;
991
                size_t tmpbuflen = 512;
992
                char *tmpbuf = NULL;
993
 
994
                do
995
                  {
996
                    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
997
                    rc = __gethostbyaddr_r (at2->addr,
998
                                            ((at2->family == AF_INET6)
999
                                             ? sizeof (struct in6_addr)
1000
                                             : sizeof (struct in_addr)),
1001
                                            at2->family, &th, tmpbuf,
1002
                                            tmpbuflen, &h, &herrno);
1003
                  }
1004
                while (rc == ERANGE && herrno == NETDB_INTERNAL);
1005
 
1006
                if (rc != 0 && herrno == NETDB_INTERNAL)
1007
                  {
1008
                    h_errno = (herrno);
1009
                    return -EAI_SYSTEM;
1010
                  }
1011
 
1012
                if (h != NULL)
1013
                  canon = h->h_name;
1014
                else
1015
                  {
1016
                    assert (orig_name != NULL);
1017
                    /* If the canonical name cannot be determined, use
1018
                       the passed in string.  */
1019
                    canon = orig_name;
1020
                  }
1021
              }
1022
 
1023
#ifdef HAVE_LIBIDN
1024
            if (req->ai_flags & AI_CANONIDN)
1025
              {
1026
                int idn_flags = 0;
1027
                if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)
1028
                  idn_flags |= IDNA_ALLOW_UNASSIGNED;
1029
                if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)
1030
                  idn_flags |= IDNA_USE_STD3_ASCII_RULES;
1031
 
1032
                char *out;
1033
                int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);
1034
                if (rc != IDNA_SUCCESS)
1035
                  {
1036
                    if (rc == IDNA_MALLOC_ERROR)
1037
                      return -EAI_MEMORY;
1038
                    if (rc == IDNA_DLOPEN_ERROR)
1039
                      return -EAI_SYSTEM;
1040
                    return -EAI_IDN_ENCODE;
1041
                  }
1042
                /* In case the output string is the same as the input
1043
                   string no new string has been allocated.  Otherwise
1044
                   make a copy.  */
1045
                if (out == canon)
1046
                  goto make_copy;
1047
              }
1048
            else
1049
#endif
1050
              {
1051
#ifdef HAVE_LIBIDN
1052
              make_copy:
1053
#endif
1054
                canon = strdup (canon);
1055
                if (canon == NULL)
1056
                  return -EAI_MEMORY;
1057
              }
1058
          }
1059
 
1060
        if (at2->family == AF_INET6)
1061
          {
1062
            family = AF_INET6;
1063
            socklen = sizeof (struct sockaddr_in6);
1064
 
1065
            /* If we looked up IPv4 mapped address discard them here if
1066
               the caller isn't interested in all address and we have
1067
               found at least one IPv6 address.  */
1068
            if (got_ipv6
1069
                && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
1070
                && IN6_IS_ADDR_V4MAPPED ((struct in6_addr *)at2->addr))
1071
              goto ignore;
1072
          }
1073
        else
1074
          {
1075
            family = AF_INET;
1076
            socklen = sizeof (struct sockaddr_in);
1077
          }
1078
 
1079
        for (st2 = st; st2 != NULL; st2 = st2->next)
1080
          {
1081
            struct addrinfo *ai;
1082
            ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
1083
            if (ai == NULL)
1084
              return -EAI_MEMORY;
1085
 
1086
            ai->ai_flags = req->ai_flags;
1087
            ai->ai_family = family;
1088
            ai->ai_socktype = st2->socktype;
1089
            ai->ai_protocol = st2->protocol;
1090
            ai->ai_addrlen = socklen;
1091
            ai->ai_addr = (void *) (ai + 1);
1092
 
1093
            /* We only add the canonical name once.  */
1094
            ai->ai_canonname = (char *) canon;
1095
            canon = NULL;
1096
 
1097
#if SALEN
1098
            ai->ai_addr->sa_len = socklen;
1099
#endif /* SALEN */
1100
            ai->ai_addr->sa_family = family;
1101
 
1102
            if (family == AF_INET6)
1103
              {
1104
                struct sockaddr_in6 *sin6p =
1105
                  (struct sockaddr_in6 *) ai->ai_addr;
1106
 
1107
                sin6p->sin6_port = st2->port;
1108
                sin6p->sin6_flowinfo = 0;
1109
                memcpy (&sin6p->sin6_addr,
1110
                        at2->addr, sizeof (struct in6_addr));
1111
                sin6p->sin6_scope_id = at2->scopeid;
1112
              }
1113
            else
1114
              {
1115
                struct sockaddr_in *sinp =
1116
                  (struct sockaddr_in *) ai->ai_addr;
1117
                sinp->sin_port = st2->port;
1118
                memcpy (&sinp->sin_addr,
1119
                        at2->addr, sizeof (struct in_addr));
1120
                memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
1121
              }
1122
 
1123
            pai = &(ai->ai_next);
1124
          }
1125
        *pai = NULL;
1126
 
1127
      ignore:
1128
        at2 = at2->next;
1129
      }
1130
  }
1131
  return 0;
1132
}
1133
 
1134
static struct gaih gaih[] =
1135
  {
1136
    { PF_INET6, gaih_inet },
1137
    { PF_INET, gaih_inet },
1138
#if 0
1139
    { PF_LOCAL, gaih_local },
1140
#endif
1141
    { PF_UNSPEC, NULL }
1142
  };
1143
 
1144
struct sort_result
1145
{
1146
  struct addrinfo *dest_addr;
1147
  struct sockaddr_storage source_addr;
1148
  uint8_t source_addr_len;
1149
  bool got_source_addr;
1150
};
1151
 
1152
 
1153
static int
1154
get_scope (const struct sockaddr_storage *ss)
1155
{
1156
  int scope;
1157
  if (ss->ss_family == PF_INET6)
1158
    {
1159
      const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *) ss;
1160
 
1161
      if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
1162
        {
1163
          if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
1164
            scope = 2;
1165
          else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
1166
            scope = 5;
1167
          else
1168
            /* XXX Is this the correct default behavior?  */
1169
            scope = 14;
1170
        }
1171
      else
1172
        scope = in6->sin6_addr.s6_addr[1] & 0xf;
1173
    }
1174
  else if (ss->ss_family == PF_INET)
1175
    {
1176
      const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1177
      const uint8_t *addr = (const uint8_t *) &in->sin_addr;
1178
 
1179
      /* RFC 3484 specifies how to map IPv6 addresses to scopes.
1180
         169.254/16 and 127/8 are link-local.  */
1181
      if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127)
1182
        scope = 2;
1183
      else if (addr[0] == 10 || (addr[0] == 172 && addr[1] == 16)
1184
               || (addr[0] == 192 && addr[1] == 168))
1185
        scope = 5;
1186
      else
1187
        scope = 14;
1188
    }
1189
  else
1190
    /* XXX What is a good default?  */
1191
    scope = 15;
1192
 
1193
  return scope;
1194
}
1195
 
1196
 
1197
/* XXX The system administrator should be able to install other
1198
   tables.  We need to make this configurable.  The problem is that
1199
   the kernel is also involved since it needs the same table.  */
1200
static const struct prefixlist
1201
{
1202
  struct in6_addr prefix;
1203
  unsigned int bits;
1204
  int val;
1205
} default_labels[] =
1206
  {
1207
    /* See RFC 3484 for the details.  */
1208
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1209
                                        0x0000, 0x0000, 0x0000, 0x0001 } } },
1210
      128, 0 },
1211
    { { .__u6_addr = { .__u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1212
                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1213
      16, 2 },
1214
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1215
                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1216
      96, 3 },
1217
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1218
                                       0x0000, 0xffff, 0x0000, 0x0000 } } },
1219
      96, 4 },
1220
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1221
                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1222
      0, 1 }
1223
  };
1224
 
1225
 
1226
static const struct prefixlist default_precedence[] =
1227
  {
1228
    /* See RFC 3484 for the details.  */
1229
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1230
                                       0x0000, 0x0000, 0x0000, 0x0001 } } },
1231
      128, 50 },
1232
    { { .__u6_addr = { .__u6_addr16 = { 0x2002, 0x0000, 0x0000, 0x0000,
1233
                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1234
      16, 30 },
1235
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1236
                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1237
      96, 20 },
1238
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1239
                                       0x0000, 0xffff, 0x0000, 0x0000 } } },
1240
      96, 10 },
1241
    { { .__u6_addr = { .__u6_addr16 = { 0x0000, 0x0000, 0x0000, 0x0000,
1242
                                       0x0000, 0x0000, 0x0000, 0x0000 } } },
1243
      0, 40 }
1244
  };
1245
 
1246
 
1247
static int
1248
match_prefix (const struct sockaddr_storage *ss, const struct prefixlist *list,
1249
              int default_val)
1250
{
1251
  int idx;
1252
  struct sockaddr_in6 in6_mem;
1253
  const struct sockaddr_in6 *in6;
1254
 
1255
  if (ss->ss_family == PF_INET6)
1256
    in6 = (const struct sockaddr_in6 *) ss;
1257
  else if (ss->ss_family == PF_INET)
1258
    {
1259
      const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
1260
 
1261
      /* Convert to IPv6 address.  */
1262
      in6_mem.sin6_family = PF_INET6;
1263
      in6_mem.sin6_port = in->sin_port;
1264
      in6_mem.sin6_flowinfo = 0;
1265
      if (in->sin_addr.s_addr == htonl (0x7f000001))
1266
        in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
1267
      else
1268
        {
1269
          /* Construct a V4-to-6 mapped address.  */
1270
          memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
1271
          in6_mem.sin6_addr.__u6_addr.__u6_addr16[5] = 0xffff;
1272
          in6_mem.sin6_addr.__u6_addr.__u6_addr32[3] = in->sin_addr.s_addr;
1273
          in6_mem.sin6_scope_id = 0;
1274
        }
1275
 
1276
      in6 = &in6_mem;
1277
    }
1278
  else
1279
    return default_val;
1280
 
1281
  for (idx = 0; ; ++idx)
1282
    {
1283
      unsigned int bits = list[idx].bits;
1284
      uint8_t *mask = list[idx].prefix.s6_addr;
1285
      uint8_t *val = in6->sin6_addr.s6_addr;
1286
 
1287
      while (bits > 8)
1288
        {
1289
          if (*mask != *val)
1290
            break;
1291
 
1292
          ++mask;
1293
          ++val;
1294
          bits -= 8;
1295
        }
1296
 
1297
      if (bits < 8)
1298
        {
1299
          if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
1300
            /* Match!  */
1301
            break;
1302
        }
1303
    }
1304
 
1305
  return list[idx].val;
1306
}
1307
 
1308
 
1309
static int
1310
get_label (const struct sockaddr_storage *ss)
1311
{
1312
  /* XXX What is a good default value?  */
1313
  return match_prefix (ss, default_labels, INT_MAX);
1314
}
1315
 
1316
 
1317
static int
1318
get_precedence (const struct sockaddr_storage *ss)
1319
{
1320
  /* XXX What is a good default value?  */
1321
  return match_prefix (ss, default_precedence, 0);
1322
}
1323
 
1324
 
1325
static int
1326
rfc3484_sort (const void *p1, const void *p2)
1327
{
1328
  const struct sort_result *a1 = (const struct sort_result *) p1;
1329
  const struct sort_result *a2 = (const struct sort_result *) p2;
1330
 
1331
  /* Rule 1: Avoid unusable destinations.
1332
     We have the got_source_addr flag set if the destination is reachable.  */
1333
  if (a1->got_source_addr && ! a2->got_source_addr)
1334
    return -1;
1335
  if (! a1->got_source_addr && a2->got_source_addr)
1336
    return 1;
1337
 
1338
 
1339
  /* Rule 2: Prefer matching scope.  Only interesting if both
1340
     destination addresses are IPv6.  */
1341
  int a1_dst_scope
1342
    = get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1343
 
1344
  int a2_dst_scope
1345
    = get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1346
 
1347
  if (a1->got_source_addr)
1348
    {
1349
      int a1_src_scope = get_scope (&a1->source_addr);
1350
      int a2_src_scope = get_scope (&a2->source_addr);
1351
 
1352
      if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
1353
        return -1;
1354
      if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
1355
        return 1;
1356
    }
1357
 
1358
 
1359
  /* Rule 3: Avoid deprecated addresses.
1360
     That's something only the kernel could decide.  */
1361
 
1362
  /* Rule 4: Prefer home addresses.
1363
     Another thing only the kernel can decide.  */
1364
 
1365
  /* Rule 5: Prefer matching label.  */
1366
  if (a1->got_source_addr)
1367
    {
1368
      int a1_dst_label
1369
        = get_label ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1370
      int a1_src_label = get_label (&a1->source_addr);
1371
 
1372
      int a2_dst_label
1373
        = get_label ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1374
      int a2_src_label = get_label (&a2->source_addr);
1375
 
1376
      if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
1377
        return -1;
1378
      if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
1379
        return 1;
1380
    }
1381
 
1382
 
1383
  /* Rule 6: Prefer higher precedence.  */
1384
  int a1_prec
1385
    = get_precedence ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
1386
  int a2_prec
1387
    = get_precedence ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
1388
 
1389
  if (a1_prec > a2_prec)
1390
    return -1;
1391
  if (a1_prec < a2_prec)
1392
    return 1;
1393
 
1394
 
1395
  /* Rule 7: Prefer native transport.
1396
     XXX How to recognize tunnels?  */
1397
 
1398
 
1399
  /* Rule 8: Prefer smaller scope.  */
1400
  if (a1_dst_scope < a2_dst_scope)
1401
    return -1;
1402
  if (a1_dst_scope > a2_dst_scope)
1403
    return 1;
1404
 
1405
 
1406
  /* Rule 9: Use longest matching prefix.  */
1407
  if (a1->got_source_addr
1408
      && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
1409
    {
1410
      int bit1 = 0;
1411
      int bit2 = 0;
1412
 
1413
      if (a1->dest_addr->ai_family == PF_INET)
1414
        {
1415
          assert (a1->source_addr.ss_family == PF_INET);
1416
          assert (a2->source_addr.ss_family == PF_INET);
1417
 
1418
          struct sockaddr_in *in1_dst;
1419
          struct sockaddr_in *in1_src;
1420
          struct sockaddr_in *in2_dst;
1421
          struct sockaddr_in *in2_src;
1422
 
1423
          in1_dst = (struct sockaddr_in *) a1->dest_addr->ai_addr;
1424
          in1_src = (struct sockaddr_in *) &a1->source_addr;
1425
          in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
1426
          in2_src = (struct sockaddr_in *) &a2->source_addr;
1427
 
1428
          bit1 = ffs (in1_dst->sin_addr.s_addr ^ in1_src->sin_addr.s_addr);
1429
          bit2 = ffs (in2_dst->sin_addr.s_addr ^ in2_src->sin_addr.s_addr);
1430
        }
1431
      else if (a1->dest_addr->ai_family == PF_INET6)
1432
        {
1433
          assert (a1->source_addr.ss_family == PF_INET6);
1434
          assert (a2->source_addr.ss_family == PF_INET6);
1435
 
1436
          struct sockaddr_in6 *in1_dst;
1437
          struct sockaddr_in6 *in1_src;
1438
          struct sockaddr_in6 *in2_dst;
1439
          struct sockaddr_in6 *in2_src;
1440
 
1441
          in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
1442
          in1_src = (struct sockaddr_in6 *) &a1->source_addr;
1443
          in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
1444
          in2_src = (struct sockaddr_in6 *) &a2->source_addr;
1445
 
1446
          int i;
1447
          for (i = 0; i < 4; ++i)
1448
            if (in1_dst->sin6_addr.s6_addr32[i]
1449
                != in1_src->sin6_addr.s6_addr32[i]
1450
                || (in2_dst->sin6_addr.s6_addr32[i]
1451
                    != in2_src->sin6_addr.s6_addr32[i]))
1452
              break;
1453
 
1454
          if (i < 4)
1455
            {
1456
              bit1 = ffs (in1_dst->sin6_addr.s6_addr32[i]
1457
                          ^ in1_src->sin6_addr.s6_addr32[i]);
1458
              bit2 = ffs (in2_dst->sin6_addr.s6_addr32[i]
1459
                          ^ in2_src->sin6_addr.s6_addr32[i]);
1460
            }
1461
        }
1462
 
1463
      if (bit1 > bit2)
1464
        return -1;
1465
      if (bit1 < bit2)
1466
        return 1;
1467
    }
1468
 
1469
 
1470
  /* Rule 10: Otherwise, leave the order unchanged.  */
1471
  return 0;
1472
}
1473
 
1474
 
1475
int
1476
getaddrinfo (const char *name, const char *service,
1477
             const struct addrinfo *hints, struct addrinfo **pai)
1478
{
1479
  int i = 0, j = 0, last_i = 0;
1480
  int nresults = 0;
1481
  struct addrinfo *p = NULL, **end;
1482
  struct gaih *g = gaih, *pg = NULL;
1483
  struct gaih_service gaih_service, *pservice;
1484
  struct addrinfo local_hints;
1485
 
1486
  if (name != NULL && name[0] == '*' && name[1] == 0)
1487
    name = NULL;
1488
 
1489
  if (service != NULL && service[0] == '*' && service[1] == 0)
1490
    service = NULL;
1491
 
1492
  if (name == NULL && service == NULL)
1493
    return EAI_NONAME;
1494
 
1495
  if (hints == NULL)
1496
    hints = &default_hints;
1497
 
1498
  if (hints->ai_flags
1499
      & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
1500
#ifdef HAVE_LIBIDN
1501
          |AI_IDN|AI_CANONIDN|AI_IDN_ALLOW_UNASSIGNED
1502
          |AI_IDN_USE_STD3_ASCII_RULES
1503
#endif
1504
          |AI_NUMERICSERV|AI_ALL))
1505
    return EAI_BADFLAGS;
1506
 
1507
  if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
1508
    return EAI_BADFLAGS;
1509
 
1510
  if (hints->ai_flags & AI_ADDRCONFIG)
1511
    {
1512
      /* Determine whether we have IPv4 or IPv6 interfaces or both.
1513
         We cannot cache the results since new interfaces could be
1514
         added at any time.  */
1515
      bool seen_ipv4;
1516
      bool seen_ipv6;
1517
      __check_pf (&seen_ipv4, &seen_ipv6);
1518
 
1519
      /* Now make a decision on what we return, if anything.  */
1520
      if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
1521
        {
1522
          /* If we haven't seen both IPv4 and IPv6 interfaces we can
1523
             narrow down the search.  */
1524
          if (! seen_ipv4 || ! seen_ipv6)
1525
            {
1526
              local_hints = *hints;
1527
              local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6;
1528
              hints = &local_hints;
1529
            }
1530
        }
1531
      else if ((hints->ai_family == PF_INET && ! seen_ipv4)
1532
               || (hints->ai_family == PF_INET6 && ! seen_ipv6))
1533
        /* We cannot possibly return a valid answer.  */
1534
        return EAI_NONAME;
1535
    }
1536
 
1537
  if (service && service[0])
1538
    {
1539
      char *c;
1540
      gaih_service.name = service;
1541
      gaih_service.num = strtoul (gaih_service.name, &c, 10);
1542
      if (*c != '\0')
1543
        {
1544
          if (hints->ai_flags & AI_NUMERICSERV)
1545
            return EAI_NONAME;
1546
 
1547
          gaih_service.num = -1;
1548
        }
1549
 
1550
      pservice = &gaih_service;
1551
    }
1552
  else
1553
    pservice = NULL;
1554
 
1555
  if (pai)
1556
    end = &p;
1557
  else
1558
    end = NULL;
1559
 
1560
  while (g->gaih)
1561
    {
1562
      if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
1563
        {
1564
          j++;
1565
          if (pg == NULL || pg->gaih != g->gaih)
1566
            {
1567
              pg = g;
1568
              i = g->gaih (name, pservice, hints, end);
1569
              if (i != 0)
1570
                {
1571
                  /* EAI_NODATA is a more specific result as it says that
1572
                     we found a result but it is not usable.  */
1573
                  if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
1574
                    last_i = i;
1575
 
1576
                  if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
1577
                    {
1578
                      ++g;
1579
                      continue;
1580
                    }
1581
 
1582
                  freeaddrinfo (p);
1583
 
1584
                  return -(i & GAIH_EAI);
1585
                }
1586
              if (end)
1587
                while (*end)
1588
                  {
1589
                    end = &((*end)->ai_next);
1590
                    ++nresults;
1591
                  }
1592
            }
1593
        }
1594
      ++g;
1595
    }
1596
 
1597
  if (j == 0)
1598
    return EAI_FAMILY;
1599
 
1600
  if (nresults > 1)
1601
    {
1602
      /* Sort results according to RFC 3484.  */
1603
      struct sort_result results[nresults];
1604
      struct addrinfo *q;
1605
      struct addrinfo *last = NULL;
1606
      char *canonname = NULL;
1607
 
1608
      for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
1609
        {
1610
          results[i].dest_addr = q;
1611
          results[i].got_source_addr = false;
1612
 
1613
          /* If we just looked up the address for a different
1614
             protocol, reuse the result.  */
1615
          if (last != NULL && last->ai_addrlen == q->ai_addrlen
1616
              && memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0)
1617
            {
1618
              memcpy (&results[i].source_addr, &results[i - 1].source_addr,
1619
                      results[i - 1].source_addr_len);
1620
              results[i].source_addr_len = results[i - 1].source_addr_len;
1621
              results[i].got_source_addr = results[i - 1].got_source_addr;
1622
            }
1623
          else
1624
            {
1625
              /* We overwrite the type with SOCK_DGRAM since we do not
1626
                 want connect() to connect to the other side.  If we
1627
                 cannot determine the source address remember this
1628
                 fact.  */
1629
              int fd = socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
1630
              socklen_t sl = sizeof (results[i].source_addr);
1631
              if (fd != -1
1632
                  && connect (fd, q->ai_addr, q->ai_addrlen) == 0
1633
                  && getsockname (fd,
1634
                                    (struct sockaddr *) &results[i].source_addr,
1635
                                    &sl) == 0)
1636
                {
1637
                  results[i].source_addr_len = sl;
1638
                  results[i].got_source_addr = true;
1639
                }
1640
              else
1641
                /* Just make sure that if we have to process the same
1642
                   address again we do not copy any memory.  */
1643
                results[i].source_addr_len = 0;
1644
 
1645
              if (fd != -1)
1646
                close_not_cancel_no_status (fd);
1647
            }
1648
 
1649
          /* Remember the canonical name.  */
1650
          if (q->ai_canonname != NULL)
1651
            {
1652
              assert (canonname == NULL);
1653
              canonname = q->ai_canonname;
1654
              q->ai_canonname = NULL;
1655
            }
1656
        }
1657
 
1658
      /* We got all the source addresses we can get, now sort using
1659
         the information.  */
1660
      qsort (results, nresults, sizeof (results[0]), rfc3484_sort);
1661
 
1662
      /* Queue the results up as they come out of sorting.  */
1663
      q = p = results[0].dest_addr;
1664
      for (i = 1; i < nresults; ++i)
1665
        q = q->ai_next = results[i].dest_addr;
1666
      q->ai_next = NULL;
1667
 
1668
      /* Fill in the canonical name into the new first entry.  */
1669
      p->ai_canonname = canonname;
1670
    }
1671
 
1672
  if (p)
1673
    {
1674
      *pai = p;
1675
      return 0;
1676
    }
1677
 
1678
  if (pai == NULL && last_i == 0)
1679
    return 0;
1680
 
1681
  return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
1682
}
1683
libc_hidden_def (getaddrinfo)
1684
 
1685
static_link_warning (getaddrinfo)
1686
 
1687
void
1688
freeaddrinfo (struct addrinfo *ai)
1689
{
1690
  struct addrinfo *p;
1691
 
1692
  while (ai != NULL)
1693
    {
1694
      p = ai;
1695
      ai = ai->ai_next;
1696
      free (p->ai_canonname);
1697
      free (p);
1698
    }
1699
}
1700
libc_hidden_def (freeaddrinfo)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.