4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
53 static const char in_addrany
[] = { 0, 0, 0, 0 };
54 static const char in6_addrany
[] = {
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
57 static const char in_loopback
[] = { 127, 0, 0, 1 };
58 static const char in6_loopback
[] = {
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
73 const char *a_addrany
;
74 const char *a_loopback
;
78 {PF_INET6
, sizeof(struct in6_addr
),
79 sizeof(struct sockaddr_in6
),
80 offsetof(struct sockaddr_in6
, sin6_addr
),
81 in6_addrany
, in6_loopback
},
86 {PF_INET
, sizeof(struct in_addr
),
87 sizeof(struct sockaddr_in
),
88 offsetof(struct sockaddr_in
, sin_addr
),
89 in_addrany
, in_loopback
},
90 {0, 0, 0, 0, NULL
, NULL
},
100 static int get_name(const char *, struct afd
*,
101 struct addrinfo
**, char *, struct addrinfo
*,
103 static int get_addr(const char *, int, struct addrinfo
**,
104 struct addrinfo
*, int);
105 static int get_addr0(const char *, int, struct addrinfo
**,
106 struct addrinfo
*, int);
107 static int str_isnumber(const char *);
109 static char *ai_errlist
[] = {
111 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
112 "Temporary failure in name resolution", /* EAI_AGAIN */
113 "Invalid value for ai_flags", /* EAI_BADFLAGS */
114 "Non-recoverable failure in name resolution", /* EAI_FAIL */
115 "ai_family not supported", /* EAI_FAMILY */
116 "Memory allocation failure", /* EAI_MEMORY */
117 "No address associated with hostname", /* EAI_NODATA */
118 "hostname nor servname provided, or not known",/* EAI_NONAME */
119 "servname not supported for ai_socktype", /* EAI_SERVICE */
120 "ai_socktype not supported", /* EAI_SOCKTYPE */
121 "System error returned in errno", /* EAI_SYSTEM */
122 "Invalid value for hints", /* EAI_BADHINTS */
123 "Resolved protocol is unknown", /* EAI_PROTOCOL */
124 "Unknown error", /* EAI_MAX */
127 #define GET_CANONNAME(ai, str) \
128 if (pai->ai_flags & AI_CANONNAME) {\
129 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
130 strcpy((ai)->ai_canonname, (str));\
138 #define SET_AILEN(ai,l) (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (l)
140 #define SET_AILEN(ai,l) (ai)->ai_addrlen = (l)
143 #define GET_AI(ai, afd, addr, port) {\
145 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
146 ((afd)->a_socklen)))\
151 memcpy(ai, pai, sizeof(struct addrinfo));\
152 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
153 memset((ai)->ai_addr, 0, (afd)->a_socklen);\
154 SET_AILEN((ai), (afd)->a_socklen);\
155 (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
156 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
157 p = (char *)((ai)->ai_addr);\
158 memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
161 #define ERR(err) { error = (err); goto bad; }
167 if (ecode
< 0 || ecode
> EAI_MAX
)
169 return ai_errlist
[ecode
];
176 struct addrinfo
*next
;
180 if (ai
->ai_canonname
)
181 free(ai
->ai_canonname
);
182 /* no need to free(ai->ai_addr) */
184 } while ((ai
= next
) != NULL
);
201 getaddrinfo(hostname
, servname
, hints
, res
)
202 const char *hostname
, *servname
;
203 const struct addrinfo
*hints
;
204 struct addrinfo
**res
;
206 struct addrinfo sentinel
;
207 struct addrinfo
*top
= NULL
;
208 struct addrinfo
*cur
;
212 struct addrinfo
*pai
;
215 /* initialize file static vars */
216 sentinel
.ai_next
= NULL
;
220 pai
->ai_family
= PF_UNSPEC
;
221 pai
->ai_socktype
= ANY
;
222 pai
->ai_protocol
= ANY
;
224 pai
->ai_canonname
= NULL
;
229 if (hostname
== NULL
&& servname
== NULL
)
232 /* error check for hints */
233 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
234 hints
->ai_addr
|| hints
->ai_next
)
235 ERR(EAI_BADHINTS
); /* xxx */
236 if (hints
->ai_flags
& ~AI_MASK
)
238 switch (hints
->ai_family
) {
248 memcpy(pai
, hints
, sizeof(*pai
));
249 switch (pai
->ai_socktype
) {
251 switch (pai
->ai_protocol
) {
255 pai
->ai_socktype
= SOCK_DGRAM
;
258 pai
->ai_socktype
= SOCK_STREAM
;
261 pai
->ai_socktype
= SOCK_RAW
;
268 if (pai
->ai_protocol
!= IPPROTO_UDP
&&
269 pai
->ai_protocol
!= ANY
)
270 ERR(EAI_BADHINTS
); /*xxx*/
271 pai
->ai_protocol
= IPPROTO_UDP
;
274 if (pai
->ai_protocol
!= IPPROTO_TCP
&&
275 pai
->ai_protocol
!= ANY
)
276 ERR(EAI_BADHINTS
); /*xxx*/
277 pai
->ai_protocol
= IPPROTO_TCP
;
289 if (str_isnumber(servname
)) {
290 if (pai
->ai_socktype
== ANY
) {
291 /* caller accept *ANY* socktype */
292 pai
->ai_socktype
= SOCK_DGRAM
;
293 pai
->ai_protocol
= IPPROTO_UDP
;
295 port
= htons(atoi(servname
));
301 switch (pai
->ai_socktype
) {
312 fprintf(stderr
, "panic!\n");
315 if ((sp
= getservbyname(servname
, proto
)) == NULL
)
318 if (pai
->ai_socktype
== ANY
) {
319 if (strcmp(sp
->s_proto
, "udp") == 0) {
320 pai
->ai_socktype
= SOCK_DGRAM
;
321 pai
->ai_protocol
= IPPROTO_UDP
;
322 } else if (strcmp(sp
->s_proto
, "tcp") == 0) {
323 pai
->ai_socktype
= SOCK_STREAM
;
324 pai
->ai_protocol
= IPPROTO_TCP
;
326 ERR(EAI_PROTOCOL
); /*xxx*/
333 * passive socket -> anyaddr (0.0.0.0 or ::)
334 * non-passive socket -> localhost (127.0.0.1 or ::1)
336 if (hostname
== NULL
) {
340 for (afd
= &afdl
[0]; afd
->a_af
; afd
++) {
341 if (!(pai
->ai_family
== PF_UNSPEC
342 || pai
->ai_family
== afd
->a_af
)) {
347 * filter out AFs that are not supported by the kernel
350 s
= socket(afd
->a_af
, SOCK_DGRAM
, 0);
355 if (pai
->ai_flags
& AI_PASSIVE
) {
356 GET_AI(cur
->ai_next
, afd
, afd
->a_addrany
, port
);
358 * GET_CANONNAME(cur->ai_next, "anyaddr");
361 GET_AI(cur
->ai_next
, afd
, afd
->a_loopback
,
364 * GET_CANONNAME(cur->ai_next, "localhost");
369 top
= sentinel
.ai_next
;
376 /* hostname as numeric name */
377 for (i
= 0; afdl
[i
].a_af
; i
++) {
378 if (inet_pton(afdl
[i
].a_af
, hostname
, pton
) == 1) {
382 switch (afdl
[i
].a_af
) {
384 v4a
= ntohl(((struct in_addr
*)pton
)->s_addr
);
385 if (IN_MULTICAST(v4a
) || IN_EXPERIMENTAL(v4a
))
386 pai
->ai_flags
&= ~AI_CANONNAME
;
387 v4a
>>= IN_CLASSA_NSHIFT
;
388 if (v4a
== 0 || v4a
== IN_LOOPBACKNET
)
389 pai
->ai_flags
&= ~AI_CANONNAME
;
393 pfx
= ((struct in6_addr
*)pton
)->s6_addr
[0];
394 if (pfx
== 0 || pfx
== 0xfe || pfx
== 0xff)
395 pai
->ai_flags
&= ~AI_CANONNAME
;
400 if (pai
->ai_family
== afdl
[i
].a_af
||
401 pai
->ai_family
== PF_UNSPEC
) {
402 if (! (pai
->ai_flags
& AI_CANONNAME
)) {
403 GET_AI(top
, &afdl
[i
], pton
, port
);
407 * if AI_CANONNAME and if reverse lookup
408 * fail, return ai anyway to pacify
409 * calling application.
411 * XXX getaddrinfo() is a name->address
412 * translation function, and it looks strange
413 * that we do addr->name translation here.
415 get_name(pton
, &afdl
[i
], &top
, pton
, pai
, port
);
418 ERR(EAI_FAMILY
); /*xxx*/
422 if (pai
->ai_flags
& AI_NUMERICHOST
)
425 /* hostname as alphabetical name */
426 error
= get_addr(hostname
, pai
->ai_family
, &top
, pai
, port
);
444 get_name(addr
, afd
, res
, numaddr
, pai
, port0
)
447 struct addrinfo
**res
;
449 struct addrinfo
*pai
;
452 u_short port
= port0
& 0xffff;
454 struct addrinfo
*cur
;
456 hp
= gethostbyaddr(addr
, afd
->a_addrlen
, afd
->a_af
);
457 if (hp
&& hp
->h_name
&& hp
->h_name
[0] && hp
->h_addr_list
[0]) {
458 GET_AI(cur
, afd
, hp
->h_addr_list
[0], port
);
459 GET_CANONNAME(cur
, hp
->h_name
);
461 GET_AI(cur
, afd
, numaddr
, port
);
475 get_addr(hostname
, af
, res0
, pai
, port0
)
476 const char *hostname
;
478 struct addrinfo
**res0
;
479 struct addrinfo
*pai
;
483 struct addrinfo
*cur
;
484 struct addrinfo
**res
;
491 for (i
= 0; afdl
[i
].a_af
; i
++) {
493 if (af
== AF_UNSPEC
) {
495 * filter out AFs that are not supported by the kernel
498 s
= socket(afdl
[i
].a_af
, SOCK_DGRAM
, 0);
503 if (af
!= afdl
[i
].a_af
)
506 /* It is WRONG, we need getipnodebyname(). */
508 error
= get_addr0(hostname
, afdl
[i
].a_af
, res
, pai
, port0
);
520 /* make chain of addrs */
531 /* if we got something, it's okay */
535 return error
? error
: ekeep
;
539 get_addr0(hostname
, af
, res
, pai
, port0
)
540 const char *hostname
;
542 struct addrinfo
**res
;
543 struct addrinfo
*pai
;
546 u_short port
= port0
& 0xffff;
547 struct addrinfo sentinel
;
549 struct addrinfo
*top
, *cur
;
551 int i
, error
= 0, h_error
;
555 sentinel
.ai_next
= NULL
;
558 #ifdef HAVE_GETHOSTBYNAME2
559 if (af
== AF_UNSPEC
) {
563 hp
= gethostbyname2(hostname
, af
);
565 if (af
!= AF_UNSPEC
&& af
!= AF_INET
) {
569 hp
= gethostbyname(hostname
);
591 if ((hp
->h_name
== NULL
) || (hp
->h_name
[0] == 0) ||
592 (hp
->h_addr_list
[0] == NULL
))
595 for (i
= 0; (ap
= hp
->h_addr_list
[i
]) != NULL
; i
++) {
599 afd
= &afdl
[N_INET6
];
603 default: /* AF_UNSPEC */
609 default: /* AF_UNSPEC */
610 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr
*)ap
)) {
611 ap
+= sizeof(struct in6_addr
) -
612 sizeof(struct in_addr
);
615 afd
= &afdl
[N_INET6
];
619 GET_AI(cur
->ai_next
, afd
, ap
, port
);
620 if (cur
== &sentinel
) {
622 GET_CANONNAME(top
, hp
->h_name
);