]>
jfr.im git - solanum.git/blob - authd/getaddrinfo.c
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
32 #include "getaddrinfo.h"
35 static const char in_addrany
[] = { 0, 0, 0, 0 };
36 static const char in_loopback
[] = { 127, 0, 0, 1 };
37 static const char in6_addrany
[] = {
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
40 static const char in6_loopback
[] = {
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
44 static const struct afd
{
49 const char *a_addrany
;
50 const char *a_loopback
;
55 {PF_INET6
, sizeof(struct in6_addr
),
56 sizeof(struct sockaddr_in6
),
57 offsetof(struct sockaddr_in6
, sin6_addr
),
58 in6_addrany
, in6_loopback
, 1},
61 {PF_INET
, sizeof(struct in_addr
),
62 sizeof(struct sockaddr_in
),
63 offsetof(struct sockaddr_in
, sin_addr
),
64 in_addrany
, in_loopback
, 0},
65 {0, 0, 0, 0, NULL
, NULL
, 0},
72 const char *e_protostr
;
74 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
75 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
76 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
79 static const struct explore explore
[] = {
81 { PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
82 { PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
83 { PF_INET6
, SOCK_RAW
, ANY
, NULL
, 0x05 },
85 { PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
86 { PF_INET
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
87 { PF_INET
, SOCK_RAW
, ANY
, NULL
, 0x05 },
88 { PF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
89 { PF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
90 { PF_UNSPEC
, SOCK_RAW
, ANY
, NULL
, 0x05 },
91 { -1, 0, 0, NULL
, 0 },
96 static bool str_isnumber(const char *);
97 static int explore_null(const struct rb_addrinfo
*,
98 const char *, struct rb_addrinfo
**);
99 static int explore_numeric(const struct rb_addrinfo
*, const char *,
100 const char *, struct rb_addrinfo
**);
101 static struct rb_addrinfo
*get_ai(const struct rb_addrinfo
*,
102 const struct afd
*, const char *);
103 static int get_portmatch(const struct rb_addrinfo
*, const char *);
104 static int get_port(struct rb_addrinfo
*, const char *, int);
105 static const struct afd
*find_afd(int);
107 /* We will need this should we ever want gai_strerror() */
108 static char *ai_errlist
[] = {
110 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
111 "Temporary failure in name resolution", /* EAI_AGAIN */
112 "Invalid value for ai_flags", /* EAI_BADFLAGS */
113 "Non-recoverable failure in name resolution", /* EAI_FAIL */
114 "ai_family not supported", /* EAI_FAMILY */
115 "Memory allocation failure", /* EAI_MEMORY */
116 "No address associated with hostname", /* EAI_NODATA */
117 "hostname nor servname provided, or not known", /* EAI_NONAME */
118 "servname not supported for ai_socktype", /* EAI_SERVICE */
119 "ai_socktype not supported", /* EAI_SOCKTYPE */
120 "System error returned in errno", /* EAI_SYSTEM */
121 "Invalid value for hints", /* EAI_BADHINTS */
122 "Resolved protocol is unknown", /* EAI_PROTOCOL */
123 "Unknown error", /* EAI_MAX */
126 /* XXX macros that make external reference is BAD. */
128 #define GET_AI(ai, afd, addr) \
130 /* external reference: pai, error, and label free */ \
131 (ai) = get_ai(pai, (afd), (addr)); \
132 if ((ai) == NULL) { \
133 error = EAI_MEMORY; \
136 } while (/*CONSTCOND*/0)
138 #define GET_PORT(ai, serv) \
140 /* external reference: error and label free */ \
141 error = get_port((ai), (serv), 0); \
144 } while (/*CONSTCOND*/0)
148 /* external reference: error, and label bad */ \
152 } while (/*CONSTCOND*/0)
154 #define MATCH_FAMILY(x, y, w) \
155 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
156 #define MATCH(x, y, w) \
157 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
160 /* We will need this should we ever want gai_strerror() */
162 gai_strerror(int ecode
)
164 if (ecode
< 0 || ecode
> EAI_MAX
)
166 return ai_errlist
[ecode
];
171 rb_freeaddrinfo(struct rb_addrinfo
*ai
)
173 struct rb_addrinfo
*next
;
177 if (ai
->ai_canonname
)
178 rb_free(ai
->ai_canonname
);
179 /* no need to free(ai->ai_addr) */
186 str_isnumber(const char *p
)
195 (void)strtoul(p
, &ep
, 10);
196 if (errno
== 0 && ep
&& *ep
== '\0')
203 rb_getaddrinfo(const char *hostname
, const char *servname
,
204 const struct rb_addrinfo
*hints
, struct rb_addrinfo
**res
)
206 struct rb_addrinfo sentinel
;
207 struct rb_addrinfo
*cur
;
209 struct rb_addrinfo ai
;
210 struct rb_addrinfo ai0
;
211 struct rb_addrinfo
*pai
;
212 const struct explore
*ex
;
214 memset(&sentinel
, 0, sizeof(sentinel
));
218 pai
->ai_family
= PF_UNSPEC
;
219 pai
->ai_socktype
= ANY
;
220 pai
->ai_protocol
= ANY
;
222 pai
->ai_canonname
= NULL
;
226 if (hostname
== NULL
&& servname
== NULL
)
229 /* error check for hints */
230 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
231 hints
->ai_addr
|| hints
->ai_next
)
232 ERR(EAI_BADHINTS
); /* xxx */
233 if (hints
->ai_flags
& ~AI_MASK
)
235 switch (hints
->ai_family
) {
245 memcpy(pai
, hints
, sizeof(*pai
));
248 * if both socktype/protocol are specified, check if they
249 * are meaningful combination.
251 if (pai
->ai_socktype
!= ANY
&& pai
->ai_protocol
!= ANY
) {
252 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
253 if (pai
->ai_family
!= ex
->e_af
)
255 if (ex
->e_socktype
== ANY
)
257 if (ex
->e_protocol
== ANY
)
259 if (pai
->ai_socktype
== ex
->e_socktype
&&
260 pai
->ai_protocol
!= ex
->e_protocol
) {
268 * check for special cases. (1) numeric servname is disallowed if
269 * socktype/protocol are left unspecified. (2) servname is disallowed
270 * for raw and other inet{,6} sockets.
272 if (MATCH_FAMILY(pai
->ai_family
, PF_INET
, 1)
274 || MATCH_FAMILY(pai
->ai_family
, PF_INET6
, 1)
277 ai0
= *pai
; /* backup *pai */
279 if (pai
->ai_family
== PF_UNSPEC
) {
281 pai
->ai_family
= PF_INET6
;
283 pai
->ai_family
= PF_INET
;
286 error
= get_portmatch(pai
, servname
);
295 /* NULL hostname, or numeric hostname */
296 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
299 /* PF_UNSPEC entries are prepared for DNS queries only */
300 if (ex
->e_af
== PF_UNSPEC
)
303 if (!MATCH_FAMILY(pai
->ai_family
, ex
->e_af
, WILD_AF(ex
)))
305 if (!MATCH(pai
->ai_socktype
, ex
->e_socktype
, WILD_SOCKTYPE(ex
)))
307 if (!MATCH(pai
->ai_protocol
, ex
->e_protocol
, WILD_PROTOCOL(ex
)))
310 if (pai
->ai_family
== PF_UNSPEC
)
311 pai
->ai_family
= ex
->e_af
;
312 if (pai
->ai_socktype
== ANY
&& ex
->e_socktype
!= ANY
)
313 pai
->ai_socktype
= ex
->e_socktype
;
314 if (pai
->ai_protocol
== ANY
&& ex
->e_protocol
!= ANY
)
315 pai
->ai_protocol
= ex
->e_protocol
;
317 if (hostname
== NULL
)
318 error
= explore_null(pai
, servname
, &cur
->ai_next
);
320 error
= explore_numeric(pai
, hostname
, servname
, &cur
->ai_next
);
325 while (cur
&& cur
->ai_next
)
331 * If numreic representation of AF1 can be interpreted as FQDN
332 * representation of AF2, we need to think again about the code below.
334 if (sentinel
.ai_next
)
337 if (pai
->ai_flags
& AI_NUMERICHOST
)
339 if (hostname
== NULL
)
343 if (sentinel
.ai_next
)
349 if (sentinel
.ai_next
) {
351 *res
= sentinel
.ai_next
;
358 if (sentinel
.ai_next
)
359 rb_freeaddrinfo(sentinel
.ai_next
);
366 * passive socket -> anyaddr (0.0.0.0 or ::)
367 * non-passive socket -> localhost (127.0.0.1 or ::1)
370 explore_null(const struct rb_addrinfo
*pai
, const char *servname
, struct rb_addrinfo
**res
)
373 const struct afd
*afd
;
374 struct rb_addrinfo
*cur
;
375 struct rb_addrinfo sentinel
;
379 sentinel
.ai_next
= NULL
;
383 * filter out AFs that are not supported by the kernel
386 s
= socket(pai
->ai_family
, SOCK_DGRAM
, 0);
389 errno
= WSAGetLastError();
401 * if the servname does not match socktype/protocol, ignore it.
403 if (get_portmatch(pai
, servname
) != 0)
406 afd
= find_afd(pai
->ai_family
);
410 if (pai
->ai_flags
& AI_PASSIVE
) {
411 GET_AI(cur
->ai_next
, afd
, afd
->a_addrany
);
412 GET_PORT(cur
->ai_next
, servname
);
414 GET_AI(cur
->ai_next
, afd
, afd
->a_loopback
);
415 GET_PORT(cur
->ai_next
, servname
);
419 *res
= sentinel
.ai_next
;
423 if (sentinel
.ai_next
)
424 rb_freeaddrinfo(sentinel
.ai_next
);
432 explore_numeric(const struct rb_addrinfo
*pai
, const char *hostname
,
433 const char *servname
, struct rb_addrinfo
**res
)
435 const struct afd
*afd
;
436 struct rb_addrinfo
*cur
;
437 struct rb_addrinfo sentinel
;
442 sentinel
.ai_next
= NULL
;
446 * if the servname does not match socktype/protocol, ignore it.
448 if (get_portmatch(pai
, servname
) != 0)
451 afd
= find_afd(pai
->ai_family
);
456 #if 0 /*X/Open spec*/
459 if (inet_aton(hostname
, (struct in_addr
*)pton
) == 1) {
460 if (pai
->ai_family
== afd
->a_af
||
461 pai
->ai_family
== PF_UNSPEC
/*?*/) {
462 GET_AI(cur
->ai_next
, afd
, pton
);
463 GET_PORT(cur
->ai_next
, servname
);
464 while (cur
&& cur
->ai_next
)
467 ERR(EAI_FAMILY
); /*xxx*/
472 if (rb_inet_pton(afd
->a_af
, hostname
, pton
) == 1) {
473 if (pai
->ai_family
== afd
->a_af
||
474 pai
->ai_family
== PF_UNSPEC
/*?*/) {
475 GET_AI(cur
->ai_next
, afd
, pton
);
476 GET_PORT(cur
->ai_next
, servname
);
477 while (cur
&& cur
->ai_next
)
480 ERR(EAI_FAMILY
); /* XXX */
485 *res
= sentinel
.ai_next
;
490 if (sentinel
.ai_next
)
491 rb_freeaddrinfo(sentinel
.ai_next
);
495 static struct rb_addrinfo
*
496 get_ai(const struct rb_addrinfo
*pai
, const struct afd
*afd
, const char *addr
)
499 struct rb_addrinfo
*ai
;
501 ai
= (struct rb_addrinfo
*)rb_malloc(sizeof(struct rb_addrinfo
)
506 memcpy(ai
, pai
, sizeof(struct rb_addrinfo
));
507 ai
->ai_addr
= (struct sockaddr
*)(void *)(ai
+ 1);
508 memset(ai
->ai_addr
, 0, (size_t)afd
->a_socklen
);
509 ai
->ai_addrlen
= afd
->a_socklen
;
510 ai
->ai_addr
->sa_family
= ai
->ai_family
= afd
->a_af
;
511 p
= (char *)(void *)(ai
->ai_addr
);
512 memcpy(p
+ afd
->a_off
, addr
, (size_t)afd
->a_addrlen
);
517 get_portmatch(const struct rb_addrinfo
*ai
, const char *servname
)
519 struct rb_addrinfo xai
;
520 memcpy(&xai
, ai
, sizeof(struct rb_addrinfo
));
521 return(get_port(&xai
, servname
, 1));
525 get_port(struct rb_addrinfo
*ai
, const char *servname
, int matchonly
)
532 if (servname
== NULL
)
534 switch (ai
->ai_family
) {
544 switch (ai
->ai_socktype
) {
558 if (str_isnumber(servname
)) {
561 port
= atoi(servname
);
562 if (port
< 0 || port
> 65535)
566 switch (ai
->ai_socktype
) {
578 if ((sp
= getservbyname(servname
, proto
)) == NULL
)
584 switch (ai
->ai_family
) {
586 ((struct sockaddr_in
*)(void *)
587 ai
->ai_addr
)->sin_port
= port
;
591 ((struct sockaddr_in6
*)(void *)
592 ai
->ai_addr
)->sin6_port
= port
;
601 static const struct afd
*
604 const struct afd
*afd
;
609 for (afd
= afdl
; afd
->a_af
; afd
++)