Annotation of embedaddon/sudo/compat/getaddrinfo.c, revision 1.1.1.2
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 */
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: }
1.1.1.2 ! misho 441: #endif /* HAVE_GETADDRINFO */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>