Annotation of embedaddon/sudo/compat/getaddrinfo.c, revision 1.1.1.3
1.1 misho 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:
1.1.1.2 misho 35: #ifndef HAVE_GETADDRINFO
36:
1.1 misho 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 */
1.1.1.3 ! misho 55: #include <limits.h>
1.1 misho 56: #include <netdb.h>
57: #include <errno.h>
58:
1.1.1.3 ! misho 59: #include <arpa/inet.h>
1.1 misho 60: #include <netinet/in.h>
61:
62: #include "compat/getaddrinfo.h"
63: #include "missing.h"
64:
65: /* We need access to h_errno to map errors from gethostbyname. */
1.1.1.3 ! misho 66: #ifndef HAVE_DECL_H_ERRNO
1.1 misho 67: extern int h_errno;
68: #endif
69:
70: /*
71: * The netdb constants, which aren't always defined (particularly if h_errno
72: * isn't declared). We also make sure that a few of the less-used ones are
73: * defined so that we can deal with them in case statements.
74: */
75: #ifndef HOST_NOT_FOUND
76: # define HOST_NOT_FOUND 1
77: # define TRY_AGAIN 2
78: # define NO_RECOVERY 3
79: # define NO_DATA 4
80: #endif
81: #ifndef NETDB_INTERNAL
82: # define NETDB_INTERNAL -1
83: #endif
84:
85: /*
86: * If we're running the test suite, rename the functions to avoid conflicts
87: * with the system version. Note that we don't rename the structures and
88: * constants, but that should be okay (except possibly for gai_strerror).
89: */
1.1.1.3 ! misho 90: #ifdef TESTING
1.1 misho 91: # define gai_strerror test_gai_strerror
92: # define freeaddrinfo test_freeaddrinfo
93: # define getaddrinfo test_getaddrinfo
94: const char *test_gai_strerror(int);
95: void test_freeaddrinfo(struct addrinfo *);
96: int test_getaddrinfo(const char *, const char *, const struct addrinfo *,
97: struct addrinfo **);
98: #endif
99:
100: /*
101: * If the native platform doesn't support AI_NUMERICSERV or AI_NUMERICHOST,
102: * pick some other values for them.
103: */
1.1.1.3 ! misho 104: #ifdef TESTING
1.1 misho 105: # if AI_NUMERICSERV == 0
106: # undef AI_NUMERICSERV
107: # define AI_NUMERICSERV 0x0080
108: # endif
109: # if AI_NUMERICHOST == 0
110: # undef AI_NUMERICHOST
111: # define AI_NUMERICHOST 0x0100
112: # endif
113: #endif
114:
115: /*
116: * Value representing all of the hint flags set. Linux uses flags up to
117: * 0x0400, so be sure not to break when testing on that platform.
118: */
1.1.1.3 ! misho 119: #ifdef TESTING
1.1 misho 120: # ifdef HAVE_GETADDRINFO
121: # define AI_INTERNAL_ALL 0x04ff
122: # else
123: # define AI_INTERNAL_ALL 0x01ff
124: # endif
125: #else
126: # define AI_INTERNAL_ALL 0x007f
127: #endif
128:
129: /* Table of strings corresponding to the EAI_* error codes. */
130: static const char * const gai_errors[] = {
131: "Host name lookup failure", /* 1 EAI_AGAIN */
132: "Invalid flag value", /* 2 EAI_BADFLAGS */
133: "Unknown server error", /* 3 EAI_FAIL */
134: "Unsupported address family", /* 4 EAI_FAMILY */
135: "Memory allocation failure", /* 5 EAI_MEMORY */
136: "Host unknown or not given", /* 6 EAI_NONAME */
137: "Service not supported for socket", /* 7 EAI_SERVICE */
138: "Unsupported socket type", /* 8 EAI_SOCKTYPE */
139: "System error", /* 9 EAI_SYSTEM */
140: "Supplied buffer too small", /* 10 EAI_OVERFLOW */
141: };
142:
143: /* Macro to set the len attribute of sockaddr_in. */
1.1.1.3 ! misho 144: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
1.1 misho 145: # define sin_set_length(s) ((s)->sin_len = sizeof(struct sockaddr_in))
146: #else
147: # define sin_set_length(s) /* empty */
148: #endif
149:
150: /*
151: * Used for iterating through arrays. ARRAY_SIZE returns the number of
152: * elements in the array (useful for a < upper bound in a for loop).
153: */
154: #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
155:
156:
157: /*
158: * Return a constant string for a given EAI_* error code or a string
159: * indicating an unknown error.
160: */
161: const char *
162: gai_strerror(int ecode)
163: {
164: if (ecode < 1 || (size_t) ecode > ARRAY_SIZE(gai_errors))
165: return "Unknown error";
166: else
167: return gai_errors[ecode - 1];
168: }
169:
170:
171: /*
172: * Free a linked list of addrinfo structs.
173: */
174: void
175: freeaddrinfo(struct addrinfo *ai)
176: {
177: struct addrinfo *next;
178:
179: while (ai != NULL) {
180: next = ai->ai_next;
181: if (ai->ai_addr != NULL)
182: free(ai->ai_addr);
183: if (ai->ai_canonname != NULL)
184: free(ai->ai_canonname);
185: free(ai);
186: ai = next;
187: }
188: }
189:
190:
191: /*
192: * Allocate a new addrinfo struct, setting some defaults given that this
193: * implementation is IPv4 only. Also allocates an attached sockaddr_in and
194: * zeroes it, per the requirement for getaddrinfo. Takes the socktype,
195: * canonical name (which is copied if not NULL), address, and port. Returns
196: * NULL on a memory allocation failure.
197: */
198: static struct addrinfo *
199: gai_addrinfo_new(int socktype, const char *canonical, struct in_addr addr,
200: unsigned short port)
201: {
202: struct addrinfo *ai;
203:
204: ai = malloc(sizeof(*ai));
205: if (ai == NULL)
206: return NULL;
207: ai->ai_addr = malloc(sizeof(struct sockaddr_in));
208: if (ai->ai_addr == NULL) {
209: free(ai);
210: return NULL;
211: }
212: ai->ai_next = NULL;
213: if (canonical == NULL)
214: ai->ai_canonname = NULL;
215: else {
216: ai->ai_canonname = strdup(canonical);
217: if (ai->ai_canonname == NULL) {
218: freeaddrinfo(ai);
219: return NULL;
220: }
221: }
222: memset(ai->ai_addr, 0, sizeof(struct sockaddr_in));
223: ai->ai_flags = 0;
224: ai->ai_family = AF_INET;
225: ai->ai_socktype = socktype;
226: ai->ai_protocol = (socktype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
227: ai->ai_addrlen = sizeof(struct sockaddr_in);
228: ((struct sockaddr_in *) ai->ai_addr)->sin_family = AF_INET;
229: ((struct sockaddr_in *) ai->ai_addr)->sin_addr = addr;
230: ((struct sockaddr_in *) ai->ai_addr)->sin_port = htons(port);
231: sin_set_length((struct sockaddr_in *) ai->ai_addr);
232: return ai;
233: }
234:
235:
236: /*
237: * Look up a service. Takes the service name (which may be numeric), the hint
238: * flags, a pointer to the socket type (used to determine whether TCP or UDP
239: * services are of interest and, if 0, is filled in with the result of
240: * getservbyname if the service was not numeric), and a pointer to the
241: * addrinfo struct to fill in. Returns 0 on success or an EAI_* error on
242: * failure.
243: */
244: static int
245: gai_service(const char *servname, int flags, int *type, unsigned short *port)
246: {
247: struct servent *servent;
248: const char *protocol;
1.1.1.3 ! misho 249: const char *errstr;
! 250: unsigned short value;
1.1 misho 251:
1.1.1.3 ! misho 252: value = strtonum(servname, 0, USHRT_MAX, &errstr);
! 253: if (errstr == NULL) {
1.1 misho 254: *port = value;
1.1.1.3 ! misho 255: } else if (errno == ERANGE) {
! 256: return EAI_SERVICE;
1.1 misho 257: } else {
258: if (flags & AI_NUMERICSERV)
259: return EAI_NONAME;
260: if (*type != 0)
261: protocol = (*type == SOCK_DGRAM) ? "udp" : "tcp";
262: else
263: protocol = NULL;
264:
265: /*
266: * We really technically should be generating an addrinfo struct for
267: * each possible protocol unless type is set, but this works well
268: * enough for what I need this for.
269: */
270: servent = getservbyname(servname, protocol);
271: if (servent == NULL)
272: return EAI_NONAME;
273: if (strcmp(servent->s_proto, "udp") == 0)
274: *type = SOCK_DGRAM;
275: else if (strcmp(servent->s_proto, "tcp") == 0)
276: *type = SOCK_STREAM;
277: else
278: return EAI_SERVICE;
279: *port = htons(servent->s_port);
280: }
281: return 0;
282: }
283:
284:
285: /*
286: * Look up a host and fill in a linked list of addrinfo structs with the
287: * results, one per IP address of the returned host. Takes the name or IP
288: * address of the host as a string, the lookup flags, the type of socket (to
289: * fill into the addrinfo structs), the port (likewise), and a pointer to
290: * where the head of the linked list should be put. Returns 0 on success or
291: * the appropriate EAI_* error.
292: */
293: static int
294: gai_lookup(const char *nodename, int flags, int socktype, unsigned short port,
295: struct addrinfo **res)
296: {
297: struct addrinfo *ai, *first, *prev;
298: struct in_addr addr;
299: struct hostent *host;
300: const char *canonical;
301: int i;
302:
1.1.1.3 ! misho 303: if (inet_pton(AF_INET, nodename, &addr)) {
1.1 misho 304: canonical = (flags & AI_CANONNAME) ? nodename : NULL;
305: ai = gai_addrinfo_new(socktype, canonical, addr, port);
306: if (ai == NULL)
307: return EAI_MEMORY;
308: *res = ai;
309: return 0;
310: } else {
311: if (flags & AI_NUMERICHOST)
312: return EAI_NONAME;
313: host = gethostbyname(nodename);
314: if (host == NULL)
315: switch (h_errno) {
316: case HOST_NOT_FOUND:
317: return EAI_NONAME;
318: case TRY_AGAIN:
319: case NO_DATA:
320: return EAI_AGAIN;
321: case NO_RECOVERY:
322: return EAI_FAIL;
323: case NETDB_INTERNAL:
324: default:
325: return EAI_SYSTEM;
326: }
327: if (host->h_addr_list[0] == NULL)
328: return EAI_FAIL;
329: canonical = (flags & AI_CANONNAME)
330: ? ((host->h_name != NULL) ? host->h_name : nodename)
331: : NULL;
332: first = NULL;
333: prev = NULL;
334: for (i = 0; host->h_addr_list[i] != NULL; i++) {
335: if (host->h_length != sizeof(addr)) {
336: freeaddrinfo(first);
337: return EAI_FAIL;
338: }
339: memcpy(&addr, host->h_addr_list[i], sizeof(addr));
340: ai = gai_addrinfo_new(socktype, canonical, addr, port);
341: if (ai == NULL) {
342: freeaddrinfo(first);
343: return EAI_MEMORY;
344: }
345: if (first == NULL) {
346: first = ai;
347: prev = ai;
348: } else {
349: prev->ai_next = ai;
350: prev = ai;
351: }
352: }
353: *res = first;
354: return 0;
355: }
356: }
357:
358:
359: /*
360: * The actual getaddrinfo implementation.
361: */
362: int
363: getaddrinfo(const char *nodename, const char *servname,
364: const struct addrinfo *hints, struct addrinfo **res)
365: {
366: struct addrinfo *ai;
367: struct in_addr addr;
368: int flags, socktype, status;
369: unsigned short port;
370:
371: /* Take the hints into account and check them for validity. */
372: if (hints != NULL) {
373: flags = hints->ai_flags;
374: socktype = hints->ai_socktype;
375: if ((flags & AI_INTERNAL_ALL) != flags)
376: return EAI_BADFLAGS;
377: if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET)
378: return EAI_FAMILY;
379: if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
380: return EAI_SOCKTYPE;
381:
382: /* EAI_SOCKTYPE isn't quite right, but there isn't anything better. */
383: if (hints->ai_protocol != 0) {
384: int protocol = hints->ai_protocol;
385: if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
386: return EAI_SOCKTYPE;
387: }
388: } else {
389: flags = 0;
390: socktype = 0;
391: }
392:
393: /*
394: * See what we're doing. If nodename is null, either AI_PASSIVE is set or
395: * we're getting information for connecting to a service on the loopback
396: * address. Otherwise, we're getting information for connecting to a
397: * remote system.
398: */
399: if (servname == NULL)
400: port = 0;
401: else {
402: status = gai_service(servname, flags, &socktype, &port);
403: if (status != 0)
404: return status;
405: }
406: if (nodename != NULL)
407: return gai_lookup(nodename, flags, socktype, port, res);
408: else {
409: if (servname == NULL)
410: return EAI_NONAME;
411: if ((flags & AI_PASSIVE) == AI_PASSIVE)
412: addr.s_addr = INADDR_ANY;
413: else
414: addr.s_addr = htonl(0x7f000001UL);
415: ai = gai_addrinfo_new(socktype, NULL, addr, port);
416: if (ai == NULL)
417: return EAI_MEMORY;
418: *res = ai;
419: return 0;
420: }
421: }
1.1.1.2 misho 422: #endif /* HAVE_GETADDRINFO */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>