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