Postfix3.3.1
myaddrinfo.c
[詳解]
1 /*++
2 /* NAME
3 /* myaddrinfo 3
4 /* SUMMARY
5 /* addrinfo encapsulation and emulation
6 /* SYNOPSIS
7 /* #include <myaddrinfo.h>
8 /*
9 /* #define MAI_V4ADDR_BITS ...
10 /* #define MAI_V6ADDR_BITS ...
11 /* #define MAI_V4ADDR_BYTES ...
12 /* #define MAI_V6ADDR_BYTES ...
13 /*
14 /* typedef struct { char buf[....]; } MAI_HOSTNAME_STR;
15 /* typedef struct { char buf[....]; } MAI_HOSTADDR_STR;
16 /* typedef struct { char buf[....]; } MAI_SERVNAME_STR;
17 /* typedef struct { char buf[....]; } MAI_SERVPORT_STR;
18 /*
19 /* int hostname_to_sockaddr(hostname, service, socktype, result)
20 /* const char *hostname;
21 /* const char *service;
22 /* int socktype;
23 /* struct addrinfo **result;
24 /*
25 /* int hostname_to_sockaddr_pf(hostname, pf, service, socktype, result)
26 /* const char *hostname;
27 /* int pf;
28 /* const char *service;
29 /* int socktype;
30 /* struct addrinfo **result;
31 /*
32 /* int hostaddr_to_sockaddr(hostaddr, service, socktype, result)
33 /* const char *hostaddr;
34 /* const char *service;
35 /* int socktype;
36 /* struct addrinfo **result;
37 /*
38 /* int sockaddr_to_hostaddr(sa, salen, hostaddr, portnum, socktype)
39 /* const struct sockaddr *sa;
40 /* SOCKADDR_SIZE salen;
41 /* MAI_HOSTADDR_STR *hostaddr;
42 /* MAI_SERVPORT_STR *portnum;
43 /* int socktype;
44 /*
45 /* int sockaddr_to_hostname(sa, salen, hostname, service, socktype)
46 /* const struct sockaddr *sa;
47 /* SOCKADDR_SIZE salen;
48 /* MAI_HOSTNAME_STR *hostname;
49 /* MAI_SERVNAME_STR *service;
50 /* int socktype;
51 /*
52 /* const char *MAI_STRERROR(error)
53 /* int error;
54 /* DESCRIPTION
55 /* This module provides a simplified user interface to the
56 /* getaddrinfo(3) and getnameinfo(3) routines (which provide
57 /* a unified interface to manipulate IPv4 and IPv6 socket
58 /* address structures).
59 /*
60 /* On systems without getaddrinfo(3) and getnameinfo(3) support,
61 /* emulation for IPv4 only can be enabled by defining
62 /* EMULATE_IPV4_ADDRINFO.
63 /*
64 /* hostname_to_sockaddr() looks up the binary addresses for
65 /* the specified symbolic hostname or numeric address. The
66 /* result should be destroyed with freeaddrinfo(). A null host
67 /* pointer converts to the null host address.
68 /*
69 /* hostname_to_sockaddr_pf() is an extended interface that
70 /* provides a protocol family override.
71 /*
72 /* hostaddr_to_sockaddr() converts a printable network address
73 /* into the corresponding binary form. The result should be
74 /* destroyed with freeaddrinfo(). A null host pointer converts
75 /* to the null host address.
76 /*
77 /* sockaddr_to_hostaddr() converts a binary network address
78 /* into printable form. The result buffers should be large
79 /* enough to hold the printable address or port including the
80 /* null terminator.
81 /* This function strips off the IPv6 datalink suffix.
82 /*
83 /* sockaddr_to_hostname() converts a binary network address
84 /* into a hostname or service. The result buffer should be
85 /* large enough to hold the hostname or service including the
86 /* null terminator. This routine rejects malformed hostnames
87 /* or numeric hostnames and pretends that the lookup failed.
88 /*
89 /* MAI_STRERROR() is an unsafe macro (it evaluates the argument
90 /* multiple times) that invokes strerror() or gai_strerror()
91 /* as appropriate.
92 /*
93 /* This module exports the following constants that should be
94 /* user for storage allocation of name or address information:
95 /* .IP MAI_V4ADDR_BITS
96 /* .IP MAI_V6ADDR_BITS
97 /* .IP MAI_V4ADDR_BYTES
98 /* .IP MAI_V6ADDR_BYTES
99 /* The number of bits or bytes needed to store a binary
100 /* IPv4 or IPv6 network address.
101 /* .PP
102 /* The types MAI_HOST{NAME,ADDR}_STR and MAI_SERV{NAME,PORT}_STR
103 /* implement buffers for the storage of the string representations
104 /* of symbolic or numerical hosts or services. Do not use
105 /* buffer types other than the ones that are expected here,
106 /* or things will blow up with buffer overflow problems.
107 /*
108 /* Arguments:
109 /* .IP hostname
110 /* On input to hostname_to_sockaddr(), a numeric or symbolic
111 /* hostname, or a null pointer (meaning the wild-card listen
112 /* address). On output from sockaddr_to_hostname(), storage
113 /* for the result hostname, or a null pointer.
114 /* .IP pf
115 /* Protocol type: PF_UNSPEC (meaning: use any protocol that is
116 /* available), PF_INET, or PF_INET6. This argument is ignored
117 /* in EMULATE_IPV4_ADDRINFO mode.
118 /* .IP hostaddr
119 /* On input to hostaddr_to_sockaddr(), a numeric hostname,
120 /* or a null pointer (meaning the wild-card listen address).
121 /* On output from sockaddr_to_hostaddr(), storage for the
122 /* result hostaddress, or a null pointer.
123 /* .IP service
124 /* On input to hostname/addr_to_sockaddr(), a numeric or
125 /* symbolic service name, or a null pointer in which case the
126 /* socktype argument is ignored. On output from
127 /* sockaddr_to_hostname/addr(), storage for the result service
128 /* name, or a null pointer.
129 /* .IP portnum
130 /* Storage for the result service port number, or a null pointer.
131 /* .IP socktype
132 /* Socket type: SOCK_STREAM, SOCK_DGRAM, etc. This argument is
133 /* ignored when no service or port are specified.
134 /* .IP sa
135 /* Protocol-independent socket address structure.
136 /* .IP salen
137 /* Protocol-dependent socket address structure size in bytes.
138 /* SEE ALSO
139 /* getaddrinfo(3), getnameinfo(3), freeaddrinfo(3), gai_strerror(3)
140 /* DIAGNOSTICS
141 /* All routines either return 0 upon success, or an error code
142 /* that is compatible with gai_strerror().
143 /*
144 /* On systems where addrinfo support is emulated by Postfix,
145 /* some out-of-memory errors are not reported to the caller,
146 /* but are handled by mymalloc().
147 /* BUGS
148 /* The IPv4-only emulation code does not support requests that
149 /* specify a service but no socket type. It returns an error
150 /* indication, instead of enumerating all the possible answers.
151 /*
152 /* The hostname/addr_to_sockaddr() routines should accept a
153 /* list of address families that the caller is interested in,
154 /* and they should return only information of those types.
155 /*
156 /* Unfortunately, it is not possible to remove unwanted address
157 /* family results from hostname_to_sockaddr(), because we
158 /* don't know how the system library routine getaddrinfo()
159 /* allocates memory. For example, getaddrinfo() could save
160 /* space by referencing the same string object from multiple
161 /* addrinfo structures; or it could allocate a string object
162 /* and the addrinfo structure as one memory block.
163 /*
164 /* We could get around this by copying getaddrinfo() results
165 /* to our own private data structures, but that would only
166 /* make an already expensive API even more expensive.
167 /*
168 /* A better workaround is to return a vector of addrinfo
169 /* pointers to the elements that contain only the elements
170 /* that the caller is interested in. The pointer to the
171 /* original getaddrinfo() result can be hidden at the end
172 /* after the null terminator, or before the first element.
173 /* LICENSE
174 /* .ad
175 /* .fi
176 /* The Secure Mailer license must be distributed with this software.
177 /* AUTHOR(S)
178 /* Wietse Venema
179 /* IBM T.J. Watson Research
180 /* P.O. Box 704
181 /* Yorktown Heights, NY 10598, USA
182 /*--*/
183 
184 /* System library. */
185 
186 #include <sys_defs.h>
187 #include <sys/types.h>
188 #include <sys/socket.h>
189 #include <netinet/in.h>
190 #include <arpa/inet.h>
191 #include <netdb.h>
192 #include <string.h>
193 #include <errno.h>
194 #include <stdlib.h>
195 #include <stdio.h> /* sprintf() */
196 
197 /* Utility library. */
198 
199 #include <mymalloc.h>
200 #include <valid_hostname.h>
201 #include <sock_addr.h>
202 #include <stringops.h>
203 #include <msg.h>
204 #include <inet_proto.h>
205 #include <myaddrinfo.h>
206 #include <split_at.h>
207 
208 /* Application-specific. */
209 
210  /*
211  * Use an old trick to save some space: allocate space for two objects in
212  * one. In Postfix we often use this trick for structures that have an array
213  * of things at the end.
214  */
215 struct ipv4addrinfo {
216  struct addrinfo info;
217  struct sockaddr_in sin;
218 };
219 
220  /*
221  * When we're not interested in service ports, we must pick a socket type
222  * otherwise getaddrinfo() will give us duplicate results: one set for TCP,
223  * and another set for UDP. For consistency, we'll use the same default
224  * socket type for the results from emulation mode.
225  */
226 #define MAI_SOCKTYPE SOCK_STREAM /* getaddrinfo() query */
227 
228 #ifdef EMULATE_IPV4_ADDRINFO
229 
230 /* clone_ipv4addrinfo - clone ipv4addrinfo structure */
231 
232 static struct ipv4addrinfo *clone_ipv4addrinfo(struct ipv4addrinfo * tp)
233 {
234  struct ipv4addrinfo *ip;
235 
236  ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
237  *ip = *tp;
238  ip->info.ai_addr = (struct sockaddr *) &(ip->sin);
239  return (ip);
240 }
241 
242 /* init_ipv4addrinfo - initialize an ipv4addrinfo structure */
243 
244 static void init_ipv4addrinfo(struct ipv4addrinfo * ip, int socktype)
245 {
246 
247  /*
248  * Portability: null pointers aren't necessarily all-zero bits, so we
249  * make explicit assignments to all the pointers that we're aware of.
250  */
251  memset((void *) ip, 0, sizeof(*ip));
252  ip->info.ai_family = PF_INET;
253  ip->info.ai_socktype = socktype;
254  ip->info.ai_protocol = 0; /* XXX */
255  ip->info.ai_addrlen = sizeof(ip->sin);
256  ip->info.ai_canonname = 0;
257  ip->info.ai_addr = (struct sockaddr *) &(ip->sin);
258  ip->info.ai_next = 0;
259  ip->sin.sin_family = AF_INET;
260 #ifdef HAS_SA_LEN
261  ip->sin.sin_len = sizeof(ip->sin);
262 #endif
263 }
264 
265 /* find_service - translate numeric or symbolic service name */
266 
267 static int find_service(const char *service, int socktype)
268 {
269  struct servent *sp;
270  const char *proto;
271  unsigned port;
272 
273  if (alldig(service)) {
274  port = atoi(service);
275  return (port < 65536 ? htons(port) : -1);
276  }
277  if (socktype == SOCK_STREAM) {
278  proto = "tcp";
279  } else if (socktype == SOCK_DGRAM) {
280  proto = "udp";
281  } else {
282  return (-1);
283  }
284  if ((sp = getservbyname(service, proto)) != 0) {
285  return (sp->s_port);
286  } else {
287  return (-1);
288  }
289 }
290 
291 #endif
292 
293 /* hostname_to_sockaddr_pf - hostname to binary address form */
294 
295 int hostname_to_sockaddr_pf(const char *hostname, int pf,
296  const char *service, int socktype,
297  struct addrinfo ** res)
298 {
299 #ifdef EMULATE_IPV4_ADDRINFO
300 
301  /*
302  * Emulated getaddrinfo(3) version.
303  */
304  static struct ipv4addrinfo template;
305  struct ipv4addrinfo *ip;
306  struct ipv4addrinfo *prev;
307  struct in_addr addr;
308  struct hostent *hp;
309  char **name_list;
310  int port;
311 
312  /*
313  * Validate the service.
314  */
315  if (service) {
316  if ((port = find_service(service, socktype)) < 0)
317  return (EAI_SERVICE);
318  } else {
319  port = 0;
320  socktype = MAI_SOCKTYPE;
321  }
322 
323  /*
324  * No host means INADDR_ANY.
325  */
326  if (hostname == 0) {
327  ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
328  init_ipv4addrinfo(ip, socktype);
329  ip->sin.sin_addr.s_addr = INADDR_ANY;
330  ip->sin.sin_port = port;
331  *res = &(ip->info);
332  return (0);
333  }
334 
335  /*
336  * Numeric host.
337  */
338  if (inet_pton(AF_INET, hostname, (void *) &addr) == 1) {
339  ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
340  init_ipv4addrinfo(ip, socktype);
341  ip->sin.sin_addr = addr;
342  ip->sin.sin_port = port;
343  *res = &(ip->info);
344  return (0);
345  }
346 
347  /*
348  * Look up the IPv4 address list.
349  */
350  if ((hp = gethostbyname(hostname)) == 0)
351  return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NODATA);
352  if (hp->h_addrtype != AF_INET
353  || hp->h_length != sizeof(template.sin.sin_addr))
354  return (EAI_NODATA);
355 
356  /*
357  * Initialize the result template.
358  */
359  if (template.info.ai_addrlen == 0)
360  init_ipv4addrinfo(&template, socktype);
361 
362  /*
363  * Copy the address information into an addrinfo structure.
364  */
365  prev = &template;
366  for (name_list = hp->h_addr_list; name_list[0]; name_list++) {
367  ip = clone_ipv4addrinfo(prev);
368  ip->sin.sin_addr = IN_ADDR(name_list[0]);
369  ip->sin.sin_port = port;
370  if (prev == &template)
371  *res = &(ip->info);
372  else
373  prev->info.ai_next = &(ip->info);
374  prev = ip;
375  }
376  return (0);
377 #else
378 
379  /*
380  * Native getaddrinfo(3) version.
381  *
382  * XXX Wild-card listener issues.
383  *
384  * With most IPv4 plus IPv6 systems, an IPv6 wild-card listener also listens
385  * on the IPv4 wild-card address. Connections from IPv4 clients appear as
386  * IPv4-in-IPv6 addresses; when Postfix support for IPv4 is turned on,
387  * Postfix automatically maps these embedded addresses to their original
388  * IPv4 form. So everything seems to be fine.
389  *
390  * However, some applications prefer to use separate listener sockets for
391  * IPv4 and IPv6. The Postfix IPv6 patch provided such an example. And
392  * this is where things become tricky. On many systems the IPv6 and IPv4
393  * wild-card listeners cannot coexist. When one is already active, the
394  * other fails with EADDRINUSE. Solaris 9, however, will automagically
395  * "do the right thing" and allow both listeners to coexist.
396  *
397  * Recent systems have the IPV6_V6ONLY feature (RFC 3493), which tells the
398  * system that we really mean IPv6 when we say IPv6. This allows us to
399  * set up separate wild-card listener sockets for IPv4 and IPv6. So
400  * everything seems to be fine again.
401  *
402  * The following workaround disables the wild-card IPv4 listener when
403  * IPV6_V6ONLY is unavailable. This is necessary for some Linux versions,
404  * but is not needed for Solaris 9 (which allows IPv4 and IPv6 wild-card
405  * listeners to coexist). Solaris 10 beta already has IPV6_V6ONLY.
406  *
407  * XXX This workaround obviously breaks if we want to support protocols in
408  * addition to IPv6 and IPv4, but it is needed only until IPv6
409  * implementations catch up with RFC 3493. A nicer fix is to filter the
410  * getaddrinfo() result, and to return a vector of addrinfo pointers to
411  * only those types of elements that the caller has expressed interested
412  * in.
413  *
414  * XXX Vanilla AIX 5.1 getaddrinfo() does not support a null hostname with
415  * AI_PASSIVE. And since we don't know how getaddrinfo() manages its
416  * memory we can't bypass it for this special case, or freeaddrinfo()
417  * might blow up. Instead we turn off IPV6_V6ONLY in inet_listen(), and
418  * supply a protocol-dependent hard-coded string value to getaddrinfo()
419  * below, so that it will convert into the appropriate wild-card address.
420  *
421  * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null
422  * service argument is specified.
423  */
424  struct addrinfo hints;
425  int err;
426 
427  memset((void *) &hints, 0, sizeof(hints));
428  hints.ai_family = (pf != PF_UNSPEC) ? pf : inet_proto_info()->ai_family;
429  hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
430  if (!hostname) {
431  hints.ai_flags = AI_PASSIVE;
432 #if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
433  switch (hints.ai_family) {
434  case PF_UNSPEC:
435  hints.ai_family = PF_INET6;
436 #ifdef BROKEN_AI_PASSIVE_NULL_HOST
437  case PF_INET6:
438  hostname = "::";
439  break;
440  case PF_INET:
441  hostname = "0.0.0.0";
442  break;
443 #endif
444  }
445 #endif
446  }
447  err = getaddrinfo(hostname, service, &hints, res);
448 #if defined(BROKEN_AI_NULL_SERVICE)
449  if (service == 0 && err == 0) {
450  struct addrinfo *r;
451  unsigned short *portp;
452 
453  for (r = *res; r != 0; r = r->ai_next)
454  if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0)
455  *portp = 0;
456  }
457 #endif
458  return (err);
459 #endif
460 }
461 
462 /* hostaddr_to_sockaddr - printable address to binary address form */
463 
464 int hostaddr_to_sockaddr(const char *hostaddr, const char *service,
465  int socktype, struct addrinfo ** res)
466 {
467 #ifdef EMULATE_IPV4_ADDRINFO
468 
469  /*
470  * Emulated getaddrinfo(3) version.
471  */
472  struct ipv4addrinfo *ip;
473  struct in_addr addr;
474  int port;
475 
476  /*
477  * Validate the service.
478  */
479  if (service) {
480  if ((port = find_service(service, socktype)) < 0)
481  return (EAI_SERVICE);
482  } else {
483  port = 0;
484  socktype = MAI_SOCKTYPE;
485  }
486 
487  /*
488  * No host means INADDR_ANY.
489  */
490  if (hostaddr == 0) {
491  ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
492  init_ipv4addrinfo(ip, socktype);
493  ip->sin.sin_addr.s_addr = INADDR_ANY;
494  ip->sin.sin_port = port;
495  *res = &(ip->info);
496  return (0);
497  }
498 
499  /*
500  * Deal with bad address forms.
501  */
502  switch (inet_pton(AF_INET, hostaddr, (void *) &addr)) {
503  case 1: /* Success */
504  break;
505  default: /* Unparsable */
506  return (EAI_NONAME);
507  case -1: /* See errno */
508  return (EAI_SYSTEM);
509  }
510 
511  /*
512  * Initialize the result structure.
513  */
514  ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
515  init_ipv4addrinfo(ip, socktype);
516 
517  /*
518  * And copy the result.
519  */
520  ip->sin.sin_addr = addr;
521  ip->sin.sin_port = port;
522  *res = &(ip->info);
523 
524  return (0);
525 #else
526 
527  /*
528  * Native getaddrinfo(3) version. See comments in hostname_to_sockaddr().
529  *
530  * XXX Vanilla AIX 5.1 getaddrinfo() returns multiple results when
531  * converting a printable ipv4 or ipv6 address to socket address with
532  * ai_family=PF_UNSPEC, ai_flags=AI_NUMERICHOST, ai_socktype=SOCK_STREAM,
533  * ai_protocol=0 or IPPROTO_TCP, and service=0. The workaround is to
534  * ignore all but the first result.
535  *
536  * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null
537  * service argument is specified.
538  */
539  struct addrinfo hints;
540  int err;
541 
542  memset(&hints, 0, sizeof(hints));
543  hints.ai_family = inet_proto_info()->ai_family;
544  hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
545  hints.ai_flags = AI_NUMERICHOST;
546  if (!hostaddr) {
547  hints.ai_flags |= AI_PASSIVE;
548 #if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
549  switch (hints.ai_family) {
550  case PF_UNSPEC:
551  hints.ai_family = PF_INET6;
552 #ifdef BROKEN_AI_PASSIVE_NULL_HOST
553  case PF_INET6:
554  hostaddr = "::";
555  break;
556  case PF_INET:
557  hostaddr = "0.0.0.0";
558  break;
559 #endif
560  }
561 #endif
562  }
563  err = getaddrinfo(hostaddr, service, &hints, res);
564 #if defined(BROKEN_AI_NULL_SERVICE)
565  if (service == 0 && err == 0) {
566  struct addrinfo *r;
567  unsigned short *portp;
568 
569  for (r = *res; r != 0; r = r->ai_next)
570  if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0)
571  *portp = 0;
572  }
573 #endif
574  return (err);
575 #endif
576 }
577 
578 /* sockaddr_to_hostaddr - binary address to printable address form */
579 
580 int sockaddr_to_hostaddr(const struct sockaddr *sa, SOCKADDR_SIZE salen,
581  MAI_HOSTADDR_STR *hostaddr,
582  MAI_SERVPORT_STR *portnum,
583  int unused_socktype)
584 {
585 #ifdef EMULATE_IPV4_ADDRINFO
586  char portbuf[sizeof("65535")];
587  ssize_t len;
588 
589  /*
590  * Emulated getnameinfo(3) version. The buffer length includes the space
591  * for the null terminator.
592  */
593  if (sa->sa_family != AF_INET) {
594  errno = EAFNOSUPPORT;
595  return (EAI_SYSTEM);
596  }
597  if (hostaddr != 0) {
598  if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)),
599  hostaddr->buf, sizeof(hostaddr->buf)) == 0)
600  return (EAI_SYSTEM);
601  }
602  if (portnum != 0) {
603  sprintf(portbuf, "%d", ntohs(SOCK_ADDR_IN_PORT(sa)) & 0xffff);
604  if ((len = strlen(portbuf)) >= sizeof(portnum->buf)) {
605  errno = ENOSPC;
606  return (EAI_SYSTEM);
607  }
608  memcpy(portnum->buf, portbuf, len + 1);
609  }
610  return (0);
611 #else
612  int ret;
613 
614  /*
615  * Native getnameinfo(3) version.
616  */
617  ret = getnameinfo(sa, salen,
618  hostaddr ? hostaddr->buf : (char *) 0,
619  hostaddr ? sizeof(hostaddr->buf) : 0,
620  portnum ? portnum->buf : (char *) 0,
621  portnum ? sizeof(portnum->buf) : 0,
622  NI_NUMERICHOST | NI_NUMERICSERV);
623  if (hostaddr != 0 && ret == 0 && sa->sa_family == AF_INET6)
624  (void) split_at(hostaddr->buf, '%');
625  return (ret);
626 #endif
627 }
628 
629 /* sockaddr_to_hostname - binary address to printable hostname */
630 
631 int sockaddr_to_hostname(const struct sockaddr *sa, SOCKADDR_SIZE salen,
632  MAI_HOSTNAME_STR *hostname,
633  MAI_SERVNAME_STR *service,
634  int socktype)
635 {
636 #ifdef EMULATE_IPV4_ADDRINFO
637 
638  /*
639  * Emulated getnameinfo(3) version.
640  */
641  struct hostent *hp;
642  struct servent *sp;
643  size_t len;
644 
645  /*
646  * Sanity check.
647  */
648  if (sa->sa_family != AF_INET)
649  return (EAI_NODATA);
650 
651  /*
652  * Look up the host name.
653  */
654  if (hostname != 0) {
655  if ((hp = gethostbyaddr((char *) &(SOCK_ADDR_IN_ADDR(sa)),
656  sizeof(SOCK_ADDR_IN_ADDR(sa)),
657  AF_INET)) == 0)
658  return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NONAME);
659 
660  /*
661  * Save the result. The buffer length includes the space for the null
662  * terminator. Hostname sanity checks are at the end of this
663  * function.
664  */
665  if ((len = strlen(hp->h_name)) >= sizeof(hostname->buf)) {
666  errno = ENOSPC;
667  return (EAI_SYSTEM);
668  }
669  memcpy(hostname->buf, hp->h_name, len + 1);
670  }
671 
672  /*
673  * Look up the service.
674  */
675  if (service != 0) {
676  if ((sp = getservbyport(ntohs(SOCK_ADDR_IN_PORT(sa)),
677  socktype == SOCK_DGRAM ? "udp" : "tcp")) == 0)
678  return (EAI_NONAME);
679 
680  /*
681  * Save the result. The buffer length includes the space for the null
682  * terminator.
683  */
684  if ((len = strlen(sp->s_name)) >= sizeof(service->buf)) {
685  errno = ENOSPC;
686  return (EAI_SYSTEM);
687  }
688  memcpy(service->buf, sp->s_name, len + 1);
689  }
690 #else
691 
692  /*
693  * Native getnameinfo(3) version.
694  */
695  int err;
696 
697  err = getnameinfo(sa, salen,
698  hostname ? hostname->buf : (char *) 0,
699  hostname ? sizeof(hostname->buf) : 0,
700  service ? service->buf : (char *) 0,
701  service ? sizeof(service->buf) : 0,
702  socktype == SOCK_DGRAM ?
703  NI_NAMEREQD | NI_DGRAM : NI_NAMEREQD);
704  if (err != 0)
705  return (err);
706 #endif
707 
708  /*
709  * Hostname sanity checks.
710  */
711  if (hostname != 0) {
712  if (valid_hostaddr(hostname->buf, DONT_GRIPE)) {
713  msg_warn("numeric hostname: %s", hostname->buf);
714  return (EAI_NONAME);
715  }
716  if (!valid_hostname(hostname->buf, DO_GRIPE))
717  return (EAI_NONAME);
718  }
719  return (0);
720 }
721 
722 /* myaddrinfo_control - fine control */
723 
724 void myaddrinfo_control(int name,...)
725 {
726  const char *myname = "myaddrinfo_control";
727  va_list ap;
728 
729  for (va_start(ap, name); name != 0; name = va_arg(ap, int)) {
730  switch (name) {
731  default:
732  msg_panic("%s: bad name %d", myname, name);
733  }
734  }
735  va_end(ap);
736 }
737 
738 #ifdef EMULATE_IPV4_ADDRINFO
739 
740 /* freeaddrinfo - release storage */
741 
742 void freeaddrinfo(struct addrinfo * ai)
743 {
744  struct addrinfo *ap;
745  struct addrinfo *next;
746 
747  /*
748  * Artefact of implementation: tolerate a null pointer argument.
749  */
750  for (ap = ai; ap != 0; ap = next) {
751  next = ap->ai_next;
752  if (ap->ai_canonname)
753  myfree(ap->ai_canonname);
754  /* ap->ai_addr is allocated within this memory block */
755  myfree((void *) ap);
756  }
757 }
758 
759 static char *ai_errlist[] = {
760  "Success",
761  "Address family for hostname not supported", /* EAI_ADDRFAMILY */
762  "Temporary failure in name resolution", /* EAI_AGAIN */
763  "Invalid value for ai_flags", /* EAI_BADFLAGS */
764  "Non-recoverable failure in name resolution", /* EAI_FAIL */
765  "ai_family not supported", /* EAI_FAMILY */
766  "Memory allocation failure", /* EAI_MEMORY */
767  "No address associated with hostname", /* EAI_NODATA */
768  "hostname nor servname provided, or not known", /* EAI_NONAME */
769  "service name not supported for ai_socktype", /* EAI_SERVICE */
770  "ai_socktype not supported", /* EAI_SOCKTYPE */
771  "System error returned in errno", /* EAI_SYSTEM */
772  "Invalid value for hints", /* EAI_BADHINTS */
773  "Resolved protocol is unknown", /* EAI_PROTOCOL */
774  "Unknown error", /* EAI_MAX */
775 };
776 
777 /* gai_strerror - error number to string */
778 
779 char *gai_strerror(int ecode)
780 {
781 
782  /*
783  * Note: EAI_SYSTEM errors are not automatically handed over to
784  * strerror(). The application decides.
785  */
786  if (ecode < 0 || ecode > EAI_MAX)
787  ecode = EAI_MAX;
788  return (ai_errlist[ecode]);
789 }
790 
791 #endif
792 
793 #ifdef TEST
794 
795  /*
796  * A test program that takes some info from the command line and runs it
797  * forward and backward through the above conversion routines.
798  */
799 #include <stdlib.h>
800 #include <msg.h>
801 #include <vstream.h>
802 #include <msg_vstream.h>
803 
804 static int compare_family(const void *a, const void *b)
805 {
806  struct addrinfo *resa = *(struct addrinfo **) a;
807  struct addrinfo *resb = *(struct addrinfo **) b;
808 
809  return (resa->ai_family - resb->ai_family);
810 }
811 
812 int main(int argc, char **argv)
813 {
814  struct addrinfo *info;
815  struct addrinfo *ip;
816  struct addrinfo **resv;
817  MAI_HOSTNAME_STR host;
818  MAI_HOSTADDR_STR addr;
819  size_t len, n;
820  int err;
821 
822  msg_vstream_init(argv[0], VSTREAM_ERR);
823 
824  if (argc != 4)
825  msg_fatal("usage: %s protocols hostname hostaddress", argv[0]);
826 
827  inet_proto_init(argv[0], argv[1]);
828 
829  msg_info("=== hostname %s ===", argv[2]);
830 
831  if ((err = hostname_to_sockaddr(argv[2], (char *) 0, 0, &info)) != 0) {
832  msg_info("hostname_to_sockaddr(%s): %s",
833  argv[2], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
834  } else {
835  for (len = 0, ip = info; ip != 0; ip = ip->ai_next)
836  len += 1;
837  resv = (struct addrinfo **) mymalloc(len * sizeof(*resv));
838  for (len = 0, ip = info; ip != 0; ip = ip->ai_next)
839  resv[len++] = ip;
840  qsort((void *) resv, len, sizeof(*resv), compare_family);
841  for (n = 0; n < len; n++) {
842  ip = resv[n];
843  if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
844  (MAI_SERVPORT_STR *) 0, 0)) != 0) {
845  msg_info("sockaddr_to_hostaddr: %s",
846  err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
847  continue;
848  }
849  msg_info("%s -> family=%d sock=%d proto=%d %s", argv[2],
850  ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf);
851  if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
852  (MAI_SERVNAME_STR *) 0, 0)) != 0) {
853  msg_info("sockaddr_to_hostname: %s",
854  err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
855  continue;
856  }
857  msg_info("%s -> %s", addr.buf, host.buf);
858  }
859  freeaddrinfo(info);
860  myfree((void *) resv);
861  }
862 
863  msg_info("=== host address %s ===", argv[3]);
864 
865  if ((err = hostaddr_to_sockaddr(argv[3], (char *) 0, 0, &ip)) != 0) {
866  msg_info("hostaddr_to_sockaddr(%s): %s",
867  argv[3], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
868  } else {
869  if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
870  (MAI_SERVPORT_STR *) 0, 0)) != 0) {
871  msg_info("sockaddr_to_hostaddr: %s",
872  err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
873  } else {
874  msg_info("%s -> family=%d sock=%d proto=%d %s", argv[3],
875  ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf);
876  if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
877  (MAI_SERVNAME_STR *) 0, 0)) != 0) {
878  msg_info("sockaddr_to_hostname: %s",
879  err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
880  } else
881  msg_info("%s -> %s", addr.buf, host.buf);
882  freeaddrinfo(ip);
883  }
884  }
885  exit(0);
886 }
887 
888 #endif
#define IN_ADDR(ia)
Definition: sock_addr.h:34
int valid_hostaddr(const char *addr, int gripe)
void myfree(void *ptr)
Definition: mymalloc.c:207
#define SOCK_ADDR_PORTP(sa)
Definition: sock_addr.h:82
void freeaddrinfo(struct addrinfo *ai)
Definition: myaddrinfo.c:742
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define inet_proto_info()
Definition: inet_proto.h:29
int main(int argc, char **argv)
Definition: anvil.c:1010
INET_PROTO_INFO * inet_proto_init(const char *context, const char *protocols)
Definition: inet_proto.c:180
#define hostname_to_sockaddr(host, serv, sock, res)
Definition: myaddrinfo.h:171
int alldig(const char *string)
Definition: alldig.c:38
int hostaddr_to_sockaddr(const char *hostaddr, const char *service, int socktype, struct addrinfo **res)
Definition: myaddrinfo.c:464
int sockaddr_to_hostaddr(const struct sockaddr *sa, SOCKADDR_SIZE salen, MAI_HOSTADDR_STR *hostaddr, MAI_SERVPORT_STR *portnum, int unused_socktype)
Definition: myaddrinfo.c:580
#define SOCKADDR_SIZE
Definition: sys_defs.h:1411
int valid_hostname(const char *name, int gripe)
char buf[MAI_HOSTADDR_STRSIZE]
Definition: myaddrinfo.h:146
char buf[MAI_SERVNAME_STRSIZE]
Definition: myaddrinfo.h:150
const char * inet_ntop(int af, const void *src, char *dst, SOCKADDR_SIZE size)
Definition: sys_compat.c:325
int hostname_to_sockaddr_pf(const char *hostname, int pf, const char *service, int socktype, struct addrinfo **res)
Definition: myaddrinfo.c:295
void msg_warn(const char *fmt,...)
Definition: msg.c:215
int inet_pton(int af, const char *src, void *dst)
Definition: sys_compat.c:368
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
struct addrinfo info
Definition: myaddrinfo.c:216
#define MAI_SOCKTYPE
Definition: myaddrinfo.c:226
char buf[MAI_HOSTNAME_STRSIZE]
Definition: myaddrinfo.h:142
#define DO_GRIPE
Definition: haproxy_srvr.h:30
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
char buf[MAI_SERVPORT_STRSIZE]
Definition: myaddrinfo.h:154
#define SOCK_ADDR_IN_ADDR(sa)
Definition: sock_addr.h:33
struct sockaddr_in sin
Definition: myaddrinfo.c:217
int sockaddr_to_hostname(const struct sockaddr *sa, SOCKADDR_SIZE salen, MAI_HOSTNAME_STR *hostname, MAI_SERVNAME_STR *service, int socktype)
Definition: myaddrinfo.c:631
#define SOCK_ADDR_IN_PORT(sa)
Definition: sock_addr.h:32
#define VSTREAM_ERR
Definition: vstream.h:68
char * gai_strerror(int ecode)
Definition: myaddrinfo.c:779
void myaddrinfo_control(int name,...)
Definition: myaddrinfo.c:724
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define DONT_GRIPE
Definition: haproxy_srvr.h:31
void msg_info(const char *fmt,...)
Definition: msg.c:199