Watt-32 tcp/ip  2.2 dev-rel.10
get_ai.c
Go to the documentation of this file.
1 
5 /* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * "FAITH" part is local hack for supporting IPv4-v6 translator.
35  *
36  * Issues to be discussed:
37  * - Thread safe-ness must be checked.
38  * - Return values. There are nonstandard return values defined and used
39  * in the source code. This is because RFC2553 is silent about which error
40  * code must be returned for which situation.
41  * Note:
42  * - The code filters out AFs that are not supported by the kernel,
43  * when globbing NULL hostname (to loopback, or wildcard). Is it the right
44  * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
45  * in ai_flags?
46  *
47  * Adapted for Watt-32 tcp/ip stack by G. Vanem <gvanem@yahoo.no>, Aug 2002.
48  */
49 
50 #if 0
51 static const char rcsid[] = "@(#) $Header: /tcpdump/master/tcpdump/missing/"
52  "getaddrinfo.c,v 1.10 2000/10/24 00:56:53 fenner Exp $";
53 #endif
54 
55 #include "socket.h"
56 #include "pcdns.h"
57 
58 #if defined(USE_BSD_API)
59 
60 #define ANY 0
61 #define YES 1
62 #define NO 0
63 #define PTON_MAX 16
64 
65 /* Addresss family descriptor
66  */
67 struct afd {
68  int a_af;
69  int a_addrlen;
70  int a_socklen;
71  int a_off;
72  const char *a_addrany;
73  const char *a_loopback;
74  int a_scoped;
75  };
76 
77 struct explore {
78  int e_af;
79  int e_socktype;
80  int e_protocol;
81  const char *e_protostr;
82  int e_wild;
83 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
84 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
85 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
86  };
87 
88 static struct explore explore[] = {
89  { AF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 7 },
90  { AF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 7 },
91  { AF_INET6, SOCK_RAW, ANY, NULL, 5 },
92  { AF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 7 },
93  { AF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 7 },
94  { AF_INET, SOCK_RAW, ANY, NULL, 5 },
95  { -1, 0, 0, NULL, 0 }
96  };
97 
98 BOOL called_from_getai = FALSE;
99 
100 static struct afd afd_list [3];
101 
102 static int str_isnumber (const char *);
103 static int explore_fqdn (const struct addrinfo *, const char *, const char *,
104  struct addrinfo **res);
105 
106 static int explore_null (const struct addrinfo *, const char *,
107  struct addrinfo **);
108 
109 static int explore_numeric (const struct addrinfo *, const char *, const char *,
110  struct addrinfo **);
111 
112 static int explore_numeric_scope (const struct addrinfo *, const char *,
113  const char *, struct addrinfo **);
114 
115 static int get_name (const char *, const struct afd *, struct addrinfo **,
116  char *, const struct addrinfo *, const char *);
117 
118 static int get_canonname (const struct addrinfo *, struct addrinfo *,
119  const char *);
120 
121 static struct addrinfo *get_ai (const struct addrinfo *, const struct afd *,
122  const char *);
123 
124 static int get_portmatch (const struct addrinfo *, const char *);
125 static int get_port (struct addrinfo *, const char *, int);
126 static const struct afd *find_afd (int);
127 
128 static const char *ai_errlist[] = {
129  "Success",
130  "Address family for hostname not supported", /* EAI_ADDRFAMILY */
131  "Temporary failure in name resolution", /* EAI_AGAIN */
132  "Invalid value for ai_flags", /* EAI_BADFLAGS */
133  "Non-recoverable failure in name resolution", /* EAI_FAIL */
134  "ai_family not supported", /* EAI_FAMILY */
135  "Memory allocation failure", /* EAI_MEMORY */
136  "No address associated with hostname", /* EAI_NODATA */
137  "hostname nor servname provided, or not known", /* EAI_NONAME */
138  "servname not supported for ai_socktype", /* EAI_SERVICE */
139  "ai_socktype not supported", /* EAI_SOCKTYPE */
140  "System error returned in errno", /* EAI_SYSTEM */
141  "Invalid value for hints", /* EAI_BADHINTS */
142  "Resolved protocol is unknown", /* EAI_PROTOCOL */
143  "Unknown error", /* EAI_MAX */
144 };
145 
146 /* XXX macros that make external reference is BAD. */
147 
148 #define GET_AI(ai, afd, addr) do { \
149  /* external reference: pai, error and free_it */ \
150  (ai) = get_ai (pai, (afd), (const char*) (addr)); \
151  if ((ai) == NULL) { \
152  error = EAI_MEMORY; \
153  goto free_it; \
154  } \
155  } while (0)
156 
157 #define GET_PORT(ai, serv) do { \
158  /* external reference: error and free_it */ \
159  error = get_port ((ai), (serv), 0); \
160  if (error != 0) \
161  goto free_it; \
162  } while (0)
163 
164 #define GET_CANONNAME(ai, str) do { \
165  /* external reference: pai, error and free_it */ \
166  error = get_canonname (pai, (ai), (str)); \
167  if (error != 0) \
168  goto free_it; \
169  } while (0)
170 
171 #define ERR(err) do { \
172  /* external reference: error, and label bad */ \
173  error = (err); \
174  goto bad; \
175  } while (0)
176 
177 #define MATCH_FAMILY(x, y, w) \
178  ((x) == (y) || ((w) && ((x) == AF_UNSPEC || (y) == AF_UNSPEC)))
179 
180 #define MATCH(x, y, w) \
181  ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
182 
183 char * W32_CALL gai_strerror (int ecode)
184 {
185  if (ecode < 0 || ecode > EAI_MAX)
186  ecode = EAI_MAX;
187  return (char*) ai_errlist[ecode];
188 }
189 
190 /*
191  * We only have 1 interface.
192  * Size of 'if_name' must be >= IF_NAMESIZE.
193  * Assume __get_ifname() returns name with trailing digit.
194  */
195 int W32_CALL if_nametoindex (const char *if_name)
196 {
197  char name [IF_NAMESIZE];
198  char id;
199 
200  __get_ifname (name);
201  id = name [strlen(name)] - '0';
202  if (!stricmp(if_name,name))
203  return (id+1);
204  return (0);
205 }
206 
207 char * W32_CALL if_indextoname (int if_id, char *if_name)
208 {
209  char name [IF_NAMESIZE];
210  int id;
211 
212  __get_ifname (name);
213  id = name [strlen(name)] - '0';
214  if (if_id != id+1)
215  {
216  SOCK_ERRNO (ENXIO);
217  return (NULL);
218  }
219  return strcpy (if_name, name);
220 }
221 
222 int __scope_ascii_to_id (const char *str)
223 {
224  if (!isdigit((int)*str))
225  return (0);
226  return (*str - '0');
227 }
228 
229 int __scope_id_to_ascii (int scope)
230 {
231  scope += '0';
232  if (!isdigit(scope))
233  return (0);
234  return (scope);
235 }
236 
237 static void free_addrinfo (struct addrinfo *ai)
238 {
239  struct addrinfo *next;
240 
241  for ( ; ai; ai = next)
242  {
243  next = ai->ai_next;
244  if (ai->ai_canonname)
245  free (ai->ai_canonname);
246  free (ai);
247  }
248 }
249 
250 void W32_CALL freeaddrinfo (struct addrinfo *ai)
251 {
252  SOCK_DEBUGF (("\nfreeaddrinfo: 0x%" ADDR_FMT, ADDR_CAST(ai)));
253  free_addrinfo (ai);
254 }
255 
256 static int str_isnumber (const char *p)
257 {
258  char *q = (char *) p;
259 
260  while (*q)
261  {
262  if (!isdigit((int)*q))
263  return (NO);
264  q++;
265  }
266  return (YES);
267 }
268 
273 static void afd_list_init (BOOL ip6_prio)
274 {
275  static const char in4addr_loopback[] = { 127, 0, 0, 1 };
276  static const char in4addr_addrany[] = { 0, 0, 0, 0 };
277 #if !defined(USE_IPV6)
278  static const struct in6_addr in6addr_loopback = {{ 0,0,0,0,0,0,0,0,
279  0,0,0,0,0,0,0,1 }};
280  static const struct in6_addr in6addr_any = {{ 0,0,0,0,0,0,0,0,
281  0,0,0,0,0,0,0,0 }};
282 #endif
283 
284 
285  int i = (ip6_prio ? 0 : 1);
286 
287  memset (&afd_list, 0, sizeof(afd_list));
288 
289  afd_list[i].a_af = AF_INET6;
290  afd_list[i].a_addrlen = sizeof (struct in6_addr);
291  afd_list[i].a_socklen = sizeof (struct sockaddr_in6);
292  afd_list[i].a_off = offsetof (struct sockaddr_in6, sin6_addr);
293  afd_list[i].a_addrany = (const char*) &in6addr_any;
294  afd_list[i].a_loopback = (const char*) &in6addr_loopback;
295  afd_list[i].a_scoped = 1;
296 
297  i ^= 1;
298  afd_list[i].a_af = AF_INET;
299  afd_list[i].a_addrlen = sizeof (struct in_addr);
300  afd_list[i].a_socklen = sizeof (struct sockaddr_in);
301  afd_list[i].a_off = offsetof (struct sockaddr_in, sin_addr);
302  afd_list[i].a_addrany = in4addr_addrany;
303  afd_list[i].a_loopback = in4addr_loopback;
304  afd_list[i].a_scoped = 0;
305 
306  if (!ip6_prio)
307  {
308  explore[0].e_af = explore[1].e_af = explore[2].e_af = AF_INET;
309  explore[3].e_af = explore[4].e_af = explore[5].e_af = AF_INET6;
310  }
311 }
312 
313 int W32_CALL getaddrinfo (const char *hostname, const char *servname,
314  const struct addrinfo *hints, struct addrinfo **res)
315 {
316  static BOOL init = FALSE;
317  struct addrinfo *cur, *pai, ai, ai0, sentinel;
318  const struct afd *afd;
319  const struct explore *ex;
320  int error = 0;
321 
322  if (!init)
323  afd_list_init (TRUE); /* Give IPv6 highest priority */
324  init = TRUE;
325 
326  sentinel.ai_next = NULL;
327  cur = &sentinel;
328  pai = &ai;
329  pai->ai_flags = 0;
330  pai->ai_family = AF_UNSPEC;
331  pai->ai_socktype = ANY;
332  pai->ai_protocol = ANY;
333  pai->ai_addrlen = 0;
334  pai->ai_canonname = NULL;
335  pai->ai_addr = NULL;
336  pai->ai_next = NULL;
337 
338  SOCK_DEBUGF (("\ngetaddrinfo: `%s', `%s'",
339  hostname, servname));
340 
341  if (!hostname && !servname)
342  ERR (EAI_NONAME);
343 
344  if (hints)
345  {
346  /* error check for hints */
347  if (hints->ai_addrlen || hints->ai_canonname ||
348  hints->ai_addr || hints->ai_next)
349  ERR (EAI_BADHINTS); /* xxx */
350 
351  if (hints->ai_flags & ~AI_MASK)
352  ERR (EAI_BADFLAGS);
353 
354  switch (hints->ai_family)
355  {
356  case AF_UNSPEC:
357  case AF_INET:
358  case AF_INET6:
359  break;
360  default:
361  ERR (EAI_FAMILY);
362  }
363  *pai = *hints;
364 
365  /* if both socktype/protocol are specified, check if they
366  * are meaningful combination.
367  */
368  if (pai->ai_socktype != ANY && pai->ai_protocol != ANY)
369  {
370  for (ex = explore; ex->e_af >= 0; ex++)
371  {
372  if (pai->ai_family != ex->e_af ||
373  ex->e_socktype == ANY ||
374  ex->e_protocol == ANY)
375  continue;
376 
377  if (pai->ai_socktype == ex->e_socktype &&
378  pai->ai_protocol != ex->e_protocol)
379  ERR (EAI_BADHINTS);
380  }
381  }
382  }
383 
384  /* Check for special cases:
385  * (1) numeric servname is disallowed if socktype/protocol are left
386  * unspecified.
387  * (2) servname is disallowed for raw and other inet{,6} sockets.
388  */
389  if (MATCH_FAMILY(pai->ai_family, AF_INET, 1) ||
390  MATCH_FAMILY(pai->ai_family, AF_INET6, 1))
391  {
392  ai0 = *pai;
393 
394  if (pai->ai_family == AF_UNSPEC)
395  pai->ai_family = AF_INET6;
396  error = get_portmatch (pai, servname);
397  if (error)
398  ERR (error);
399  *pai = ai0;
400  }
401 
402  ai0 = *pai;
403 
404  /* NULL hostname, or numeric hostname
405  */
406  for (ex = explore; ex->e_af >= 0; ex++)
407  {
408  *pai = ai0;
409 
410  if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
411  continue;
412 
413  if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
414  continue;
415 
416  if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
417  continue;
418 
419  if (pai->ai_family == AF_UNSPEC)
420  pai->ai_family = ex->e_af;
421  if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
422  pai->ai_socktype = ex->e_socktype;
423  if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
424  pai->ai_protocol = ex->e_protocol;
425 
426  if (!hostname)
427  error = explore_null (pai, servname, &cur->ai_next);
428  else error = explore_numeric_scope (pai, hostname, servname, &cur->ai_next);
429 
430  if (error)
431  goto free_it;
432 
433  while (cur && cur->ai_next)
434  cur = cur->ai_next;
435  }
436 
437  /* If numeric representation of AF1 can be interpreted as FQDN
438  * representation of AF2, we need to think again about the code below.
439  */
440  if (sentinel.ai_next)
441  goto good;
442 
443  if (pai->ai_flags & AI_NUMERICHOST)
444  ERR (EAI_NONAME);
445 
446  if (!hostname)
447  ERR (EAI_NONAME);
448 
449  /* hostname as alphabetical name.
450  * We would like to prefer AF_INET6 than AF_INET, so we'll make a
451  * outer loop by AFs.
452  */
453  for (afd = afd_list; afd->a_af; afd++)
454  {
455  *pai = ai0;
456 
457  if (!MATCH_FAMILY (pai->ai_family, afd->a_af, 1))
458  continue;
459 
460  for (ex = explore; ex->e_af >= 0; ex++)
461  {
462  *pai = ai0;
463 
464  if (pai->ai_family == AF_UNSPEC)
465  pai->ai_family = afd->a_af;
466 
467  if (!MATCH_FAMILY (pai->ai_family, ex->e_af, WILD_AF(ex)))
468  continue;
469 
470  if (!MATCH (pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
471  continue;
472 
473  if (!MATCH (pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
474  continue;
475 
476  if (pai->ai_family == AF_UNSPEC)
477  pai->ai_family = ex->e_af;
478  if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
479  pai->ai_socktype = ex->e_socktype;
480  if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
481  pai->ai_protocol = ex->e_protocol;
482 
483  error = explore_fqdn (pai, hostname, servname, &cur->ai_next);
484 
485  if (_resolve_exit) /* interrupted or other fail */
486  {
487  error = EAI_MAX;
488  goto free_it;
489  }
490  while (cur && cur->ai_next)
491  cur = cur->ai_next;
492  }
493  }
494 
495 good:
496  if (sentinel.ai_next)
497  error = 0;
498 
499  if (error == 0)
500  {
501  if (sentinel.ai_next)
502  {
503  if (res)
504  *res = sentinel.ai_next;
505  // dump_addrinfo (*res);
506  return (0); /* success */
507  }
508  error = EAI_FAIL;
509  }
510 
511 free_it:
512 bad:
513  free_addrinfo (sentinel.ai_next);
514  if (res)
515  *res = NULL;
516  SOCK_DEBUGF ((": %s", ai_errlist[error]));
517  return (error);
518 }
519 
520 /*
521  * FQDN hostname, DNS lookup
522  */
523 static int explore_fqdn (const struct addrinfo *pai, const char *hostname,
524  const char *servname, struct addrinfo **res)
525 {
526  static struct hostent copy;
527  static struct in6_addr addr [MAX_ADDRESSES+1];
528  static char *list [MAX_ADDRESSES+1], *ap;
529  struct hostent *hp = NULL;
530  struct addrinfo sentinel, *cur;
531  const struct afd *afd;
532  int af, i, error = 0;
533 
534 #ifdef TEST_PROG
535  SOCK_DEBUGF (("\nexplore_fqdn"));
536 #endif
537 
538  *res = NULL;
539  cur = &sentinel;
540  sentinel.ai_next = NULL;
541 
542  /* Do not filter unsupported AFs here. We need to honor content of
543  * databases (/etc/hosts, DNS and others). Otherwise we cannot
544  * replace gethostbyname() by getaddrinfo().
545  */
546 
547  /* if the servname does not match socktype/protocol, ignore it.
548  */
549  if (get_portmatch (pai, servname) != 0)
550  return (0);
551 
552  afd = find_afd (pai->ai_family);
553 
554  /* Post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG)
555  * rather than hardcoding it. We may need to add AI_ADDRCONFIG
556  * handling code by ourselves.
557  */
558  SOCK_ENTER_SCOPE();
559  hp = gethostbyname2 (hostname, pai->ai_family);
560  SOCK_LEAVE_SCOPE();
561 
562  if (!hp)
563  {
564  switch (h_errno)
565  {
566  case HOST_NOT_FOUND:
567  case NO_DATA:
568  error = EAI_NODATA;
569  break;
570  case TRY_AGAIN:
571  error = EAI_AGAIN;
572  break;
573  case NO_RECOVERY:
574  case NETDB_INTERNAL:
575  default:
576  error = EAI_FAIL;
577  break;
578  }
579 
580  }
581  else if (!hp->h_name || !hp->h_name[0] || !hp->h_addr_list[0])
582  {
583  hp = NULL;
584  error = EAI_FAIL;
585  }
586 
587  if (!hp)
588  goto free_it;
589 
590  /* Perform a shallow copy of 'hp'. Since 'hp' is returned from
591  * fill_hostent(), the contents will be destroyed in below
592  * get_name() otherwise.
593  */
594  copy = *hp;
595  memset (&addr, 0, sizeof(addr));
596  memset (&list, 0, sizeof(list));
597  for (i = 0; hp->h_addr_list[i]; i++)
598  {
599  memcpy (&addr[i], hp->h_addr_list[i], hp->h_length);
600  list[i] = (char*) &addr[i];
601  }
602  list[i] = NULL;
603  copy.h_addr_list = list;
604  hp = &copy;
605 
606  for (i = 0; hp->h_addr_list[i]; i++)
607  {
608  af = hp->h_addrtype;
609  ap = hp->h_addr_list[i];
610  if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(ap))
611  {
612  af = AF_INET;
613  ap += sizeof(struct in6_addr) - sizeof(struct in_addr);
614  }
615 
616  if (af != pai->ai_family)
617  continue;
618 
619  if (!(pai->ai_flags & AI_CANONNAME))
620  {
621  GET_AI (cur->ai_next, afd, ap);
622  GET_PORT (cur->ai_next, servname);
623  }
624  else
625  {
626  /* if AI_CANONNAME and if reverse lookup fail, return ai anyway
627  * to pacify calling application.
628  *
629  * XXX getaddrinfo() is a name to address translation function,
630  * and it looks strange that we do addr to name translation here.
631  */
632  get_name (ap, afd, &cur->ai_next, ap, pai, servname);
633  }
634  while (cur && cur->ai_next)
635  cur = cur->ai_next;
636  }
637  *res = sentinel.ai_next;
638  return (0);
639 
640 free_it:
641  free_addrinfo (sentinel.ai_next);
642  return (error);
643 }
644 
645 /*
646  * hostname == NULL.
647  * passive socket -> anyaddr (0.0.0.0 or ::)
648  * non-passive socket -> localhost (127.0.0.1 or ::1)
649  */
650 static int explore_null (const struct addrinfo *pai, const char *servname,
651  struct addrinfo **res)
652 {
653  const struct afd *afd;
654  struct addrinfo *cur, sentinel;
655  int s, error;
656 
657 #ifdef TEST_PROG
658  SOCK_DEBUGF (("\nexplore_null"));
659 #endif
660 
661  *res = NULL;
662  sentinel.ai_next = NULL;
663  cur = &sentinel;
664 
665  /* filter out AFs that are not supported
666  */
667  SOCK_ENTER_SCOPE();
668  s = socket (pai->ai_family, SOCK_DGRAM, 0);
669  if (s >= 0)
670  close_s (s);
671  SOCK_LEAVE_SCOPE();
672 
673  if (s < 0)
674  return (0);
675 
676  /* if the servname does not match socktype/protocol, ignore it.
677  */
678  if (get_portmatch (pai, servname) != 0)
679  return (0);
680 
681  afd = find_afd (pai->ai_family);
682 
683  if (pai->ai_flags & AI_PASSIVE)
684  {
685  GET_AI (cur->ai_next, afd, afd->a_addrany);
686  /* xxx meaningless?
687  * GET_CANONNAME(cur->ai_next, "anyaddr");
688  */
689  GET_PORT (cur->ai_next, servname);
690  }
691  else
692  {
693  GET_AI (cur->ai_next, afd, afd->a_loopback);
694  /* xxx meaningless?
695  * GET_CANONNAME(cur->ai_next, "localhost");
696  */
697  GET_PORT (cur->ai_next, servname);
698  }
699 
700  *res = sentinel.ai_next;
701  return (0);
702 
703 free_it:
704  free_addrinfo (sentinel.ai_next);
705  return (error);
706 }
707 
708 /*
709  * numeric hostname
710  */
711 static int explore_numeric (const struct addrinfo *pai, const char *hostname,
712  const char *servname, struct addrinfo **res)
713 {
714  const struct afd *afd;
715  struct addrinfo *cur, sentinel;
716  int error, flags;
717  union {
718  struct in_addr a4;
719  struct in6_addr a6;
720  } pton;
721 
722 #ifdef TEST_PROG
723  SOCK_DEBUGF (("\nexplore_numeric"));
724 #endif
725 
726  *res = NULL;
727  sentinel.ai_next = NULL;
728  cur = &sentinel;
729 
730  /* if the servname does not match socktype/protocol, ignore it.
731  */
732  if (get_portmatch (pai, servname) != 0)
733  return (0);
734 
735  afd = find_afd (pai->ai_family);
736  flags = pai->ai_flags;
737 
738  if (inet_pton (afd->a_af, hostname, &pton) == 1)
739  {
740  DWORD v4a;
741  BYTE pfx;
742 
743  switch (afd->a_af)
744  {
745  case AF_INET:
746  v4a = (DWORD) ntohl (pton.a4.s_addr);
747  if (IN_MULTICAST (v4a) || IN_EXPERIMENTAL(v4a))
748  flags &= ~AI_CANONNAME;
749  v4a >>= IN_CLASSA_NSHIFT;
750  if (v4a == 0 || v4a == IN_LOOPBACKNET)
751  flags &= ~AI_CANONNAME;
752  break;
753 
754  case AF_INET6:
755  pfx = pton.a6.s6_addr[0];
756  if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
757  flags &= ~AI_CANONNAME;
758  break;
759  }
760 
761  if (pai->ai_family == afd->a_af || pai->ai_family == AF_UNSPEC)
762  {
763  if (!(flags & AI_CANONNAME))
764  {
765  GET_AI (cur->ai_next, afd, &pton);
766  GET_PORT (cur->ai_next, servname);
767  }
768  else
769  {
770  /* if AI_CANONNAME and if reverse lookup fail, return ai anyway
771  * to pacify calling application.
772  *
773  * XXX getaddrinfo() is a name to address translation function,
774  * and it looks strange that we do addr to name translation here.
775  */
776  get_name ((const char*)&pton, afd, &cur->ai_next,
777  (char*)&pton, pai, servname);
778  }
779  while (cur && cur->ai_next)
780  cur = cur->ai_next;
781  }
782  else
783  ERR (EAI_FAMILY); /* xxx */
784  }
785  *res = sentinel.ai_next;
786  return (0);
787 
788 free_it:
789 bad:
790  free_addrinfo (sentinel.ai_next);
791  return (error);
792 }
793 
794 /*
795  * numeric hostname with scope
796  */
797 static int explore_numeric_scope (const struct addrinfo *pai,
798  const char *hostname, const char *servname,
799  struct addrinfo **res)
800 {
801  const struct afd *afd;
802  struct addrinfo *cur;
803  struct sockaddr_in6 *sin6;
804  char *cp, hostname2 [MAX_HOSTLEN];
805  int error, scope = 0;
806 
807 #ifdef TEST_PROG
808  SOCK_DEBUGF (("\nexplore_numeric_scope"));
809 #endif
810 
811  /* if the servname does not match socktype/protocol, ignore it.
812  */
813  if (get_portmatch (pai, servname) != 0)
814  return (0);
815 
816  afd = find_afd (pai->ai_family);
817  if (!afd->a_scoped)
818  return explore_numeric (pai, hostname, servname, res);
819 
820  cp = strchr (hostname, SCOPE_DELIMITER);
821  if (!cp || (cp - hostname) >= SIZEOF(hostname2))
822  return explore_numeric (pai, hostname, servname, res);
823 
824  /* Handle special case of <scoped_address>%<scope id>
825  * 'scope id' is numeric "1..x".
826  */
827  _strlcpy (hostname2, hostname, sizeof(hostname2));
828 
829  /* terminate at the delimiter
830  */
831  hostname2 [cp-hostname] = '\0';
832 
833  switch (pai->ai_family)
834  {
835  case AF_INET6:
836  scope = __scope_ascii_to_id (cp+1);
837  if (scope == 0)
838  return (EAI_NONAME);
839  break;
840  }
841 
842  error = explore_numeric (pai, hostname2, servname, res);
843  if (error == 0)
844  {
845  for (cur = *res; cur; cur = cur->ai_next)
846  {
847  if (cur->ai_family != AF_INET6)
848  continue;
849 
850  sin6 = (struct sockaddr_in6*) cur->ai_addr;
851  if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
852  IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
853  sin6->sin6_scope_id = scope;
854  }
855  }
856  return (error);
857 }
858 
859 static int get_name (const char *addr, const struct afd *afd,
860  struct addrinfo **res, char *numaddr,
861  const struct addrinfo *pai, const char *servname)
862 {
863  struct hostent *hp;
864  struct addrinfo *cur = NULL;
865  int error = 0;
866 
867  SOCK_ENTER_SCOPE();
868  called_from_getai = TRUE;
869  hp = gethostbyaddr (addr, afd->a_addrlen, afd->a_af);
870  called_from_getai = FALSE;
871  SOCK_LEAVE_SCOPE();
872 
873  if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0])
874  {
875  GET_AI (cur, afd, hp->h_addr);
876  GET_PORT (cur, servname);
877  GET_CANONNAME (cur, hp->h_name);
878  }
879  else
880  {
881  GET_AI (cur, afd, numaddr);
882  GET_PORT (cur, servname);
883  }
884 
885  *res = cur;
886  return (0); /* success */
887 
888 free_it:
889  free_addrinfo (cur);
890  *res = NULL;
891  return (error);
892 }
893 
894 static int get_canonname (const struct addrinfo *pai, struct addrinfo *ai,
895  const char *str)
896 {
897  if (pai->ai_flags & AI_CANONNAME)
898  {
899  ai->ai_canonname = strdup (str);
900  if (!ai->ai_canonname)
901  return (EAI_MEMORY);
902  }
903  return (0);
904 }
905 
906 static struct addrinfo *get_ai (const struct addrinfo *pai,
907  const struct afd *afd,
908  const char *addr)
909 {
910  struct addrinfo *ai;
911  char *p;
912 
913  ai = calloc (sizeof(*ai) + afd->a_socklen, 1);
914  if (!ai)
915  return (NULL);
916 
917  *ai = *pai;
918  ai->ai_addr = (struct sockaddr*) (ai + 1);
919  ai->ai_addrlen = afd->a_socklen;
920  ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
921 
922  p = (char*)ai->ai_addr + afd->a_off;
923  memcpy (p, addr, afd->a_addrlen);
924  return (ai);
925 }
926 
927 static int get_portmatch (const struct addrinfo *ai, const char *servname)
928 {
929  /* get_port does not touch first argument. when matchonly == 1. */
930  return get_port ((struct addrinfo*)ai, servname, 1);
931 }
932 
933 static int get_port (struct addrinfo *ai, const char *servname, int matchonly)
934 {
935  struct servent *sp;
936  const char *proto;
937  WORD port;
938  BOOL allownumeric;
939 
940  if (!servname ||
941  (ai->ai_family != AF_INET && ai->ai_family != AF_INET6))
942  return (0);
943 
944  switch (ai->ai_socktype)
945  {
946  case SOCK_RAW:
947  case SOCK_PACKET:
948  return (EAI_SERVICE);
949  case SOCK_DGRAM:
950  case SOCK_STREAM:
951  case ANY:
952  allownumeric = TRUE;
953  break;
954  default:
955  return (EAI_SOCKTYPE);
956  }
957 
958  if (str_isnumber(servname))
959  {
960  if (!allownumeric)
961  return (EAI_SERVICE);
962  port = htons (ATOI(servname));
963  }
964  else
965  {
966  switch (ai->ai_socktype)
967  {
968  case SOCK_DGRAM:
969  proto = "udp";
970  break;
971  case SOCK_STREAM:
972  proto = "tcp";
973  break;
974  default:
975  proto = NULL;
976  break;
977  }
978 
979  SOCK_ENTER_SCOPE();
980  sp = getservbyname (servname, proto);
981  SOCK_LEAVE_SCOPE();
982 
983  if (!sp)
984  return (EAI_SERVICE);
985  port = sp->s_port;
986  }
987 
988  if (!matchonly)
989  {
990  switch (ai->ai_family)
991  {
992  case AF_INET:
993  ((struct sockaddr_in*)ai->ai_addr)->sin_port = port;
994  break;
995  case AF_INET6:
996  ((struct sockaddr_in6*)ai->ai_addr)->sin6_port = port;
997  break;
998  }
999  }
1000  return (0);
1001 }
1002 
1003 static const struct afd *find_afd (int af)
1004 {
1005  const struct afd *afd;
1006 
1007  if (af == AF_UNSPEC)
1008  return (NULL);
1009 
1010  for (afd = afd_list; afd->a_af; afd++)
1011  if (afd->a_af == af)
1012  return (afd);
1013  return (NULL);
1014 }
1015 
1016 #if defined(TEST_PROG)
1017 static void dump_addrinfo (const struct addrinfo *ai)
1018 {
1019  for (; ai; ai = ai->ai_next)
1020  {
1021  const struct sockaddr_in *sa4 = (const struct sockaddr_in*)ai->ai_addr;
1022  const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6*)ai->ai_addr;
1023  int af = ai->ai_family;
1024  char buf [INET6_ADDRSTRLEN];
1025 
1026  printf (" family %2d, CNAME %s, ",
1027  af, ai->ai_canonname ? ai->ai_canonname : "<none>");
1028  printf ("%s\n",
1029  af == AF_INET ? inet_ntop(af, &sa4->sin_addr, buf, sizeof(buf)) :
1030  af == AF_INET6 ? inet_ntop(af, &sa6->sin6_addr, buf, sizeof(buf)) :
1031  "??");
1032  }
1033 }
1034 
1035 static void test_getaddrinfo (const char *host, const char *serv)
1036 {
1037  struct addrinfo hints, *res = NULL;
1038  int rc;
1039 
1040  printf ("Calling: getaddrinfo (\"%s\", \"%s\",...);", host, serv);
1041  memset (&hints, 0, sizeof(hints));
1042  hints.ai_family = AF_UNSPEC;
1043  hints.ai_socktype = SOCK_STREAM;
1044  hints.ai_flags = AI_CANONNAME;
1045 
1046  rc = getaddrinfo (host, serv, &hints, &res);
1047  puts ("");
1048  if (res)
1049  dump_addrinfo (res);
1050  else printf ("fail; %s\n", gai_strerror(rc));
1051 
1052  if (res)
1053  freeaddrinfo (res);
1054 }
1055 
1056 int main (void)
1057 {
1058  dbug_init();
1059  sock_init();
1060 
1061  test_getaddrinfo ("www.kame.net", "http");
1062  test_getaddrinfo ("home.broadpark.no", "http");
1063 
1064  return (0);
1065 }
1066 #endif /* TEST_PROG */
1067 #endif /* USE_BSD_API */
1068 
Definition: get_ai.c:77
Definition: netdb.h:122
const char *W32_CALL inet_ntop(int af, const void *src, char *dst, size_t size)
Convert a network format address to presentation format.
Definition: presaddr.c:40
Definition: netdb.h:102
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
static void afd_list_init(BOOL ip6_prio)
Initialise afd_list[].
Definition: get_ai.c:273
Definition: in.h:153
Definition: in.h:146
int W32_CALL inet_pton(int af, const char *src, void *dst)
Convert from presentation format (which usually means ASCII printable) to network format (which is us...
Definition: presaddr.c:66
Definition: get_ai.c:67
int W32_CALL socket(int family, int type, int protocol)
socket().
Definition: socket.c:1794
char hostname[MAX_HOSTLEN+1]
Our configured hostname.
Definition: pctcp.c:59
int main(int argc, char **argv)
Definition: echo.c:223