]>
git.ipfire.org Git - thirdparty/strongswan.git/blob - lib/liblwres/getaddrinfo.c
2 * Copyright (C) 1999-2001 Internet Software Consortium.
4 * This code is derived from software contributed to Internet Software
5 * Consortium by Berkeley Software Design, Inc.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM AND
12 * BERKELEY SOFTWARE DESIGN, INC DISCLAIM ALL WARRANTIES WITH REGARD TO
13 * THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
14 * FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE CONSORTIUM OR BERKELEY
15 * SOFTWARE DESIGN, INC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
17 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
22 /* $Id: getaddrinfo.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
30 #include <lwres/lwres.h>
31 #include <lwres/net.h>
32 #include <lwres/netdb.h>
34 #define SA(addr) ((struct sockaddr *)(addr))
35 #define SIN(addr) ((struct sockaddr_in *)(addr))
36 #define SIN6(addr) ((struct sockaddr_in6 *)(addr))
37 #define SUN(addr) ((struct sockaddr_un *)(addr))
39 static struct addrinfo
40 *ai_reverse(struct addrinfo
*oai
),
41 *ai_clone(struct addrinfo
*oai
, int family
),
42 *ai_alloc(int family
, int addrlen
);
44 static int get_local(const char *name
, int socktype
, struct addrinfo
**res
);
47 static int add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
48 int socktype
, int port
);
49 static int add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
50 int socktype
, int port
);
51 static void set_order(int, int (**)(const char *, int, struct addrinfo
**,
54 #define FOUND_IPV4 0x1
55 #define FOUND_IPV6 0x2
58 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
61 lwres_getaddrinfo(const char *hostname
, const char *servname
,
62 const struct addrinfo
*hints
, struct addrinfo
**res
)
66 int family
, socktype
, flags
, protocol
;
67 struct addrinfo
*ai
, *ai_list
;
69 int (*net_order
[FOUND_MAX
+1])(const char *, int, struct addrinfo
**,
72 if (hostname
== NULL
&& servname
== NULL
)
77 if ((hints
->ai_flags
& ~(ISC_AI_MASK
)) != 0)
78 return (EAI_BADFLAGS
);
79 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
80 hints
->ai_addr
|| hints
->ai_next
) {
84 family
= hints
->ai_family
;
85 socktype
= hints
->ai_socktype
;
86 protocol
= hints
->ai_protocol
;
87 flags
= hints
->ai_flags
;
90 switch (hints
->ai_socktype
) {
101 switch (hints
->ai_socktype
) {
113 return (EAI_SOCKTYPE
);
118 switch (hints
->ai_socktype
) {
126 return (EAI_SOCKTYPE
);
142 * First, deal with AF_LOCAL. If the family was not set,
143 * then assume AF_LOCAL if the first character of the
144 * hostname/servname is '/'.
147 if (hostname
!= NULL
&&
148 (family
== AF_LOCAL
|| (family
== 0 && *hostname
== '/')))
149 return (get_local(hostname
, socktype
, res
));
151 if (servname
!= NULL
&&
152 (family
== AF_LOCAL
|| (family
== 0 && *servname
== '/')))
153 return (get_local(servname
, socktype
, res
));
157 * Ok, only AF_INET and AF_INET6 left.
162 * First, look up the service name (port) if it was
163 * requested. If the socket type wasn't specified, then
164 * try and figure it out.
166 if (servname
!= NULL
) {
169 port
= strtol(servname
, &e
, 10);
172 return (EAI_SOCKTYPE
);
173 if (port
< 0 || port
> 65535)
174 return (EAI_SERVICE
);
175 port
= htons((unsigned short) port
);
177 sp
= getservbyname(servname
, proto
);
179 return (EAI_SERVICE
);
182 if (strcmp(sp
->s_proto
, "tcp") == 0)
183 socktype
= SOCK_STREAM
;
184 else if (strcmp(sp
->s_proto
, "udp") == 0)
185 socktype
= SOCK_DGRAM
;
192 * Next, deal with just a service name, and no hostname.
193 * (we verified that one of them was non-null up above).
195 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) != 0) {
196 if (family
== AF_INET
|| family
== 0) {
197 ai
= ai_alloc(AF_INET
, sizeof(struct sockaddr_in
));
200 ai
->ai_socktype
= socktype
;
201 ai
->ai_protocol
= protocol
;
202 SIN(ai
->ai_addr
)->sin_port
= port
;
203 ai
->ai_next
= ai_list
;
207 if (family
== AF_INET6
|| family
== 0) {
208 ai
= ai_alloc(AF_INET6
, sizeof(struct sockaddr_in6
));
210 lwres_freeaddrinfo(ai_list
);
213 ai
->ai_socktype
= socktype
;
214 ai
->ai_protocol
= protocol
;
215 SIN6(ai
->ai_addr
)->sin6_port
= port
;
216 ai
->ai_next
= ai_list
;
225 * If the family isn't specified or AI_NUMERICHOST specified,
226 * check first to see if it is a numeric address.
227 * Though the gethostbyname2() routine
228 * will recognize numeric addresses, it will only recognize
229 * the format that it is being called for. Thus, a numeric
230 * AF_INET address will be treated by the AF_INET6 call as
231 * a domain name, and vice versa. Checking for both numerics
234 if (hostname
!= NULL
&&
235 (family
== 0 || (flags
& AI_NUMERICHOST
) != 0)) {
236 char abuf
[sizeof(struct in6_addr
)];
237 char nbuf
[NI_MAXHOST
];
238 int addrsize
, addroff
;
239 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
241 char ntmp
[NI_MAXHOST
];
242 lwres_uint32_t scopeid
;
245 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
247 * Scope identifier portion.
250 if (strchr(hostname
, '%') != NULL
) {
251 strncpy(ntmp
, hostname
, sizeof(ntmp
) - 1);
252 ntmp
[sizeof(ntmp
) - 1] = '\0';
253 p
= strchr(ntmp
, '%');
257 * Vendors may want to support non-numeric
258 * scopeid around here.
262 scopeid
= (lwres_uint32_t
)strtoul(p
+ 1,
264 if (p
!= NULL
&& ep
!= NULL
&& ep
[0] == '\0')
274 if (lwres_net_pton(AF_INET
, hostname
, (struct in_addr
*)abuf
)
277 if (family
== AF_INET6
) {
279 * Convert to a V4 mapped address.
281 struct in6_addr
*a6
= (struct in6_addr
*)abuf
;
282 memcpy(&a6
->s6_addr
[12], &a6
->s6_addr
[0], 4);
283 memset(&a6
->s6_addr
[10], 0xff, 2);
284 memset(&a6
->s6_addr
[0], 0, 10);
287 addrsize
= sizeof(struct in_addr
);
288 addroff
= (char *)(&SIN(0)->sin_addr
) - (char *)0;
291 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
292 } else if (ntmp
[0] != '\0' &&
293 lwres_net_pton(AF_INET6
, ntmp
, abuf
) == 1)
295 if (family
&& family
!= AF_INET6
)
297 addrsize
= sizeof(struct in6_addr
);
298 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
302 } else if (lwres_net_pton(AF_INET6
, hostname
, abuf
) == 1) {
303 if (family
!= 0 && family
!= AF_INET6
)
306 addrsize
= sizeof(struct in6_addr
);
307 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
311 ai
= ai_clone(ai_list
, family
);
315 ai
->ai_socktype
= socktype
;
316 SIN(ai
->ai_addr
)->sin_port
= port
;
317 memcpy((char *)ai
->ai_addr
+ addroff
, abuf
, addrsize
);
318 if (flags
& AI_CANONNAME
) {
319 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
320 if (ai
->ai_family
== AF_INET6
)
321 SIN6(ai
->ai_addr
)->sin6_scope_id
=
324 if (lwres_getnameinfo(ai
->ai_addr
,
325 ai
->ai_addrlen
, nbuf
, sizeof(nbuf
),
327 NI_NUMERICHOST
) == 0) {
328 ai
->ai_canonname
= strdup(nbuf
);
329 if (ai
->ai_canonname
== NULL
)
332 /* XXX raise error? */
333 ai
->ai_canonname
= NULL
;
337 } else if ((flags
& AI_NUMERICHOST
) != 0) {
342 set_order(family
, net_order
);
343 for (i
= 0; i
< FOUND_MAX
; i
++) {
344 if (net_order
[i
] == NULL
)
346 err
= (net_order
[i
])(hostname
, flags
, &ai_list
,
356 ai_list
= ai_reverse(ai_list
);
363 lwres_strsep(char **stringp
, const char *delim
) {
364 char *string
= *stringp
;
372 for (s
= string
; *s
!= '\0'; s
++) {
374 for (d
= delim
; (dc
= *d
) != '\0'; d
++)
386 set_order(int family
, int (**net_order
)(const char *, int, struct addrinfo
**,
395 *net_order
++ = add_ipv4
;
398 *net_order
++ = add_ipv6
;
402 order
= getenv("NET_ORDER");
404 while (order
!= NULL
) {
406 * We ignore any unknown names.
408 tok
= lwres_strsep(&order
, ":");
409 if (strcasecmp(tok
, "inet6") == 0) {
410 if ((found
& FOUND_IPV6
) == 0)
411 *net_order
++ = add_ipv6
;
413 } else if (strcasecmp(tok
, "inet") == 0 ||
414 strcasecmp(tok
, "inet4") == 0) {
415 if ((found
& FOUND_IPV4
) == 0)
416 *net_order
++ = add_ipv4
;
422 * Add in anything that we didn't find.
424 if ((found
& FOUND_IPV4
) == 0)
425 *net_order
++ = add_ipv4
;
426 if ((found
& FOUND_IPV6
) == 0)
427 *net_order
++ = add_ipv6
;
433 static char v4_loop
[4] = { 127, 0, 0, 1 };
436 * The test against 0 is there to keep the Solaris compiler
437 * from complaining about "end-of-loop code not reached".
440 do { result = (code); \
441 if (result != 0) goto cleanup; \
445 add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
446 int socktype
, int port
)
449 lwres_context_t
*lwrctx
= NULL
;
450 lwres_gabnresponse_t
*by
= NULL
;
452 lwres_result_t lwres
;
455 lwres
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
456 if (lwres
!= LWRES_R_SUCCESS
)
458 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
459 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) == 0) {
460 ai
= ai_clone(*aip
, AF_INET
);
462 lwres_freeaddrinfo(*aip
);
467 ai
->ai_socktype
= socktype
;
468 SIN(ai
->ai_addr
)->sin_port
= port
;
469 memcpy(&SIN(ai
->ai_addr
)->sin_addr
, v4_loop
, 4);
471 lwres
= lwres_getaddrsbyname(lwrctx
, hostname
,
472 LWRES_ADDRTYPE_V4
, &by
);
473 if (lwres
!= LWRES_R_SUCCESS
) {
474 if (lwres
== LWRES_R_NOTFOUND
)
479 addr
= LWRES_LIST_HEAD(by
->addrs
);
480 while (addr
!= NULL
) {
481 ai
= ai_clone(*aip
, AF_INET
);
483 lwres_freeaddrinfo(*aip
);
487 ai
->ai_socktype
= socktype
;
488 SIN(ai
->ai_addr
)->sin_port
= port
;
489 memcpy(&SIN(ai
->ai_addr
)->sin_addr
,
491 if (flags
& AI_CANONNAME
) {
492 ai
->ai_canonname
= strdup(by
->realname
);
493 if (ai
->ai_canonname
== NULL
)
496 addr
= LWRES_LIST_NEXT(addr
, link
);
501 lwres_gabnresponse_free(lwrctx
, &by
);
502 if (lwrctx
!= NULL
) {
503 lwres_conf_clear(lwrctx
);
504 lwres_context_destroy(&lwrctx
);
509 static char v6_loop
[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
512 add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
513 int socktype
, int port
)
516 lwres_context_t
*lwrctx
= NULL
;
517 lwres_gabnresponse_t
*by
= NULL
;
519 lwres_result_t lwres
;
522 lwres
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
523 if (lwres
!= LWRES_R_SUCCESS
)
525 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
527 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) == 0) {
528 ai
= ai_clone(*aip
, AF_INET6
);
530 lwres_freeaddrinfo(*aip
);
535 ai
->ai_socktype
= socktype
;
536 SIN6(ai
->ai_addr
)->sin6_port
= port
;
537 memcpy(&SIN6(ai
->ai_addr
)->sin6_addr
, v6_loop
, 16);
539 lwres
= lwres_getaddrsbyname(lwrctx
, hostname
,
540 LWRES_ADDRTYPE_V6
, &by
);
541 if (lwres
!= LWRES_R_SUCCESS
) {
542 if (lwres
== LWRES_R_NOTFOUND
)
547 addr
= LWRES_LIST_HEAD(by
->addrs
);
548 while (addr
!= NULL
) {
549 ai
= ai_clone(*aip
, AF_INET6
);
551 lwres_freeaddrinfo(*aip
);
555 ai
->ai_socktype
= socktype
;
556 SIN6(ai
->ai_addr
)->sin6_port
= port
;
557 memcpy(&SIN6(ai
->ai_addr
)->sin6_addr
,
559 if (flags
& AI_CANONNAME
) {
560 ai
->ai_canonname
= strdup(by
->realname
);
561 if (ai
->ai_canonname
== NULL
)
564 addr
= LWRES_LIST_NEXT(addr
, link
);
569 lwres_gabnresponse_free(lwrctx
, &by
);
570 if (lwrctx
!= NULL
) {
571 lwres_conf_clear(lwrctx
);
572 lwres_context_destroy(&lwrctx
);
578 lwres_freeaddrinfo(struct addrinfo
*ai
) {
579 struct addrinfo
*ai_next
;
582 ai_next
= ai
->ai_next
;
583 if (ai
->ai_addr
!= NULL
)
585 if (ai
->ai_canonname
)
586 free(ai
->ai_canonname
);
594 get_local(const char *name
, int socktype
, struct addrinfo
**res
) {
596 struct sockaddr_un
*sun
;
599 return (EAI_SOCKTYPE
);
601 ai
= ai_alloc(AF_LOCAL
, sizeof(*sun
));
605 sun
= SUN(ai
->ai_addr
);
606 strncpy(sun
->sun_path
, name
, sizeof(sun
->sun_path
));
608 ai
->ai_socktype
= socktype
;
610 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
611 * and ai->ai_next were initialized to zero.
620 * Allocate an addrinfo structure, and a sockaddr structure
621 * of the specificed length. We initialize:
626 * ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
627 * and everything else is initialized to zero.
629 static struct addrinfo
*
630 ai_alloc(int family
, int addrlen
) {
633 ai
= (struct addrinfo
*)calloc(1, sizeof(*ai
));
637 ai
->ai_addr
= SA(calloc(1, addrlen
));
638 if (ai
->ai_addr
== NULL
) {
642 ai
->ai_addrlen
= addrlen
;
643 ai
->ai_family
= family
;
644 ai
->ai_addr
->sa_family
= family
;
645 #ifdef LWRES_PLATFORM_HAVESALEN
646 ai
->ai_addr
->sa_len
= addrlen
;
651 static struct addrinfo
*
652 ai_clone(struct addrinfo
*oai
, int family
) {
655 ai
= ai_alloc(family
, ((family
== AF_INET6
) ?
656 sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
)));
659 lwres_freeaddrinfo(oai
);
665 ai
->ai_flags
= oai
->ai_flags
;
666 ai
->ai_socktype
= oai
->ai_socktype
;
667 ai
->ai_protocol
= oai
->ai_protocol
;
668 ai
->ai_canonname
= NULL
;
673 static struct addrinfo
*
674 ai_reverse(struct addrinfo
*oai
) {
675 struct addrinfo
*nai
, *tai
;
679 while (oai
!= NULL
) {
681 * Grab one off the old list.
686 * Put it on the front of the new list.