]> git.ipfire.org Git - thirdparty/squid.git/blame - compat/getaddrinfo.cc
SourceFormat Enforcement
[thirdparty/squid.git] / compat / getaddrinfo.cc
CommitLineData
37be9888 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
37be9888
AJ
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
0e076fb1 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
f53969cc 16 * - added protection around libray headers
0e076fb1 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 *
d4ddbe05
DF
23 * 13-Jan-2015 : Various fixed for C++ and MinGW native build
24 *
0e076fb1 25 * Original License and code follows.
26 */
f7f3304a 27#include "squid.h"
0e076fb1 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
55d7d5e9 54#if !HAVE_DECL_GETADDRINFO
0e076fb1 55
56/* Need to turn off Posix features in glibc to build this */
57#undef _POSIX_C_SOURCE
58#undef _XOPEN_SOURCE
59
0e076fb1 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
0e076fb1 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
0e076fb1 81
0e076fb1 82static struct addrinfo *
e1381638 83dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen) {
26ac0430
AJ
84 struct addrinfo *ret;
85
d4ddbe05 86 ret = (struct addrinfo *)malloc(sizeof (struct addrinfo));
26ac0430
AJ
87 if (ret == NULL)
88 return NULL;
89 memcpy (ret, info, sizeof (struct addrinfo));
d4ddbe05 90 ret->ai_addr = (struct sockaddr*)malloc(addrlen);
26ac0430
AJ
91 if (ret->ai_addr == NULL) {
92 free (ret);
93 return NULL;
0e076fb1 94 }
26ac0430
AJ
95 memcpy (ret->ai_addr, addr, addrlen);
96 ret->ai_addrlen = addrlen;
97 return ret;
0e076fb1 98}
99
100int
101xgetaddrinfo (const char *nodename, const char *servname,
26ac0430 102 const struct addrinfo *hints, struct addrinfo **res)
0e076fb1 103{
26ac0430
AJ
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 == NULL && nodename == NULL)
113 return EAI_NONAME;
114
115 memset (&result, 0, sizeof result);
116
117 /* default for hints */
118 if (hints == NULL) {
119 memset (&hint, 0, sizeof hint);
120 hint.ai_family = PF_UNSPEC;
121 hints = &hint;
0e076fb1 122 }
123
26ac0430
AJ
124 if (servname == NULL)
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, NULL, 10);
139 else if ((servent = getservbyname (servname, socktype)) != NULL)
140 port = ntohs (servent->s_port);
141 else
142 return EAI_NONAME;
0e076fb1 143 }
144
26ac0430
AJ
145 /* if nodename == NULL refer to the local host for a client or any
146 for a server */
147 if (nodename == NULL) {
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 == NULL) ? EAI_MEMORY : 0;
166 }
167
27bc2077 168 /* If AI_NUMERIC is specified, use inet_pton to translate numbers and
26ac0430
AJ
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);
d4ddbe05 181 if (inet_pton(result.ai_family, nodename, &sin.sin_addr) != 1)
26ac0430
AJ
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 == NULL) ? EAI_MEMORY : 0;
0e076fb1 187 }
188
b095e27d 189#if HAVE_H_ERRNO
26ac0430 190 h_errno = 0;
b095e27d 191#endif
26ac0430
AJ
192 errno = 0;
193 hp = gethostbyname(nodename);
194 if (hp == NULL) {
0e076fb1 195#ifdef EAI_SYSTEM
26ac0430
AJ
196 if (errno != 0) {
197 return EAI_SYSTEM;
198 }
0e076fb1 199#endif
26ac0430
AJ
200 switch (h_errno) {
201 case HOST_NOT_FOUND:
202 return EAI_NODATA;
203 case NO_DATA:
204 return EAI_NODATA;
0e076fb1 205#if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
26ac0430
AJ
206 case NO_ADDRESS:
207 return EAI_NODATA;
0e076fb1 208#endif
26ac0430
AJ
209 case NO_RECOVERY:
210 return EAI_FAIL;
211 case TRY_AGAIN:
212 return EAI_AGAIN;
213 default:
214 return EAI_FAIL;
0e076fb1 215 }
26ac0430 216 return EAI_FAIL;
0e076fb1 217 }
218
26ac0430
AJ
219 /* Check that the address family is acceptable.
220 */
221 switch (hp->h_addrtype) {
0e076fb1 222 case AF_INET:
26ac0430
AJ
223 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET))
224 return EAI_FAMILY;
225 break;
0e076fb1 226 case AF_INET6:
26ac0430
AJ
227 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6))
228 return EAI_FAMILY;
229 break;
0e076fb1 230 default:
26ac0430 231 return EAI_FAMILY;
0e076fb1 232 }
233
26ac0430
AJ
234 /* For each element pointed to by hp, create an element in the
235 result linked list. */
236 sai = eai = NULL;
237 for (addrs = hp->h_addr_list; *addrs != NULL; 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) {
0e076fb1 245 case AF_INET:
26ac0430
AJ
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;
0e076fb1 251 case AF_INET6:
252#if SIN6_LEN
26ac0430 253 ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length;
0e076fb1 254#endif
26ac0430
AJ
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;
0e076fb1 260 default:
26ac0430 261 continue;
0e076fb1 262 }
263
26ac0430
AJ
264 result.ai_family = hp->h_addrtype;
265 ai = dup_addrinfo (&result, &sa, addrlen);
266 if (ai == NULL) {
267 xfreeaddrinfo (sai);
268 return EAI_MEMORY;
0e076fb1 269 }
26ac0430
AJ
270 if (sai == NULL)
271 sai = ai;
272 else
273 eai->ai_next = ai;
274 eai = ai;
0e076fb1 275 }
276
26ac0430
AJ
277 if (sai == NULL) {
278 return EAI_NODATA;
0e076fb1 279 }
26ac0430
AJ
280
281 if (hints->ai_flags & AI_CANONNAME) {
d4ddbe05 282 sai->ai_canonname = (char *)malloc(strlen(hp->h_name) + 1);
26ac0430
AJ
283 if (sai->ai_canonname == NULL) {
284 xfreeaddrinfo (sai);
285 return EAI_MEMORY;
0e076fb1 286 }
26ac0430 287 strcpy (sai->ai_canonname, hp->h_name);
0e076fb1 288 }
289
26ac0430
AJ
290 *res = sai;
291 return 0;
0e076fb1 292}
293
294void
295xfreeaddrinfo (struct addrinfo *ai)
296{
26ac0430
AJ
297 struct addrinfo *next;
298
299 while (ai != NULL) {
300 next = ai->ai_next;
301 if (ai->ai_canonname != NULL)
302 free (ai->ai_canonname);
303 if (ai->ai_addr != NULL)
304 free (ai->ai_addr);
305 free (ai);
306 ai = next;
0e076fb1 307 }
308}
309
310const char *
311xgai_strerror (int ecode)
312{
26ac0430
AJ
313 static const char *eai_descr[] = {
314 "no error",
f53969cc
SM
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 */
0e076fb1 327 };
328
26ac0430
AJ
329 if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0]))
330 return "unknown error";
331 return eai_descr[ecode];
0e076fb1 332}
333
55d7d5e9 334#endif /* HAVE_DECL_GETADDRINFO */
f53969cc 335