]>
Commit | Line | Data |
---|---|---|
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 | 82 | static struct addrinfo * |
e1381638 | 83 | dup_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 | ||
100 | int | |
101 | xgetaddrinfo (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 | ||
294 | void | |
295 | xfreeaddrinfo (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 | ||
310 | const char * | |
311 | xgai_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 |