]> git.ipfire.org Git - thirdparty/squid.git/blob - compat/getaddrinfo.cc
Fix memory leak of lastAclData
[thirdparty/squid.git] / compat / getaddrinfo.cc
1 /*
2 * Copyright (C) 1996-2016 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 libray 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 == NULL)
88 return NULL;
89 memcpy (ret, info, sizeof (struct addrinfo));
90 ret->ai_addr = (struct sockaddr*)malloc(addrlen);
91 if (ret->ai_addr == NULL) {
92 free (ret);
93 return NULL;
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 == 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;
122 }
123
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;
143 }
144
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
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 == NULL) ? 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 == NULL) {
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 = 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) {
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 == NULL) {
267 xfreeaddrinfo (sai);
268 return EAI_MEMORY;
269 }
270 if (sai == NULL)
271 sai = ai;
272 else
273 eai->ai_next = ai;
274 eai = ai;
275 }
276
277 if (sai == NULL) {
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 == NULL) {
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
295 xfreeaddrinfo (struct addrinfo *ai)
296 {
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;
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