2 * Replacement for a missing getaddrinfo.
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:
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.
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.
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/>.
22 * Written by Russ Allbery <rra@stanford.edu>
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
35 #ifndef HAVE_GETADDRINFO
37 #include <sys/types.h>
38 #include <sys/socket.h>
48 #endif /* STDC_HEADERS */
51 #endif /* HAVE_STRING_H */
54 #endif /* HAVE_STRINGS_H */
58 #include <netinet/in.h>
60 #include "compat/getaddrinfo.h"
63 /* We need access to h_errno to map errors from gethostbyname. */
64 #if !HAVE_DECL_H_ERRNO
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.
73 #ifndef HOST_NOT_FOUND
74 # define HOST_NOT_FOUND 1
76 # define NO_RECOVERY 3
79 #ifndef NETDB_INTERNAL
80 # define NETDB_INTERNAL -1
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).
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 *,
99 * If the native platform doesn't support AI_NUMERICSERV or AI_NUMERICHOST,
100 * pick some other values for them.
103 # if AI_NUMERICSERV == 0
104 # undef AI_NUMERICSERV
105 # define AI_NUMERICSERV 0x0080
107 # if AI_NUMERICHOST == 0
108 # undef AI_NUMERICHOST
109 # define AI_NUMERICHOST 0x0100
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.
118 # ifdef HAVE_GETADDRINFO
119 # define AI_INTERNAL_ALL 0x04ff
121 # define AI_INTERNAL_ALL 0x01ff
124 # define AI_INTERNAL_ALL 0x007f
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 */
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))
145 # define sin_set_length(s) /* empty */
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).
152 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
156 * Return a constant string for a given EAI_* error code or a string
157 * indicating an unknown error.
160 gai_strerror(int ecode)
162 if (ecode < 1 || (size_t) ecode > ARRAY_SIZE(gai_errors))
163 return "Unknown error";
165 return gai_errors[ecode - 1];
170 * Free a linked list of addrinfo structs.
173 freeaddrinfo(struct addrinfo *ai)
175 struct addrinfo *next;
179 if (ai->ai_addr != NULL)
181 if (ai->ai_canonname != NULL)
182 free(ai->ai_canonname);
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
198 convert_service(const char *string, long *result)
205 *result = strtol(string, &end, 10);
206 if (errno != 0 || *end != '\0' || *result < 0)
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.
219 static struct addrinfo *
220 gai_addrinfo_new(int socktype, const char *canonical, struct in_addr addr,
225 ai = malloc(sizeof(*ai));
228 ai->ai_addr = malloc(sizeof(struct sockaddr_in));
229 if (ai->ai_addr == NULL) {
234 if (canonical == NULL)
235 ai->ai_canonname = NULL;
237 ai->ai_canonname = strdup(canonical);
238 if (ai->ai_canonname == NULL) {
243 memset(ai->ai_addr, 0, sizeof(struct sockaddr_in));
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);
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
266 gai_service(const char *servname, int flags, int *type, unsigned short *port)
268 struct servent *servent;
269 const char *protocol;
272 if (convert_service(servname, &value)) {
273 if (value > (1L << 16) - 1)
277 if (flags & AI_NUMERICSERV)
280 protocol = (*type == SOCK_DGRAM) ? "udp" : "tcp";
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.
289 servent = getservbyname(servname, protocol);
292 if (strcmp(servent->s_proto, "udp") == 0)
294 else if (strcmp(servent->s_proto, "tcp") == 0)
298 *port = htons(servent->s_port);
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.
313 gai_lookup(const char *nodename, int flags, int socktype, unsigned short port,
314 struct addrinfo **res)
316 struct addrinfo *ai, *first, *prev;
318 struct hostent *host;
319 const char *canonical;
322 if (inet_aton(nodename, &addr)) {
323 canonical = (flags & AI_CANONNAME) ? nodename : NULL;
324 ai = gai_addrinfo_new(socktype, canonical, addr, port);
330 if (flags & AI_NUMERICHOST)
332 host = gethostbyname(nodename);
346 if (host->h_addr_list[0] == NULL)
348 canonical = (flags & AI_CANONNAME)
349 ? ((host->h_name != NULL) ? host->h_name : nodename)
353 for (i = 0; host->h_addr_list[i] != NULL; i++) {
354 if (host->h_length != sizeof(addr)) {
358 memcpy(&addr, host->h_addr_list[i], sizeof(addr));
359 ai = gai_addrinfo_new(socktype, canonical, addr, port);
379 * The actual getaddrinfo implementation.
382 getaddrinfo(const char *nodename, const char *servname,
383 const struct addrinfo *hints, struct addrinfo **res)
387 int flags, socktype, status;
390 /* Take the hints into account and check them for validity. */
392 flags = hints->ai_flags;
393 socktype = hints->ai_socktype;
394 if ((flags & AI_INTERNAL_ALL) != flags)
396 if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET)
398 if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
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)
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
418 if (servname == NULL)
421 status = gai_service(servname, flags, &socktype, &port);
425 if (nodename != NULL)
426 return gai_lookup(nodename, flags, socktype, port, res);
428 if (servname == NULL)
430 if ((flags & AI_PASSIVE) == AI_PASSIVE)
431 addr.s_addr = INADDR_ANY;
433 addr.s_addr = htonl(0x7f000001UL);
434 ai = gai_addrinfo_new(socktype, NULL, addr, port);
441 #endif /* HAVE_GETADDRINFO */