blob: 3745c430d7d11bde2e59904c842e6f61d1088faa [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
Martin v. Löwisd7830412001-07-19 17:37:46 +0000120#ifndef IN_MULTICAST
121#define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U)
122#endif
123
124#ifndef IN_EXPERIMENTAL
125#define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U)
126#endif
127
128#ifndef IN_LOOPBACKNET
129#define IN_LOOPBACKNET 127
130#endif
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000131
132static int get_name Py_PROTO((const char *, struct gai_afd *,
133 struct addrinfo **, char *, struct addrinfo *,
134 int));
135static int get_addr Py_PROTO((const char *, int, struct addrinfo **,
136 struct addrinfo *, int));
137static int str_isnumber Py_PROTO((const char *));
138
139static char *ai_errlist[] = {
140 "success.",
141 "address family for hostname not supported.", /* EAI_ADDRFAMILY */
142 "temporary failure in name resolution.", /* EAI_AGAIN */
143 "invalid value for ai_flags.", /* EAI_BADFLAGS */
144 "non-recoverable failure in name resolution.", /* EAI_FAIL */
145 "ai_family not supported.", /* EAI_FAMILY */
146 "memory allocation failure.", /* EAI_MEMORY */
147 "no address associated with hostname.", /* EAI_NODATA */
148 "hostname nor servname provided, or not known.",/* EAI_NONAME */
149 "servname not supported for ai_socktype.", /* EAI_SERVICE */
150 "ai_socktype not supported.", /* EAI_SOCKTYPE */
151 "system error returned in errno.", /* EAI_SYSTEM */
152 "invalid value for hints.", /* EAI_BADHINTS */
153 "resolved protocol is unknown.", /* EAI_PROTOCOL */
154 "unknown error.", /* EAI_MAX */
155};
156
157#define GET_CANONNAME(ai, str) \
158if (pai->ai_flags & AI_CANONNAME) {\
159 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
160 strcpy((ai)->ai_canonname, (str));\
161 } else {\
162 error = EAI_MEMORY;\
163 goto free;\
164 }\
165}
166
167#ifdef HAVE_SOCKADDR_SA_LEN
168#define GET_AI(ai, gai_afd, addr, port) {\
169 char *p;\
170 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
171 ((gai_afd)->a_socklen)))\
172 == NULL) goto free;\
173 memcpy(ai, pai, sizeof(struct addrinfo));\
174 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
175 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
176 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
177 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
178 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
179 p = (char *)((ai)->ai_addr);\
180 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
181}
182#else
183#define GET_AI(ai, gai_afd, addr, port) {\
184 char *p;\
185 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
186 ((gai_afd)->a_socklen)))\
187 == NULL) goto free;\
188 memcpy(ai, pai, sizeof(struct addrinfo));\
189 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
190 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
Martin v. Löwisc7cdc632001-07-21 18:48:56 +0000191 (ai)->ai_addrlen = (gai_afd)->a_socklen;\
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000192 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
193 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
194 p = (char *)((ai)->ai_addr);\
195 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
196}
197#endif
198
199#define ERR(err) { error = (err); goto bad; }
200
201char *
202gai_strerror(ecode)
203 int ecode;
204{
205 if (ecode < 0 || ecode > EAI_MAX)
206 ecode = EAI_MAX;
207 return ai_errlist[ecode];
208}
209
210void
211freeaddrinfo(ai)
212 struct addrinfo *ai;
213{
214 struct addrinfo *next;
215
216 do {
217 next = ai->ai_next;
218 if (ai->ai_canonname)
219 free(ai->ai_canonname);
220 /* no need to free(ai->ai_addr) */
221 free(ai);
222 } while ((ai = next) != NULL);
223}
224
225static int
226str_isnumber(p)
227 const char *p;
228{
229 char *q = (char *)p;
230 while (*q) {
231 if (! isdigit(*q))
232 return NO;
233 q++;
234 }
235 return YES;
236}
237
238int
239getaddrinfo(hostname, servname, hints, res)
240 const char *hostname, *servname;
241 const struct addrinfo *hints;
242 struct addrinfo **res;
243{
244 struct addrinfo sentinel;
245 struct addrinfo *top = NULL;
246 struct addrinfo *cur;
247 int i, error = 0;
248 char pton[PTON_MAX];
249 struct addrinfo ai;
250 struct addrinfo *pai;
251 u_short port;
252
253#ifdef FAITH
254 static int firsttime = 1;
255
256 if (firsttime) {
257 /* translator hack */
258 {
259 char *q = getenv("GAI");
260 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
261 translate = YES;
262 }
263 firsttime = 0;
264 }
265#endif
266
267 /* initialize file static vars */
268 sentinel.ai_next = NULL;
269 cur = &sentinel;
270 pai = &ai;
271 pai->ai_flags = 0;
272 pai->ai_family = PF_UNSPEC;
273 pai->ai_socktype = GAI_ANY;
274 pai->ai_protocol = GAI_ANY;
275 pai->ai_addrlen = 0;
276 pai->ai_canonname = NULL;
277 pai->ai_addr = NULL;
278 pai->ai_next = NULL;
279 port = GAI_ANY;
280
281 if (hostname == NULL && servname == NULL)
282 return EAI_NONAME;
283 if (hints) {
284 /* error check for hints */
285 if (hints->ai_addrlen || hints->ai_canonname ||
286 hints->ai_addr || hints->ai_next)
287 ERR(EAI_BADHINTS); /* xxx */
288 if (hints->ai_flags & ~AI_MASK)
289 ERR(EAI_BADFLAGS);
290 switch (hints->ai_family) {
291 case PF_UNSPEC:
292 case PF_INET:
293#ifdef INET6
294 case PF_INET6:
295#endif
296 break;
297 default:
298 ERR(EAI_FAMILY);
299 }
300 memcpy(pai, hints, sizeof(*pai));
301 switch (pai->ai_socktype) {
302 case GAI_ANY:
303 switch (pai->ai_protocol) {
304 case GAI_ANY:
305 break;
306 case IPPROTO_UDP:
307 pai->ai_socktype = SOCK_DGRAM;
308 break;
309 case IPPROTO_TCP:
310 pai->ai_socktype = SOCK_STREAM;
311 break;
312 default:
313 pai->ai_socktype = SOCK_RAW;
314 break;
315 }
316 break;
317 case SOCK_RAW:
318 break;
319 case SOCK_DGRAM:
320 if (pai->ai_protocol != IPPROTO_UDP &&
321 pai->ai_protocol != GAI_ANY)
322 ERR(EAI_BADHINTS); /*xxx*/
323 pai->ai_protocol = IPPROTO_UDP;
324 break;
325 case SOCK_STREAM:
326 if (pai->ai_protocol != IPPROTO_TCP &&
327 pai->ai_protocol != GAI_ANY)
328 ERR(EAI_BADHINTS); /*xxx*/
329 pai->ai_protocol = IPPROTO_TCP;
330 break;
331 default:
332 ERR(EAI_SOCKTYPE);
Sjoerd Mullender6f848c12001-08-30 14:15:38 +0000333 /* unreachable */
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000334 }
335 }
336
337 /*
338 * service port
339 */
340 if (servname) {
341 if (str_isnumber(servname)) {
342 if (pai->ai_socktype == GAI_ANY) {
343 /* caller accept *GAI_ANY* socktype */
344 pai->ai_socktype = SOCK_DGRAM;
345 pai->ai_protocol = IPPROTO_UDP;
346 }
Martin v. Löwisc925b1532001-07-21 09:42:15 +0000347 port = htons((u_short)atoi(servname));
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000348 } else {
349 struct servent *sp;
350 char *proto;
351
352 proto = NULL;
353 switch (pai->ai_socktype) {
354 case GAI_ANY:
355 proto = NULL;
356 break;
357 case SOCK_DGRAM:
358 proto = "udp";
359 break;
360 case SOCK_STREAM:
361 proto = "tcp";
362 break;
363 default:
364 fprintf(stderr, "panic!\n");
365 break;
366 }
367 if ((sp = getservbyname(servname, proto)) == NULL)
368 ERR(EAI_SERVICE);
369 port = sp->s_port;
370 if (pai->ai_socktype == GAI_ANY)
371 if (strcmp(sp->s_proto, "udp") == 0) {
372 pai->ai_socktype = SOCK_DGRAM;
373 pai->ai_protocol = IPPROTO_UDP;
374 } else if (strcmp(sp->s_proto, "tcp") == 0) {
375 pai->ai_socktype = SOCK_STREAM;
376 pai->ai_protocol = IPPROTO_TCP;
377 } else
378 ERR(EAI_PROTOCOL); /*xxx*/
379 }
380 }
381
382 /*
383 * hostname == NULL.
384 * passive socket -> anyaddr (0.0.0.0 or ::)
385 * non-passive socket -> localhost (127.0.0.1 or ::1)
386 */
387 if (hostname == NULL) {
388 struct gai_afd *gai_afd;
389
390 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
391 if (!(pai->ai_family == PF_UNSPEC
392 || pai->ai_family == gai_afd->a_af)) {
393 continue;
394 }
395
396 if (pai->ai_flags & AI_PASSIVE) {
397 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
398 /* xxx meaningless?
399 * GET_CANONNAME(cur->ai_next, "anyaddr");
400 */
401 } else {
402 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
403 port);
404 /* xxx meaningless?
405 * GET_CANONNAME(cur->ai_next, "localhost");
406 */
407 }
408 cur = cur->ai_next;
409 }
410 top = sentinel.ai_next;
411 if (top)
412 goto good;
413 else
414 ERR(EAI_FAMILY);
415 }
416
417 /* hostname as numeric name */
418 for (i = 0; gai_afdl[i].a_af; i++) {
419 if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
420 u_long v4a;
Martin v. Löwisc925b1532001-07-21 09:42:15 +0000421#ifdef INET6
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000422 u_char pfx;
Martin v. Löwisc925b1532001-07-21 09:42:15 +0000423#endif
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000424
425 switch (gai_afdl[i].a_af) {
426 case AF_INET:
427 v4a = ((struct in_addr *)pton)->s_addr;
428 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
429 pai->ai_flags &= ~AI_CANONNAME;
430 v4a >>= IN_CLASSA_NSHIFT;
431 if (v4a == 0 || v4a == IN_LOOPBACKNET)
432 pai->ai_flags &= ~AI_CANONNAME;
433 break;
434#ifdef INET6
435 case AF_INET6:
436 pfx = ((struct in6_addr *)pton)->s6_addr8[0];
437 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
438 pai->ai_flags &= ~AI_CANONNAME;
439 break;
440#endif
441 }
442
443 if (pai->ai_family == gai_afdl[i].a_af ||
444 pai->ai_family == PF_UNSPEC) {
445 if (! (pai->ai_flags & AI_CANONNAME)) {
446 GET_AI(top, &gai_afdl[i], pton, port);
447 goto good;
448 }
449 /*
450 * if AI_CANONNAME and if reverse lookup
451 * fail, return ai anyway to pacify
452 * calling application.
453 *
454 * XXX getaddrinfo() is a name->address
455 * translation function, and it looks strange
456 * that we do addr->name translation here.
457 */
458 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
459 goto good;
460 } else
461 ERR(EAI_FAMILY); /*xxx*/
462 }
463 }
464
465 if (pai->ai_flags & AI_NUMERICHOST)
466 ERR(EAI_NONAME);
467
468 /* hostname as alphabetical name */
469 error = get_addr(hostname, pai->ai_family, &top, pai, port);
470 if (error == 0) {
471 if (top) {
472 good:
473 *res = top;
474 return SUCCESS;
475 } else
476 error = EAI_FAIL;
477 }
478 free:
479 if (top)
480 freeaddrinfo(top);
481 bad:
482 *res = NULL;
483 return error;
484}
485
486static int
487get_name(addr, gai_afd, res, numaddr, pai, port0)
488 const char *addr;
489 struct gai_afd *gai_afd;
490 struct addrinfo **res;
491 char *numaddr;
492 struct addrinfo *pai;
493 int port0;
494{
495 u_short port = port0 & 0xffff;
496 struct hostent *hp;
497 struct addrinfo *cur;
Martin v. Löwisc925b1532001-07-21 09:42:15 +0000498 int error = 0;
499#ifdef INET6
500 int h_error;
501#endif
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000502
503#ifdef INET6
504 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
505#else
506 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
507#endif
508 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
509 GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
510 GET_CANONNAME(cur, hp->h_name);
511 } else
512 GET_AI(cur, gai_afd, numaddr, port);
513
514#ifdef INET6
515 if (hp)
516 freehostent(hp);
517#endif
518 *res = cur;
519 return SUCCESS;
520 free:
521 if (cur)
522 freeaddrinfo(cur);
523#ifdef INET6
524 if (hp)
525 freehostent(hp);
526#endif
527 /* bad: */
528 *res = NULL;
529 return error;
530}
531
532static int
533get_addr(hostname, af, res, pai, port0)
534 const char *hostname;
535 int af;
536 struct addrinfo **res;
537 struct addrinfo *pai;
538 int port0;
539{
540 u_short port = port0 & 0xffff;
541 struct addrinfo sentinel;
542 struct hostent *hp;
543 struct addrinfo *top, *cur;
544 struct gai_afd *gai_afd;
545 int i, error = 0, h_error;
546 char *ap;
Martin v. Löwis01dfdb32001-06-23 16:30:13 +0000547
548 top = NULL;
549 sentinel.ai_next = NULL;
550 cur = &sentinel;
551#ifdef INET6
552 if (af == AF_UNSPEC) {
553 hp = getipnodebyname(hostname, AF_INET6,
554 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
555 } else
556 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
557#else
558 hp = gethostbyname(hostname);
559 h_error = h_errno;
560#endif
561 if (hp == NULL) {
562 switch (h_error) {
563 case HOST_NOT_FOUND:
564 case NO_DATA:
565 error = EAI_NODATA;
566 break;
567 case TRY_AGAIN:
568 error = EAI_AGAIN;
569 break;
570 case NO_RECOVERY:
571 default:
572 error = EAI_FAIL;
573 break;
574 }
575 goto bad;
576 }
577
578 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
579 (hp->h_addr_list[0] == NULL))
580 ERR(EAI_FAIL);
581
582 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
583 switch (af) {
584#ifdef INET6
585 case AF_INET6:
586 gai_afd = &gai_afdl[N_INET6];
587 break;
588#endif
589#ifndef INET6
590 default: /* AF_UNSPEC */
591#endif
592 case AF_INET:
593 gai_afd = &gai_afdl[N_INET];
594 break;
595#ifdef INET6
596 default: /* AF_UNSPEC */
597 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
598 ap += sizeof(struct in6_addr) -
599 sizeof(struct in_addr);
600 gai_afd = &gai_afdl[N_INET];
601 } else
602 gai_afd = &gai_afdl[N_INET6];
603 break;
604#endif
605 }
606#ifdef FAITH
607 if (translate && gai_afd->a_af == AF_INET) {
608 struct in6_addr *in6;
609
610 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
611 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
612 memcpy(&in6->s6_addr32[0], &faith_prefix,
613 sizeof(struct in6_addr) - sizeof(struct in_addr));
614 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
615 } else
616#endif /* FAITH */
617 GET_AI(cur->ai_next, gai_afd, ap, port);
618 if (cur == &sentinel) {
619 top = cur->ai_next;
620 GET_CANONNAME(top, hp->h_name);
621 }
622 cur = cur->ai_next;
623 }
624#ifdef INET6
625 freehostent(hp);
626#endif
627 *res = top;
628 return SUCCESS;
629 free:
630 if (top)
631 freeaddrinfo(top);
632#ifdef INET6
633 if (hp)
634 freehostent(hp);
635#endif
636 bad:
637 *res = NULL;
638 return error;
639}