blob: a188bdd134cbc196b2f51326db1a47c1b1e32bd2 [file] [log] [blame]
Martin v. Löwis01dfdb32001-06-23 16:30:13 +00001/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
32 *
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked.
35 * - Return values. There are nonstandard return values defined and used
36 * in the source code. This is because RFC2133 is silent about which error
37 * code must be returned for which situation.
38 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
39 */
40
41#if 0
42#include <sys/types.h>
43#include <sys/param.h>
44#include <sys/sysctl.h>
45#include <sys/socket.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <arpa/nameser.h>
49#include <netdb.h>
50#include <resolv.h>
51#include <string.h>
52#include <stdlib.h>
53#include <stddef.h>
54#include <ctype.h>
55#include <unistd.h>
56
57#include "addrinfo.h"
58#endif
59
60#if defined(__KAME__) && defined(INET6)
61# define FAITH
62#endif
63
64#define SUCCESS 0
65#define GAI_ANY 0
66#define YES 1
67#define NO 0
68
69#ifdef FAITH
70static int translate = NO;
71static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
72#endif
73
74static const char in_addrany[] = { 0, 0, 0, 0 };
75static const char in6_addrany[] = {
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
77};
78static const char in_loopback[] = { 127, 0, 0, 1 };
79static const char in6_loopback[] = {
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
81};
82
83struct sockinet {
84 u_char si_len;
85 u_char si_family;
86 u_short si_port;
87};
88
89static struct gai_afd {
90 int a_af;
91 int a_addrlen;
92 int a_socklen;
93 int a_off;
94 const char *a_addrany;
95 const char *a_loopback;
96} gai_afdl [] = {
97#ifdef INET6
98#define N_INET6 0
99 {PF_INET6, sizeof(struct in6_addr),
100 sizeof(struct sockaddr_in6),
101 offsetof(struct sockaddr_in6, sin6_addr),
102 in6_addrany, in6_loopback},
103#define N_INET 1
104#else
105#define N_INET 0
106#endif
107 {PF_INET, sizeof(struct in_addr),
108 sizeof(struct sockaddr_in),
109 offsetof(struct sockaddr_in, sin_addr),
110 in_addrany, in_loopback},
111 {0, 0, 0, 0, NULL, NULL},
112};
113
114#ifdef INET6
115#define PTON_MAX 16
116#else
117#define PTON_MAX 4
118#endif
119
120
121static int get_name Py_PROTO((const char *, struct gai_afd *,
122 struct addrinfo **, char *, struct addrinfo *,
123 int));
124static int get_addr Py_PROTO((const char *, int, struct addrinfo **,
125 struct addrinfo *, int));
126static int str_isnumber Py_PROTO((const char *));
127
128static char *ai_errlist[] = {
129 "success.",
130 "address family for hostname not supported.", /* EAI_ADDRFAMILY */
131 "temporary failure in name resolution.", /* EAI_AGAIN */
132 "invalid value for ai_flags.", /* EAI_BADFLAGS */
133 "non-recoverable failure in name resolution.", /* EAI_FAIL */
134 "ai_family not supported.", /* EAI_FAMILY */
135 "memory allocation failure.", /* EAI_MEMORY */
136 "no address associated with hostname.", /* EAI_NODATA */
137 "hostname nor servname provided, or not known.",/* EAI_NONAME */
138 "servname not supported for ai_socktype.", /* EAI_SERVICE */
139 "ai_socktype not supported.", /* EAI_SOCKTYPE */
140 "system error returned in errno.", /* EAI_SYSTEM */
141 "invalid value for hints.", /* EAI_BADHINTS */
142 "resolved protocol is unknown.", /* EAI_PROTOCOL */
143 "unknown error.", /* EAI_MAX */
144};
145
146#define GET_CANONNAME(ai, str) \
147if (pai->ai_flags & AI_CANONNAME) {\
148 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
149 strcpy((ai)->ai_canonname, (str));\
150 } else {\
151 error = EAI_MEMORY;\
152 goto free;\
153 }\
154}
155
156#ifdef HAVE_SOCKADDR_SA_LEN
157#define GET_AI(ai, gai_afd, addr, port) {\
158 char *p;\
159 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
160 ((gai_afd)->a_socklen)))\
161 == NULL) goto free;\
162 memcpy(ai, pai, sizeof(struct addrinfo));\
163 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
164 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
165 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
166 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
167 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
168 p = (char *)((ai)->ai_addr);\
169 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
170}
171#else
172#define GET_AI(ai, gai_afd, addr, port) {\
173 char *p;\
174 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
175 ((gai_afd)->a_socklen)))\
176 == NULL) goto free;\
177 memcpy(ai, pai, sizeof(struct addrinfo));\
178 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
179 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
180 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
181 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
182 p = (char *)((ai)->ai_addr);\
183 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
184}
185#endif
186
187#define ERR(err) { error = (err); goto bad; }
188
189char *
190gai_strerror(ecode)
191 int ecode;
192{
193 if (ecode < 0 || ecode > EAI_MAX)
194 ecode = EAI_MAX;
195 return ai_errlist[ecode];
196}
197
198void
199freeaddrinfo(ai)
200 struct addrinfo *ai;
201{
202 struct addrinfo *next;
203
204 do {
205 next = ai->ai_next;
206 if (ai->ai_canonname)
207 free(ai->ai_canonname);
208 /* no need to free(ai->ai_addr) */
209 free(ai);
210 } while ((ai = next) != NULL);
211}
212
213static int
214str_isnumber(p)
215 const char *p;
216{
217 char *q = (char *)p;
218 while (*q) {
219 if (! isdigit(*q))
220 return NO;
221 q++;
222 }
223 return YES;
224}
225
226int
227getaddrinfo(hostname, servname, hints, res)
228 const char *hostname, *servname;
229 const struct addrinfo *hints;
230 struct addrinfo **res;
231{
232 struct addrinfo sentinel;
233 struct addrinfo *top = NULL;
234 struct addrinfo *cur;
235 int i, error = 0;
236 char pton[PTON_MAX];
237 struct addrinfo ai;
238 struct addrinfo *pai;
239 u_short port;
240
241#ifdef FAITH
242 static int firsttime = 1;
243
244 if (firsttime) {
245 /* translator hack */
246 {
247 char *q = getenv("GAI");
248 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
249 translate = YES;
250 }
251 firsttime = 0;
252 }
253#endif
254
255 /* initialize file static vars */
256 sentinel.ai_next = NULL;
257 cur = &sentinel;
258 pai = &ai;
259 pai->ai_flags = 0;
260 pai->ai_family = PF_UNSPEC;
261 pai->ai_socktype = GAI_ANY;
262 pai->ai_protocol = GAI_ANY;
263 pai->ai_addrlen = 0;
264 pai->ai_canonname = NULL;
265 pai->ai_addr = NULL;
266 pai->ai_next = NULL;
267 port = GAI_ANY;
268
269 if (hostname == NULL && servname == NULL)
270 return EAI_NONAME;
271 if (hints) {
272 /* error check for hints */
273 if (hints->ai_addrlen || hints->ai_canonname ||
274 hints->ai_addr || hints->ai_next)
275 ERR(EAI_BADHINTS); /* xxx */
276 if (hints->ai_flags & ~AI_MASK)
277 ERR(EAI_BADFLAGS);
278 switch (hints->ai_family) {
279 case PF_UNSPEC:
280 case PF_INET:
281#ifdef INET6
282 case PF_INET6:
283#endif
284 break;
285 default:
286 ERR(EAI_FAMILY);
287 }
288 memcpy(pai, hints, sizeof(*pai));
289 switch (pai->ai_socktype) {
290 case GAI_ANY:
291 switch (pai->ai_protocol) {
292 case GAI_ANY:
293 break;
294 case IPPROTO_UDP:
295 pai->ai_socktype = SOCK_DGRAM;
296 break;
297 case IPPROTO_TCP:
298 pai->ai_socktype = SOCK_STREAM;
299 break;
300 default:
301 pai->ai_socktype = SOCK_RAW;
302 break;
303 }
304 break;
305 case SOCK_RAW:
306 break;
307 case SOCK_DGRAM:
308 if (pai->ai_protocol != IPPROTO_UDP &&
309 pai->ai_protocol != GAI_ANY)
310 ERR(EAI_BADHINTS); /*xxx*/
311 pai->ai_protocol = IPPROTO_UDP;
312 break;
313 case SOCK_STREAM:
314 if (pai->ai_protocol != IPPROTO_TCP &&
315 pai->ai_protocol != GAI_ANY)
316 ERR(EAI_BADHINTS); /*xxx*/
317 pai->ai_protocol = IPPROTO_TCP;
318 break;
319 default:
320 ERR(EAI_SOCKTYPE);
321 break;
322 }
323 }
324
325 /*
326 * service port
327 */
328 if (servname) {
329 if (str_isnumber(servname)) {
330 if (pai->ai_socktype == GAI_ANY) {
331 /* caller accept *GAI_ANY* socktype */
332 pai->ai_socktype = SOCK_DGRAM;
333 pai->ai_protocol = IPPROTO_UDP;
334 }
335 port = htons(atoi(servname));
336 } else {
337 struct servent *sp;
338 char *proto;
339
340 proto = NULL;
341 switch (pai->ai_socktype) {
342 case GAI_ANY:
343 proto = NULL;
344 break;
345 case SOCK_DGRAM:
346 proto = "udp";
347 break;
348 case SOCK_STREAM:
349 proto = "tcp";
350 break;
351 default:
352 fprintf(stderr, "panic!\n");
353 break;
354 }
355 if ((sp = getservbyname(servname, proto)) == NULL)
356 ERR(EAI_SERVICE);
357 port = sp->s_port;
358 if (pai->ai_socktype == GAI_ANY)
359 if (strcmp(sp->s_proto, "udp") == 0) {
360 pai->ai_socktype = SOCK_DGRAM;
361 pai->ai_protocol = IPPROTO_UDP;
362 } else if (strcmp(sp->s_proto, "tcp") == 0) {
363 pai->ai_socktype = SOCK_STREAM;
364 pai->ai_protocol = IPPROTO_TCP;
365 } else
366 ERR(EAI_PROTOCOL); /*xxx*/
367 }
368 }
369
370 /*
371 * hostname == NULL.
372 * passive socket -> anyaddr (0.0.0.0 or ::)
373 * non-passive socket -> localhost (127.0.0.1 or ::1)
374 */
375 if (hostname == NULL) {
376 struct gai_afd *gai_afd;
377
378 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
379 if (!(pai->ai_family == PF_UNSPEC
380 || pai->ai_family == gai_afd->a_af)) {
381 continue;
382 }
383
384 if (pai->ai_flags & AI_PASSIVE) {
385 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
386 /* xxx meaningless?
387 * GET_CANONNAME(cur->ai_next, "anyaddr");
388 */
389 } else {
390 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
391 port);
392 /* xxx meaningless?
393 * GET_CANONNAME(cur->ai_next, "localhost");
394 */
395 }
396 cur = cur->ai_next;
397 }
398 top = sentinel.ai_next;
399 if (top)
400 goto good;
401 else
402 ERR(EAI_FAMILY);
403 }
404
405 /* hostname as numeric name */
406 for (i = 0; gai_afdl[i].a_af; i++) {
407 if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
408 u_long v4a;
409 u_char pfx;
410
411 switch (gai_afdl[i].a_af) {
412 case AF_INET:
413 v4a = ((struct in_addr *)pton)->s_addr;
414 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
415 pai->ai_flags &= ~AI_CANONNAME;
416 v4a >>= IN_CLASSA_NSHIFT;
417 if (v4a == 0 || v4a == IN_LOOPBACKNET)
418 pai->ai_flags &= ~AI_CANONNAME;
419 break;
420#ifdef INET6
421 case AF_INET6:
422 pfx = ((struct in6_addr *)pton)->s6_addr8[0];
423 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
424 pai->ai_flags &= ~AI_CANONNAME;
425 break;
426#endif
427 }
428
429 if (pai->ai_family == gai_afdl[i].a_af ||
430 pai->ai_family == PF_UNSPEC) {
431 if (! (pai->ai_flags & AI_CANONNAME)) {
432 GET_AI(top, &gai_afdl[i], pton, port);
433 goto good;
434 }
435 /*
436 * if AI_CANONNAME and if reverse lookup
437 * fail, return ai anyway to pacify
438 * calling application.
439 *
440 * XXX getaddrinfo() is a name->address
441 * translation function, and it looks strange
442 * that we do addr->name translation here.
443 */
444 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
445 goto good;
446 } else
447 ERR(EAI_FAMILY); /*xxx*/
448 }
449 }
450
451 if (pai->ai_flags & AI_NUMERICHOST)
452 ERR(EAI_NONAME);
453
454 /* hostname as alphabetical name */
455 error = get_addr(hostname, pai->ai_family, &top, pai, port);
456 if (error == 0) {
457 if (top) {
458 good:
459 *res = top;
460 return SUCCESS;
461 } else
462 error = EAI_FAIL;
463 }
464 free:
465 if (top)
466 freeaddrinfo(top);
467 bad:
468 *res = NULL;
469 return error;
470}
471
472static int
473get_name(addr, gai_afd, res, numaddr, pai, port0)
474 const char *addr;
475 struct gai_afd *gai_afd;
476 struct addrinfo **res;
477 char *numaddr;
478 struct addrinfo *pai;
479 int port0;
480{
481 u_short port = port0 & 0xffff;
482 struct hostent *hp;
483 struct addrinfo *cur;
484 int error = 0, h_error;
485
486#ifdef INET6
487 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
488#else
489 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
490#endif
491 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
492 GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
493 GET_CANONNAME(cur, hp->h_name);
494 } else
495 GET_AI(cur, gai_afd, numaddr, port);
496
497#ifdef INET6
498 if (hp)
499 freehostent(hp);
500#endif
501 *res = cur;
502 return SUCCESS;
503 free:
504 if (cur)
505 freeaddrinfo(cur);
506#ifdef INET6
507 if (hp)
508 freehostent(hp);
509#endif
510 /* bad: */
511 *res = NULL;
512 return error;
513}
514
515static int
516get_addr(hostname, af, res, pai, port0)
517 const char *hostname;
518 int af;
519 struct addrinfo **res;
520 struct addrinfo *pai;
521 int port0;
522{
523 u_short port = port0 & 0xffff;
524 struct addrinfo sentinel;
525 struct hostent *hp;
526 struct addrinfo *top, *cur;
527 struct gai_afd *gai_afd;
528 int i, error = 0, h_error;
529 char *ap;
530#ifndef INET6
531 extern int h_errno;
532#endif
533
534 top = NULL;
535 sentinel.ai_next = NULL;
536 cur = &sentinel;
537#ifdef INET6
538 if (af == AF_UNSPEC) {
539 hp = getipnodebyname(hostname, AF_INET6,
540 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
541 } else
542 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
543#else
544 hp = gethostbyname(hostname);
545 h_error = h_errno;
546#endif
547 if (hp == NULL) {
548 switch (h_error) {
549 case HOST_NOT_FOUND:
550 case NO_DATA:
551 error = EAI_NODATA;
552 break;
553 case TRY_AGAIN:
554 error = EAI_AGAIN;
555 break;
556 case NO_RECOVERY:
557 default:
558 error = EAI_FAIL;
559 break;
560 }
561 goto bad;
562 }
563
564 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
565 (hp->h_addr_list[0] == NULL))
566 ERR(EAI_FAIL);
567
568 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
569 switch (af) {
570#ifdef INET6
571 case AF_INET6:
572 gai_afd = &gai_afdl[N_INET6];
573 break;
574#endif
575#ifndef INET6
576 default: /* AF_UNSPEC */
577#endif
578 case AF_INET:
579 gai_afd = &gai_afdl[N_INET];
580 break;
581#ifdef INET6
582 default: /* AF_UNSPEC */
583 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
584 ap += sizeof(struct in6_addr) -
585 sizeof(struct in_addr);
586 gai_afd = &gai_afdl[N_INET];
587 } else
588 gai_afd = &gai_afdl[N_INET6];
589 break;
590#endif
591 }
592#ifdef FAITH
593 if (translate && gai_afd->a_af == AF_INET) {
594 struct in6_addr *in6;
595
596 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
597 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
598 memcpy(&in6->s6_addr32[0], &faith_prefix,
599 sizeof(struct in6_addr) - sizeof(struct in_addr));
600 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
601 } else
602#endif /* FAITH */
603 GET_AI(cur->ai_next, gai_afd, ap, port);
604 if (cur == &sentinel) {
605 top = cur->ai_next;
606 GET_CANONNAME(top, hp->h_name);
607 }
608 cur = cur->ai_next;
609 }
610#ifdef INET6
611 freehostent(hp);
612#endif
613 *res = top;
614 return SUCCESS;
615 free:
616 if (top)
617 freeaddrinfo(top);
618#ifdef INET6
619 if (hp)
620 freehostent(hp);
621#endif
622 bad:
623 *res = NULL;
624 return error;
625}