2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * 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 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 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
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.
41 #include "ruby/config.h"
42 #include <sys/types.h>
44 #include <sys/param.h>
45 #if defined(__BEOS__) && !defined(__HAIKU__)
46 # include <net/socket.h>
48 # include <sys/socket.h>
50 #include <netinet/in.h>
51 #if defined(HAVE_ARPA_INET_H)
52 #include <arpa/inet.h>
54 #if defined(HAVE_ARPA_NAMESER_H)
55 #include <arpa/nameser.h>
58 #if defined(HAVE_RESOLV_H)
82 #if defined(__KAME__) && defined(INET6)
92 static int translate
= NO
;
93 static struct in6_addr faith_prefix
= IN6ADDR_ANY_INIT
;
96 static const char in_addrany
[] = { 0, 0, 0, 0 };
97 static const char in6_addrany
[] = {
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
100 static const char in_loopback
[] = { 127, 0, 0, 1 };
101 static const char in6_loopback
[] = {
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
111 static const struct afd
{
116 const char *a_addrany
;
117 const char *a_loopback
;
121 {PF_INET6
, sizeof(struct in6_addr
),
122 sizeof(struct sockaddr_in6
),
123 offsetof(struct sockaddr_in6
, sin6_addr
),
124 in6_addrany
, in6_loopback
},
129 {PF_INET
, sizeof(struct in_addr
),
130 sizeof(struct sockaddr_in
),
131 offsetof(struct sockaddr_in
, sin_addr
),
132 in_addrany
, in_loopback
},
133 {0, 0, 0, 0, NULL
, NULL
},
142 static int get_name
__P((const char *, const struct afd
*,
143 struct addrinfo
**, char *, struct addrinfo
*,
145 static int get_addr
__P((const char *, int, struct addrinfo
**,
146 struct addrinfo
*, int));
147 static int str_isnumber
__P((const char *));
149 static const char *const ai_errlist
[] = {
151 "address family for hostname not supported.", /* EAI_ADDRFAMILY */
152 "temporary failure in name resolution.", /* EAI_AGAIN */
153 "invalid value for ai_flags.", /* EAI_BADFLAGS */
154 "non-recoverable failure in name resolution.", /* EAI_FAIL */
155 "ai_family not supported.", /* EAI_FAMILY */
156 "memory allocation failure.", /* EAI_MEMORY */
157 "no address associated with hostname.", /* EAI_NODATA */
158 "hostname nor servname provided, or not known.",/* EAI_NONAME */
159 "servname not supported for ai_socktype.", /* EAI_SERVICE */
160 "ai_socktype not supported.", /* EAI_SOCKTYPE */
161 "system error returned in errno.", /* EAI_SYSTEM */
162 "invalid value for hints.", /* EAI_BADHINTS */
163 "resolved protocol is unknown.", /* EAI_PROTOCOL */
164 "unknown error.", /* EAI_MAX */
167 #define GET_CANONNAME(ai, str) \
168 if (pai->ai_flags & AI_CANONNAME) {\
169 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
170 strcpy((ai)->ai_canonname, (str));\
177 #define GET_AI(ai, afd, addr, port) {\
179 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
180 ((afd)->a_socklen)))\
185 memcpy(ai, pai, sizeof(struct addrinfo));\
186 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
187 memset((ai)->ai_addr, 0, (afd)->a_socklen);\
188 SET_SA_LEN((ai)->ai_addr, (ai)->ai_addrlen = (afd)->a_socklen);\
189 (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
190 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
191 p = (char *)((ai)->ai_addr);\
192 memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
195 #define ERR(err) { error = (err); goto bad; }
198 #if defined __UCLIBC__
202 gai_strerror(int ecode
)
204 if (ecode
< 0 || ecode
> EAI_MAX
)
206 return (char *)ai_errlist
[ecode
];
211 freeaddrinfo(struct addrinfo
*ai
)
213 struct addrinfo
*next
;
217 if (ai
->ai_canonname
)
218 free(ai
->ai_canonname
);
219 /* no need to free(ai->ai_addr) */
221 } while ((ai
= next
) != NULL
);
225 str_isnumber(const char *p
)
236 #ifndef HAVE_INET_PTON
239 inet_pton(int af
, const char *hostname
, void *pton
)
243 #ifdef HAVE_INET_ATON
244 if (!inet_aton(hostname
, &in
))
250 if (sscanf(hostname
, "%d.%d.%d.%d%c", &d1
, &d2
, &d3
, &d4
, &ch
) == 4 &&
251 0 <= d1
&& d1
<= 255 && 0 <= d2
&& d2
<= 255 &&
252 0 <= d3
&& d3
<= 255 && 0 <= d4
&& d4
<= 255) {
254 ((long) d1
<< 24) | ((long) d2
<< 16) |
255 ((long) d3
<< 8) | ((long) d4
<< 0));
261 memcpy(pton
, &in
, sizeof(in
));
267 getaddrinfo(const char *hostname
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
269 struct addrinfo sentinel
;
270 struct addrinfo
*top
= NULL
;
271 struct addrinfo
*cur
;
275 struct addrinfo
*pai
;
279 static int firsttime
= 1;
282 /* translator hack */
284 char *q
= getenv("GAI");
285 if (q
&& inet_pton(AF_INET6
, q
, &faith_prefix
) == 1)
292 /* initialize file static vars */
293 sentinel
.ai_next
= NULL
;
297 pai
->ai_family
= PF_UNSPEC
;
298 pai
->ai_socktype
= ANY
;
299 pai
->ai_protocol
= ANY
;
301 pai
->ai_canonname
= NULL
;
306 if (hostname
== NULL
&& servname
== NULL
)
309 /* error check for hints */
310 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
311 hints
->ai_addr
|| hints
->ai_next
)
312 ERR(EAI_BADHINTS
); /* xxx */
313 if (hints
->ai_flags
& ~AI_MASK
)
315 switch (hints
->ai_family
) {
325 memcpy(pai
, hints
, sizeof(*pai
));
326 switch (pai
->ai_socktype
) {
328 switch (pai
->ai_protocol
) {
332 pai
->ai_socktype
= SOCK_DGRAM
;
335 pai
->ai_socktype
= SOCK_STREAM
;
338 #if defined(SOCK_RAW)
339 pai
->ai_socktype
= SOCK_RAW
;
344 #if defined(SOCK_RAW)
349 if (pai
->ai_protocol
!= IPPROTO_UDP
&&
350 pai
->ai_protocol
!= ANY
)
351 ERR(EAI_BADHINTS
); /*xxx*/
352 pai
->ai_protocol
= IPPROTO_UDP
;
355 if (pai
->ai_protocol
!= IPPROTO_TCP
&&
356 pai
->ai_protocol
!= ANY
)
357 ERR(EAI_BADHINTS
); /*xxx*/
358 pai
->ai_protocol
= IPPROTO_TCP
;
370 if (str_isnumber(servname
)) {
371 if (pai
->ai_socktype
== ANY
) {
372 /* caller accept *ANY* socktype */
373 pai
->ai_socktype
= SOCK_DGRAM
;
374 pai
->ai_protocol
= IPPROTO_UDP
;
376 port
= htons((unsigned short)atoi(servname
));
382 switch (pai
->ai_socktype
) {
393 fprintf(stderr
, "panic!\n");
396 if ((sp
= getservbyname((char*)servname
, proto
)) == NULL
)
399 if (pai
->ai_socktype
== ANY
)
400 if (strcmp(sp
->s_proto
, "udp") == 0) {
401 pai
->ai_socktype
= SOCK_DGRAM
;
402 pai
->ai_protocol
= IPPROTO_UDP
;
403 } else if (strcmp(sp
->s_proto
, "tcp") == 0) {
404 pai
->ai_socktype
= SOCK_STREAM
;
405 pai
->ai_protocol
= IPPROTO_TCP
;
407 ERR(EAI_PROTOCOL
); /*xxx*/
413 * passive socket -> anyaddr (0.0.0.0 or ::)
414 * non-passive socket -> localhost (127.0.0.1 or ::1)
416 if (hostname
== NULL
) {
417 const struct afd
*afd
;
420 for (afd
= &afdl
[0]; afd
->a_af
; afd
++) {
421 if (!(pai
->ai_family
== PF_UNSPEC
422 || pai
->ai_family
== afd
->a_af
)) {
427 * filter out AFs that are not supported by the kernel
430 s
= socket(afd
->a_af
, SOCK_DGRAM
, 0);
433 #if defined(__BEOS__)
439 if (pai
->ai_flags
& AI_PASSIVE
) {
440 GET_AI(cur
->ai_next
, afd
, afd
->a_addrany
, port
);
442 * GET_CANONNAME(cur->ai_next, "anyaddr");
445 GET_AI(cur
->ai_next
, afd
, afd
->a_loopback
,
448 * GET_CANONNAME(cur->ai_next, "localhost");
453 top
= sentinel
.ai_next
;
460 /* hostname as numeric name */
461 for (i
= 0; afdl
[i
].a_af
; i
++) {
462 if (inet_pton(afdl
[i
].a_af
, hostname
, pton
)) {
468 switch (afdl
[i
].a_af
) {
470 v4a
= ((struct in_addr
*)pton
)->s_addr
;
471 if (IN_MULTICAST(v4a
) || IN_EXPERIMENTAL(v4a
))
472 pai
->ai_flags
&= ~AI_CANONNAME
;
473 v4a
>>= IN_CLASSA_NSHIFT
;
474 if (v4a
== 0 || v4a
== IN_LOOPBACKNET
)
475 pai
->ai_flags
&= ~AI_CANONNAME
;
480 pfx
= ((struct in6_addr
*)pton
)->s6_addr8
[0];
482 pfx
= ((struct in6_addr
*)pton
)->s6_addr
[0];
484 if (pfx
== 0 || pfx
== 0xfe || pfx
== 0xff)
485 pai
->ai_flags
&= ~AI_CANONNAME
;
490 if (pai
->ai_family
== afdl
[i
].a_af
||
491 pai
->ai_family
== PF_UNSPEC
) {
492 if (! (pai
->ai_flags
& AI_CANONNAME
)) {
493 GET_AI(top
, &afdl
[i
], pton
, port
);
497 * if AI_CANONNAME and if reverse lookup
498 * fail, return ai anyway to pacify
499 * calling application.
501 * XXX getaddrinfo() is a name->address
502 * translation function, and it looks strange
503 * that we do addr->name translation here.
505 get_name(pton
, &afdl
[i
], &top
, pton
, pai
, port
);
508 ERR(EAI_FAMILY
); /*xxx*/
512 if (pai
->ai_flags
& AI_NUMERICHOST
)
515 /* hostname as alphabetical name */
516 error
= get_addr(hostname
, pai
->ai_family
, &top
, pai
, port
);
534 get_name(const char *addr
, const struct afd
*afd
, struct addrinfo
**res
, char *numaddr
, struct addrinfo
*pai
, int port0
)
536 u_short port
= port0
& 0xffff;
538 struct addrinfo
*cur
;
545 hp
= getipnodebyaddr(addr
, afd
->a_addrlen
, afd
->a_af
, &h_error
);
547 hp
= gethostbyaddr((char*)addr
, afd
->a_addrlen
, AF_INET
);
549 if (hp
&& hp
->h_name
&& hp
->h_name
[0] && hp
->h_addr_list
[0]) {
550 GET_AI(cur
, afd
, hp
->h_addr_list
[0], port
);
551 GET_CANONNAME(cur
, hp
->h_name
);
553 GET_AI(cur
, afd
, numaddr
, port
);
574 get_addr(const char *hostname
, int af
, struct addrinfo
**res
, struct addrinfo
*pai
, int port0
)
576 u_short port
= port0
& 0xffff;
577 struct addrinfo sentinel
;
579 struct addrinfo
*top
, *cur
;
580 const struct afd
*afd
;
581 int i
, error
= 0, h_error
;
585 sentinel
.ai_next
= NULL
;
588 if (af
== AF_UNSPEC
) {
589 hp
= getipnodebyname(hostname
, AF_INET6
,
590 AI_ADDRCONFIG
|AI_ALL
|AI_V4MAPPED
, &h_error
);
592 hp
= getipnodebyname(hostname
, af
, AI_ADDRCONFIG
, &h_error
);
594 hp
= gethostbyname((char*)hostname
);
614 if ((hp
->h_name
== NULL
) || (hp
->h_name
[0] == 0) ||
615 (hp
->h_addr_list
[0] == NULL
))
618 for (i
= 0; (ap
= hp
->h_addr_list
[i
]) != NULL
; i
++) {
622 afd
= &afdl
[N_INET6
];
626 default: /* AF_UNSPEC */
632 default: /* AF_UNSPEC */
633 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr
*)ap
)) {
634 ap
+= sizeof(struct in6_addr
) -
635 sizeof(struct in_addr
);
638 afd
= &afdl
[N_INET6
];
643 if (translate
&& afd
->a_af
== AF_INET
) {
644 struct in6_addr
*in6
;
646 GET_AI(cur
->ai_next
, &afdl
[N_INET6
], ap
, port
);
647 in6
= &((struct sockaddr_in6
*)cur
->ai_next
->ai_addr
)->sin6_addr
;
648 memcpy(&in6
->s6_addr32
[0], &faith_prefix
,
649 sizeof(struct in6_addr
) - sizeof(struct in_addr
));
650 memcpy(&in6
->s6_addr32
[3], ap
, sizeof(struct in_addr
));
653 GET_AI(cur
->ai_next
, afd
, ap
, port
);
654 if (cur
== &sentinel
) {
656 GET_CANONNAME(top
, hp
->h_name
);