1 /* $Id: getaddrinfo.c 10396 2020-11-12 20:19:41Z iulius $
2 *
3 * Replacement for a missing getaddrinfo.
4 *
5 * This is an implementation of getaddrinfo for systems that don't have one so
6 * that networking code can use a consistent interface without #ifdef. It is
7 * a fairly minimal implementation, with the following limitations:
8 *
9 * - IPv4 support only. IPv6 is not supported.
10 * - AI_ADDRCONFIG is ignored.
11 * - Not thread-safe due to gethostbyname and getservbyname.
12 * - SOCK_DGRAM and SOCK_STREAM only.
13 * - Multiple possible socket types only generate one addrinfo struct.
14 * - Protocol hints aren't used correctly.
15 *
16 * The last four issues could probably be easily remedied, but haven't been
17 * needed to date. Adding IPv6 support isn't worth it; systems with IPv6
18 * support should already support getaddrinfo natively.
19 *
20 * The canonical version of this file is maintained in the rra-c-util package,
21 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
22 *
23 * Written by Russ Allbery <eagle@eyrie.org>
24 * Copyright 2003-2005, 2016-2017, 2019-2020 Russ Allbery <eagle@eyrie.org>
25 * Copyright 2015 Julien ÉLIE <julien@trigofacile.com>
26 * Copyright 2008, 2011, 2013-2014
27 * The Board of Trustees of the Leland Stanford Junior University
28 *
29 * Copying and distribution of this file, with or without modification, are
30 * permitted in any medium without royalty provided the copyright notice and
31 * this notice are preserved. This file is offered as-is, without any
32 * warranty.
33 *
34 * SPDX-License-Identifier: FSFAP
35 */
36
37 #include "config.h"
38 #include "portable/socket.h"
39 #include "clibrary.h"
40
41 #include <errno.h>
42
43 /* We need access to h_errno to map errors from gethostbyname. */
44 #if !HAVE_DECL_H_ERRNO
45 extern int h_errno;
46 #endif
47
48 /*
49 * The netdb constants, which aren't always defined (particularly if h_errno
50 * isn't declared). We also make sure that a few of the less-used ones are
51 * defined so that we can deal with them in case statements.
52 */
53 #ifndef HOST_NOT_FOUND
54 # define HOST_NOT_FOUND 1
55 # define TRY_AGAIN 2
56 # define NO_RECOVERY 3
57 # define NO_DATA 4
58 #endif
59 #ifndef NETDB_INTERNAL
60 # define NETDB_INTERNAL -1
61 #endif
62
63 /*
64 * If we're running the test suite, rename the functions to avoid conflicts
65 * with the system version. Note that we don't rename the structures and
66 * constants, but that should be okay (except possibly for gai_strerror).
67 */
68 #if TESTING
69 # undef gai_strerror
70 # undef freeaddrinfo
71 # undef getaddrinfo
72 # define gai_strerror test_gai_strerror
73 # define freeaddrinfo test_freeaddrinfo
74 # define getaddrinfo test_getaddrinfo
75 const char *test_gai_strerror(int);
76 void test_freeaddrinfo(struct addrinfo *);
77 int test_getaddrinfo(const char *, const char *, const struct addrinfo *,
78 struct addrinfo **);
79 #endif
80
81 /*
82 * If the native platform doesn't support AI_NUMERICSERV or AI_NUMERICHOST,
83 * pick some other values for them.
84 */
85 #if TESTING
86 # if AI_NUMERICSERV == 0
87 # undef AI_NUMERICSERV
88 # define AI_NUMERICSERV 0x0080
89 # endif
90 # if AI_NUMERICHOST == 0
91 # undef AI_NUMERICHOST
92 # define AI_NUMERICHOST 0x0100
93 # endif
94 #endif
95
96 /*
97 * Value representing all of the hint flags set. Linux uses flags up to
98 * 0x0400, and Mac OS X up to 0x1000, so be sure not to break when testing
99 * on these platforms.
100 */
101 #if TESTING
102 # ifdef HAVE_GETADDRINFO
103 # define AI_INTERNAL_ALL 0x1fff
104 # else
105 # define AI_INTERNAL_ALL 0x01ff
106 # endif
107 #else
108 # define AI_INTERNAL_ALL 0x007f
109 #endif
110
111 /* Table of strings corresponding to the EAI_* error codes. */
112 static const char *const gai_errors[] = {
113 "Host name lookup failure", /* 1 EAI_AGAIN */
114 "Invalid flag value", /* 2 EAI_BADFLAGS */
115 "Unknown server error", /* 3 EAI_FAIL */
116 "Unsupported address family", /* 4 EAI_FAMILY */
117 "Memory allocation failure", /* 5 EAI_MEMORY */
118 "Host unknown or not given", /* 6 EAI_NONAME */
119 "Service not supported for socket", /* 7 EAI_SERVICE */
120 "Unsupported socket type", /* 8 EAI_SOCKTYPE */
121 "System error", /* 9 EAI_SYSTEM */
122 "Supplied buffer too small", /* 10 EAI_OVERFLOW */
123 };
124
125 /* Macro to set the len attribute of sockaddr_in. */
126 #if HAVE_STRUCT_SOCKADDR_SA_LEN
127 # define sin_set_length(s) ((s)->sin_len = sizeof(struct sockaddr_in))
128 #else
129 # define sin_set_length(s) /* empty */
130 #endif
131
132 /*
133 * Used for iterating through arrays. ARRAY_SIZE returns the number of
134 * elements in the array (useful for a < upper bound in a for loop).
135 */
136 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
137
138
139 /*
140 * Return a constant string for a given EAI_* error code or a string
141 * indicating an unknown error.
142 */
143 const char *
gai_strerror(int ecode)144 gai_strerror(int ecode)
145 {
146 if (ecode < 1 || (size_t) ecode > ARRAY_SIZE(gai_errors))
147 return "Unknown error";
148 else
149 return gai_errors[ecode - 1];
150 }
151
152
153 /*
154 * Free a linked list of addrinfo structs.
155 */
156 void
freeaddrinfo(struct addrinfo * ai)157 freeaddrinfo(struct addrinfo *ai)
158 {
159 struct addrinfo *next;
160
161 while (ai != NULL) {
162 next = ai->ai_next;
163 free(ai->ai_addr);
164 free(ai->ai_canonname);
165 free(ai);
166 ai = next;
167 }
168 }
169
170
171 /*
172 * Convert a numeric service string to a number with error checking, returning
173 * true if the number was parsed correctly and false otherwise. Stores the
174 * converted number in the second argument. Equivalent to calling strtol, but
175 * with the base always fixed at 10, with checking of errno, ensuring that all
176 * of the string is consumed, and checking that the resulting number is
177 * positive.
178 */
179 static bool
convert_service(const char * string,long * result)180 convert_service(const char *string, long *result)
181 {
182 char *end;
183
184 if (*string == '\0')
185 return false;
186 errno = 0;
187 *result = strtol(string, &end, 10);
188 if (errno != 0 || *end != '\0' || *result < 0)
189 return false;
190 return true;
191 }
192
193
194 /*
195 * Allocate a new addrinfo struct, setting some defaults given that this
196 * implementation is IPv4 only. Also allocates an attached sockaddr_in and
197 * zeroes it, per the requirement for getaddrinfo. Takes the socktype,
198 * canonical name (which is copied if not NULL), address, and port. Returns
199 * NULL on a memory allocation failure.
200 */
201 static struct addrinfo *
gai_addrinfo_new(int socktype,const char * canonical,struct in_addr addr,unsigned short port)202 gai_addrinfo_new(int socktype, const char *canonical, struct in_addr addr,
203 unsigned short port)
204 {
205 struct addrinfo *ai;
206 struct sockaddr_in *sin;
207
208 ai = malloc(sizeof(*ai));
209 if (ai == NULL)
210 return NULL;
211 sin = calloc(1, sizeof(struct sockaddr_in));
212 if (sin == NULL) {
213 free(ai);
214 return NULL;
215 }
216 ai->ai_next = NULL;
217 if (canonical == NULL)
218 ai->ai_canonname = NULL;
219 else {
220 ai->ai_canonname = strdup(canonical);
221 if (ai->ai_canonname == NULL) {
222 free(sin);
223 free(ai);
224 return NULL;
225 }
226 }
227 ai->ai_flags = 0;
228 ai->ai_family = AF_INET;
229 ai->ai_socktype = socktype;
230 ai->ai_protocol = (socktype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
231 sin->sin_family = AF_INET;
232 sin->sin_addr = addr;
233 sin->sin_port = htons(port);
234 sin_set_length(sin);
235 ai->ai_addr = (struct sockaddr *) sin;
236 ai->ai_addrlen = sizeof(struct sockaddr_in);
237 return ai;
238 }
239
240
241 /*
242 * Look up a service. Takes the service name (which may be numeric), the hint
243 * flags, a pointer to the socket type (used to determine whether TCP or UDP
244 * services are of interest and, if 0, is filled in with the result of
245 * getservbyname if the service was not numeric), and a pointer to the
246 * addrinfo struct to fill in. Returns 0 on success or an EAI_* error on
247 * failure.
248 */
249 static int
gai_service(const char * servname,int flags,int * type,unsigned short * port)250 gai_service(const char *servname, int flags, int *type, unsigned short *port)
251 {
252 struct servent *servent;
253 const char *protocol;
254 long value;
255
256 if (convert_service(servname, &value)) {
257 if (value > (1L << 16) - 1)
258 return EAI_SERVICE;
259 *port = (unsigned short) value;
260 } else {
261 if (flags & AI_NUMERICSERV)
262 return EAI_NONAME;
263 if (*type != 0)
264 protocol = (*type == SOCK_DGRAM) ? "udp" : "tcp";
265 else
266 protocol = NULL;
267
268 /*
269 * We really technically should be generating an addrinfo struct for
270 * each possible protocol unless type is set, but this works well
271 * enough for what I need this for.
272 */
273 servent = getservbyname(servname, protocol);
274 if (servent == NULL)
275 return EAI_NONAME;
276 if (strcmp(servent->s_proto, "udp") == 0)
277 *type = SOCK_DGRAM;
278 else if (strcmp(servent->s_proto, "tcp") == 0)
279 *type = SOCK_STREAM;
280 else
281 return EAI_SERVICE;
282 if (servent->s_port > (1L << 16) - 1)
283 return EAI_SERVICE;
284 *port = htons((unsigned short) servent->s_port);
285 }
286 return 0;
287 }
288
289
290 /*
291 * Look up a host and fill in a linked list of addrinfo structs with the
292 * results, one per IP address of the returned host. Takes the name or IP
293 * address of the host as a string, the lookup flags, the type of socket (to
294 * fill into the addrinfo structs), the port (likewise), and a pointer to
295 * where the head of the linked list should be put. Returns 0 on success or
296 * the appropriate EAI_* error.
297 */
298 static int
gai_lookup(const char * nodename,int flags,int socktype,unsigned short port,struct addrinfo ** res)299 gai_lookup(const char *nodename, int flags, int socktype, unsigned short port,
300 struct addrinfo **res)
301 {
302 struct addrinfo *ai, *first, *prev;
303 struct in_addr addr;
304 struct hostent *host;
305 const char *canonical;
306 int i;
307
308 if (inet_aton(nodename, &addr)) {
309 canonical = (flags & AI_CANONNAME) ? nodename : NULL;
310 ai = gai_addrinfo_new(socktype, canonical, addr, port);
311 if (ai == NULL)
312 return EAI_MEMORY;
313 *res = ai;
314 return 0;
315 } else {
316 if (flags & AI_NUMERICHOST)
317 return EAI_NONAME;
318 host = gethostbyname(nodename);
319 if (host == NULL)
320 switch (h_errno) {
321 case HOST_NOT_FOUND:
322 return EAI_NONAME;
323 case TRY_AGAIN:
324 case NO_DATA:
325 return EAI_AGAIN;
326 case NO_RECOVERY:
327 return EAI_FAIL;
328 case NETDB_INTERNAL:
329 default:
330 return EAI_SYSTEM;
331 }
332 if (host->h_addr_list[0] == NULL)
333 return EAI_FAIL;
334 canonical = (flags & AI_CANONNAME)
335 ? ((host->h_name != NULL) ? host->h_name : nodename)
336 : NULL;
337 first = NULL;
338 prev = NULL;
339 for (i = 0; host->h_addr_list[i] != NULL; i++) {
340 if (host->h_length != sizeof(addr)) {
341 freeaddrinfo(first);
342 return EAI_FAIL;
343 }
344 memcpy(&addr, host->h_addr_list[i], sizeof(addr));
345 ai = gai_addrinfo_new(socktype, canonical, addr, port);
346 if (ai == NULL) {
347 freeaddrinfo(first);
348 return EAI_MEMORY;
349 }
350 if (first == NULL) {
351 first = ai;
352 prev = ai;
353 } else {
354 prev->ai_next = ai;
355 prev = ai;
356 }
357 }
358 *res = first;
359 return 0;
360 }
361 }
362
363
364 /*
365 * The actual getaddrinfo implementation.
366 */
367 int
getaddrinfo(const char * nodename,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)368 getaddrinfo(const char *nodename, const char *servname,
369 const struct addrinfo *hints, struct addrinfo **res)
370 {
371 struct addrinfo *ai;
372 struct in_addr addr;
373 int flags, socktype, status;
374 unsigned short port;
375
376 /* Take the hints into account and check them for validity. */
377 if (hints != NULL) {
378 flags = hints->ai_flags;
379 socktype = hints->ai_socktype;
380 if ((flags & AI_INTERNAL_ALL) != flags)
381 return EAI_BADFLAGS;
382 if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET)
383 return EAI_FAMILY;
384 if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
385 return EAI_SOCKTYPE;
386
387 /* EAI_SOCKTYPE isn't quite right, but there isn't anything better. */
388 if (hints->ai_protocol != 0) {
389 int protocol = hints->ai_protocol;
390 if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
391 return EAI_SOCKTYPE;
392 }
393 } else {
394 flags = 0;
395 socktype = 0;
396 }
397
398 /*
399 * See what we're doing. If nodename is null, either AI_PASSIVE is set or
400 * we're getting information for connecting to a service on the loopback
401 * address. Otherwise, we're getting information for connecting to a
402 * remote system.
403 */
404 if (servname == NULL)
405 port = 0;
406 else {
407 status = gai_service(servname, flags, &socktype, &port);
408 if (status != 0)
409 return status;
410 }
411 if (nodename != NULL)
412 return gai_lookup(nodename, flags, socktype, port, res);
413 else {
414 if (servname == NULL)
415 return EAI_NONAME;
416 if ((flags & AI_PASSIVE) == AI_PASSIVE)
417 addr.s_addr = INADDR_ANY;
418 else
419 addr.s_addr = htonl(0x7f000001UL);
420 ai = gai_addrinfo_new(socktype, NULL, addr, port);
421 if (ai == NULL)
422 return EAI_MEMORY;
423 *res = ai;
424 return 0;
425 }
426 }
427