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