getaddrinfo.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /*
10  * Shamelessly duplicated from the fetchmail public sources
11  * for use by the Squid Project under GNU Public License.
12  *
13  * Update/Maintenance History:
14  *
15  * 15-Aug-2007 : Copied from fetchmail 6.3.8
16  * - added protection around library headers
17  *
18  * 16-Aug-2007 : Altered configure checks
19  * Un-hacked slightly to use system gethostbyname()
20  *
21  * 06-Oct-2007 : Various fixes to allow the build on MinGW
22  *
23  * 13-Jan-2015 : Various fixed for C++ and MinGW native build
24  *
25  * Original License and code follows.
26  */
27 #include "squid.h"
28 
29 /*
30  * This file is part of libESMTP, a library for submission of RFC 2822
31  * formatted electronic mail messages using the SMTP protocol described
32  * in RFC 2821.
33  *
34  * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
35  *
36  * This library is free software; you can redistribute it and/or
37  * modify it under the terms of the GNU Lesser General Public
38  * License as published by the Free Software Foundation; either
39  * version 2.1 of the License, or (at your option) any later version.
40  *
41  * This library is distributed in the hope that it will be useful,
42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44  * Lesser General Public License for more details.
45  *
46  * You should have received a copy of the GNU Lesser General Public
47  * License along with this library; if not, write to the Free Software
48  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
49  */
50 
51 /* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface.
52  */
53 
54 #if !HAVE_DECL_GETADDRINFO
55 
56 /* Need to turn off Posix features in glibc to build this */
57 #undef _POSIX_C_SOURCE
58 #undef _XOPEN_SOURCE
59 
60 #if HAVE_STRING_H
61 #include <string.h>
62 #endif
63 #if HAVE_CTYPE_H
64 #include <ctype.h>
65 #endif
66 #if HAVE_ERRNO_H
67 #include <errno.h>
68 #endif
69 #if HAVE_SYS_SOCKET_H
70 #include <sys/socket.h>
71 #endif
72 #if HAVE_NETINET_IN_H
73 #include <netinet/in.h>
74 #endif
75 #if HAVE_ARPA_INET_H
76 #include <arpa/inet.h>
77 #endif
78 #if HAVE_NETDB_H
79 #include <netdb.h>
80 #endif
81 
82 static struct addrinfo *
83 dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen) {
84  struct addrinfo *ret;
85 
86  ret = (struct addrinfo *)malloc(sizeof (struct addrinfo));
87  if (!ret)
88  return nullptr;
89  memcpy (ret, info, sizeof (struct addrinfo));
90  ret->ai_addr = (struct sockaddr*)malloc(addrlen);
91  if (!ret->ai_addr) {
92  free (ret);
93  return nullptr;
94  }
95  memcpy (ret->ai_addr, addr, addrlen);
96  ret->ai_addrlen = addrlen;
97  return ret;
98 }
99 
100 int
101 xgetaddrinfo (const char *nodename, const char *servname,
102  const struct addrinfo *hints, struct addrinfo **res)
103 {
104  struct hostent *hp;
105  struct servent *servent;
106  const char *socktype;
107  int port;
108  struct addrinfo hint, result;
109  struct addrinfo *ai, *sai, *eai;
110  char **addrs;
111 
112  if (!servname && !nodename)
113  return EAI_NONAME;
114 
115  memset (&result, 0, sizeof result);
116 
117  /* default for hints */
118  if (!hints) {
119  memset (&hint, 0, sizeof hint);
120  hint.ai_family = PF_UNSPEC;
121  hints = &hint;
122  }
123 
124  if (!servname)
125  port = 0;
126  else {
127  /* check for tcp or udp sockets only */
128  if (hints->ai_socktype == SOCK_STREAM)
129  socktype = "tcp";
130  else if (hints->ai_socktype == SOCK_DGRAM)
131  socktype = "udp";
132  else
133  return EAI_SERVICE;
134  result.ai_socktype = hints->ai_socktype;
135 
136  /* Note: maintain port in host byte order to make debugging easier */
137  if (isdigit (*servname))
138  port = strtol (servname, nullptr, 10);
139  else if ((servent = getservbyname (servname, socktype)))
140  port = ntohs (servent->s_port);
141  else
142  return EAI_NONAME;
143  }
144 
145  /* if !nodename, refer to the local host for a client or any
146  for a server */
147  if (!nodename) {
148  struct sockaddr_in sin;
149 
150  /* check protocol family is PF_UNSPEC or PF_INET - could try harder
151  for IPv6 but that's more code than I'm prepared to write */
152  if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
153  result.ai_family = AF_INET;
154  else
155  return EAI_FAMILY;
156 
157  sin.sin_family = result.ai_family;
158  sin.sin_port = htons (port);
159  if (hints->ai_flags & AI_PASSIVE)
160  sin.sin_addr.s_addr = htonl (INADDR_ANY);
161  else
162  sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
163  /* Duplicate result and addr and return */
164  *res = dup_addrinfo (&result, &sin, sizeof sin);
165  return (!*res) ? EAI_MEMORY : 0;
166  }
167 
168  /* If AI_NUMERIC is specified, use inet_pton to translate numbers and
169  dots notation. */
170  if (hints->ai_flags & AI_NUMERICHOST) {
171  struct sockaddr_in sin;
172 
173  /* check protocol family is PF_UNSPEC or PF_INET */
174  if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
175  result.ai_family = AF_INET;
176  else
177  return EAI_FAMILY;
178 
179  sin.sin_family = result.ai_family;
180  sin.sin_port = htons (port);
181  if (inet_pton(result.ai_family, nodename, &sin.sin_addr) != 1)
182  return EAI_NONAME;
183  sin.sin_addr.s_addr = inet_addr (nodename);
184  /* Duplicate result and addr and return */
185  *res = dup_addrinfo (&result, &sin, sizeof sin);
186  return (!*res) ? EAI_MEMORY : 0;
187  }
188 
189 #if HAVE_H_ERRNO
190  h_errno = 0;
191 #endif
192  errno = 0;
193  hp = gethostbyname(nodename);
194  if (!hp) {
195 #ifdef EAI_SYSTEM
196  if (errno != 0) {
197  return EAI_SYSTEM;
198  }
199 #endif
200  switch (h_errno) {
201  case HOST_NOT_FOUND:
202  return EAI_NODATA;
203  case NO_DATA:
204  return EAI_NODATA;
205 #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
206  case NO_ADDRESS:
207  return EAI_NODATA;
208 #endif
209  case NO_RECOVERY:
210  return EAI_FAIL;
211  case TRY_AGAIN:
212  return EAI_AGAIN;
213  default:
214  return EAI_FAIL;
215  }
216  return EAI_FAIL;
217  }
218 
219  /* Check that the address family is acceptable.
220  */
221  switch (hp->h_addrtype) {
222  case AF_INET:
223  if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET))
224  return EAI_FAMILY;
225  break;
226  case AF_INET6:
227  if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6))
228  return EAI_FAMILY;
229  break;
230  default:
231  return EAI_FAMILY;
232  }
233 
234  /* For each element pointed to by hp, create an element in the
235  result linked list. */
236  sai = eai = nullptr;
237  for (addrs = hp->h_addr_list; *addrs; addrs++) {
238  struct sockaddr sa;
239  size_t addrlen;
240 
241  if (hp->h_length < 1)
242  continue;
243  sa.sa_family = hp->h_addrtype;
244  switch (hp->h_addrtype) {
245  case AF_INET:
246  ((struct sockaddr_in *) &sa)->sin_port = htons (port);
247  memcpy (&((struct sockaddr_in *) &sa)->sin_addr,
248  *addrs, hp->h_length);
249  addrlen = sizeof (struct sockaddr_in);
250  break;
251  case AF_INET6:
252 #if SIN6_LEN
253  ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length;
254 #endif
255  ((struct sockaddr_in6 *) &sa)->sin6_port = htons (port);
256  memcpy (&((struct sockaddr_in6 *) &sa)->sin6_addr,
257  *addrs, hp->h_length);
258  addrlen = sizeof (struct sockaddr_in6);
259  break;
260  default:
261  continue;
262  }
263 
264  result.ai_family = hp->h_addrtype;
265  ai = dup_addrinfo (&result, &sa, addrlen);
266  if (!ai) {
267  xfreeaddrinfo (sai);
268  return EAI_MEMORY;
269  }
270  if (!sai)
271  sai = ai;
272  else
273  eai->ai_next = ai;
274  eai = ai;
275  }
276 
277  if (!sai) {
278  return EAI_NODATA;
279  }
280 
281  if (hints->ai_flags & AI_CANONNAME) {
282  sai->ai_canonname = (char *)malloc(strlen(hp->h_name) + 1);
283  if (!sai->ai_canonname) {
284  xfreeaddrinfo (sai);
285  return EAI_MEMORY;
286  }
287  strcpy (sai->ai_canonname, hp->h_name);
288  }
289 
290  *res = sai;
291  return 0;
292 }
293 
294 void
296 {
297  struct addrinfo *next;
298 
299  while (ai) {
300  next = ai->ai_next;
301  if (ai->ai_canonname)
302  free (ai->ai_canonname);
303  if (ai->ai_addr)
304  free (ai->ai_addr);
305  free (ai);
306  ai = next;
307  }
308 }
309 
310 const char *
311 xgai_strerror (int ecode)
312 {
313  static const char *eai_descr[] = {
314  "no error",
315  "address family for nodename not supported", /* EAI_ADDRFAMILY */
316  "temporary failure in name resolution", /* EAI_AGAIN */
317  "invalid value for ai_flags", /* EAI_BADFLAGS */
318  "non-recoverable failure in name resolution", /* EAI_FAIL */
319  "ai_family not supported", /* EAI_FAMILY */
320  "memory allocation failure", /* EAI_MEMORY */
321  "no address associated with nodename", /* EAI_NODATA */
322  "nodename nor servname provided, or not known", /* EAI_NONAME */
323  "servname not supported for ai_socktype", /* EAI_SERVICE */
324  "ai_socktype not supported", /* EAI_SOCKTYPE */
325  "system error returned in errno", /* EAI_SYSTEM */
326  "argument buffer overflow", /* EAI_OVERFLOW */
327  };
328 
329  if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0]))
330  return "unknown error";
331  return eai_descr[ecode];
332 }
333 
334 #endif /* HAVE_DECL_GETADDRINFO */
335 
static int port
Definition: ldap_backend.cc:70
int xgetaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
Definition: getaddrinfo.cc:101
void xfreeaddrinfo(struct addrinfo *ai)
Definition: getaddrinfo.cc:295
static struct addrinfo * dup_addrinfo(struct addrinfo *info, void *addr, size_t addrlen)
Definition: getaddrinfo.cc:83
const char * xgai_strerror(int ecode)
Definition: getaddrinfo.cc:311
#define EAI_SYSTEM
Definition: getaddrinfo.h:56
#define inet_pton
Definition: inet_pton.h:28
#define EAI_NONAME
#define EAI_FAMILY
int h_errno
#define AI_NUMERICHOST
#define EAI_MEMORY
#define NO_DATA
#define EAI_AGAIN
#define NO_RECOVERY
#define EAI_NODATA
#define AI_CANONNAME
#define HOST_NOT_FOUND
#define EAI_SERVICE
#define EAI_FAIL
struct servent * getservbyname()
struct hostent * gethostbyname()
#define NO_ADDRESS
#define AI_PASSIVE
#define TRY_AGAIN
struct sockaddr * ai_addr
socklen_t ai_addrlen
struct addrinfo * ai_next
char ** h_addr_list

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors