1/*
2 * Copyright (c) 2008-2011 Apple Inc.  All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <netdb.h>
25#include <sys/types.h>
26#include <ctype.h>
27#include <stdio.h>
28#include <stdint.h>
29#include <sys/socket.h>
30#include <net/if.h>
31#include <netinet/in.h>
32#include <network/sa_compare.h>
33#include <arpa/inet.h>
34#include <ifaddrs.h>
35#include <net/if.h>
36#include <string.h>
37#include <sys/param.h>
38#include <notify.h>
39#include <notify_keys.h>
40#include <pthread.h>
41#include <TargetConditionals.h>
42#include "netdb_async.h"
43#include "si_module.h"
44
45#define SOCK_UNSPEC 0
46#define IPPROTO_UNSPEC 0
47
48#define IPV6_ADDR_LEN 16
49#define IPV4_ADDR_LEN 4
50
51#define WANT_NOTHING 0
52#define WANT_A4_ONLY 1
53#define WANT_A6_ONLY 2
54#define WANT_A6_PLUS_MAPPED_A4 3
55#define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
56
57#define V6TO4_PREFIX_16 0x2002
58
59static int net_config_token = -1;
60static uint32_t net_v4_count = 0;
61static uint32_t net_v6_count = 0;	// includes 6to4 addresses
62static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
63
64// Libc SPI
65int _inet_aton_check(const char *cp, struct in_addr *addr, int strict);
66
67typedef struct {
68	struct hostent host;
69	int alias_count;
70	int addr_count;
71	uint64_t ttl;
72} build_hostent_t;
73
74__private_extern__ int
75si_inet_config(uint32_t *inet4, uint32_t *inet6)
76{
77	int status, checkit;
78	struct ifaddrs *ifa, *ifap;
79
80	pthread_mutex_lock(&net_config_mutex);
81
82	checkit = 1;
83
84	if (net_config_token < 0)
85	{
86		status = notify_register_check(kNotifySCNetworkChange, &net_config_token);
87		if (status != 0) net_config_token = -1;
88	}
89
90	if (net_config_token >= 0)
91	{
92		status = notify_check(net_config_token, &checkit);
93		if (status != 0) checkit = 1;
94	}
95
96	status = 0;
97
98	if (checkit != 0)
99	{
100		if (getifaddrs(&ifa) < 0)
101		{
102			status = -1;
103		}
104		else
105		{
106			net_v4_count = 0;
107			net_v6_count = 0;
108
109			for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
110			{
111				if (ifap->ifa_addr == NULL) continue;
112				if ((ifap->ifa_flags & IFF_UP) == 0) continue;
113
114				if (ifap->ifa_addr->sa_family == AF_INET)
115				{
116					net_v4_count++;
117				}
118				else if (ifap->ifa_addr->sa_family == AF_INET6)
119				{
120					net_v6_count++;
121				}
122			}
123            freeifaddrs(ifa);
124		}
125
126	}
127
128	if (inet4 != NULL) *inet4 = net_v4_count;
129	if (inet6 != NULL) *inet6 = net_v6_count;
130
131	pthread_mutex_unlock(&net_config_mutex);
132
133	return status;
134}
135
136void
137freeaddrinfo(struct addrinfo *a)
138{
139	struct addrinfo *next;
140
141	while (a != NULL)
142	{
143		next = a->ai_next;
144		if (a->ai_addr != NULL) free(a->ai_addr);
145		if (a->ai_canonname != NULL) free(a->ai_canonname);
146		free(a);
147		a = next;
148	}
149}
150
151const char *
152gai_strerror(int32_t err)
153{
154	switch (err)
155	{
156		case EAI_ADDRFAMILY: return "Address family for nodename not supported";
157		case EAI_AGAIN: return "Temporary failure in name resolution";
158		case EAI_BADFLAGS:	return "Invalid value for ai_flags";
159		case EAI_FAIL: return "Non-recoverable failure in name resolution";
160		case EAI_FAMILY: return "ai_family not supported";
161		case EAI_MEMORY: return "Memory allocation failure";
162		case EAI_NODATA: return "No address associated with nodename";
163		case EAI_NONAME: return "nodename nor servname provided, or not known";
164		case EAI_SERVICE: return "servname not supported for ai_socktype";
165		case EAI_SOCKTYPE: return "ai_socktype not supported";
166		case EAI_SYSTEM: return "System error";
167		case EAI_BADHINTS: return "Bad hints";
168		case EAI_PROTOCOL: return "ai_protocol not supported";
169		case EAI_OVERFLOW: return "argument buffer overflow";
170	}
171
172	return "Unknown error";
173}
174
175/*
176 * getnameinfo
177 *
178 * We handle some "trival" cases locally.  If the caller passes
179 * NI_NUMERICHOST (only), then this call turns into a getservbyport
180 * to get the service name + inet_pton() to create a host string.
181 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
182 * number, complete the getnameinfo, and use printf() to create a service
183 * string.  If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
184 * we inet_ntop() and printf() and return the results.
185 */
186si_item_t *
187si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
188{
189	si_item_t *out = NULL;
190	const struct sockaddr *lookup_sa;
191	struct sockaddr_in s4;
192	struct in_addr a4;
193	struct in6_addr a6;
194	const uint64_t unused = 0;
195	void *addr = NULL;
196	char *host = NULL;
197	char *serv = NULL;
198	uint32_t ifnum = 0;
199	uint16_t port = 0;
200
201	int do_host_lookup = ((flags & NI_NUMERICHOST) == 0);
202	int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0);
203
204	/* check input */
205	if ((si == NULL) || (sa == NULL))
206	{
207		if (err != NULL) *err = SI_STATUS_EAI_FAIL;
208		return NULL;
209	}
210
211	if (err != NULL) *err = SI_STATUS_NO_ERROR;
212
213	lookup_sa = sa;
214
215	if (sa->sa_family == AF_INET)
216	{
217		struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
218		memcpy(&a4, &s4->sin_addr, sizeof(a4));
219		port = s4->sin_port;
220		addr = &a4;
221	}
222	else if (sa->sa_family == AF_INET6)
223	{
224		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
225		memcpy(&a6, &s6->sin6_addr, sizeof(a6));
226		port = s6->sin6_port;
227
228		/* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */
229		if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))
230		{
231			ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]);
232			if (ifnum == 0)
233			{
234				ifnum = s6->sin6_scope_id;
235				a6.__u6_addr.__u6_addr16[1] = htons(ifnum);
236			}
237
238			if ((ifnum != s6->sin6_scope_id) && (s6->sin6_scope_id != 0))
239			{
240				if (err != NULL) *err = SI_STATUS_EAI_FAIL;
241				return NULL;
242			}
243		}
244
245		/* v4 mapped and compat addresses are converted to plain v4 */
246		if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr))
247		{
248			memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4));
249			addr = &a4;
250			memset(&s4, 0, sizeof(s4));
251			s4.sin_len = sizeof(s4);
252			s4.sin_family = AF_INET;
253			s4.sin_port = port;
254			memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr));
255			lookup_sa = (const struct sockaddr *)&s4;
256		}
257		else
258		{
259			addr = &a6;
260		}
261	}
262	else
263	{
264		if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
265		return NULL;
266	}
267
268	if (do_host_lookup == 1)
269	{
270		si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL);
271		if (item != NULL)
272		{
273			struct hostent *h;
274			h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
275			host = strdup(h->h_name);
276			si_item_release(item);
277			if (host == NULL)
278			{
279				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
280				return NULL;
281			}
282		}
283	}
284
285	if ((do_serv_lookup == 1) && (port != 0))
286	{
287		si_item_t *item = si_service_byport(si, port, NULL);
288		if (item != NULL)
289		{
290			struct servent *s;
291			s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
292			serv = strdup(s->s_name);
293			si_item_release(item);
294			if (serv == NULL)
295			{
296				free(host);
297				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
298				return NULL;
299			}
300		}
301	}
302
303	/*
304	 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
305	 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
306	 */
307	if ((host == NULL) && ((flags & NI_NAMEREQD) == 0))
308	{
309		char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1];
310		tmp[0] = '\0';
311		if (sa->sa_family == AF_INET)
312		{
313			char buf[INET_ADDRSTRLEN];
314			if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0)
315			{
316				host = strdup(buf);
317			}
318		}
319		else if (sa->sa_family == AF_INET6)
320		{
321			char buf[INET6_ADDRSTRLEN];
322
323			/* zero the embedded scope ID */
324			if (ifnum != 0)
325			{
326				a6.__u6_addr.__u6_addr16[1] = 0;
327			}
328
329			if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0)
330			{
331				if (ifnum != 0)
332				{
333					char ifname[IF_NAMESIZE];
334					if (if_indextoname(ifnum, ifname) != NULL)
335					{
336						asprintf(&host, "%s%%%s", buf, ifname);
337					}
338					else
339					{
340						/* ENXIO */
341						if (err != NULL) *err = SI_STATUS_EAI_FAIL;
342						return NULL;
343					}
344				}
345				else
346				{
347					host = strdup(buf);
348				}
349			}
350		}
351	}
352
353	/* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
354	if (serv == NULL)
355	{
356		asprintf(&serv, "%hu", ntohs(port));
357	}
358
359	if ((host == NULL) || (serv == NULL))
360	{
361		if (err != NULL)
362		{
363			if ((flags & NI_NAMEREQD) != 0)
364			{
365				*err = SI_STATUS_EAI_NONAME;
366			}
367			else
368			{
369				*err = SI_STATUS_EAI_MEMORY;
370			}
371		}
372	}
373	else
374	{
375		out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv);
376	}
377
378	free(host);
379	free(serv);
380	return out;
381}
382
383static int
384_gai_numericserv(const char *serv, uint16_t *port)
385{
386	int numeric;
387	char *endptr;
388	long num;
389
390	numeric = 0;
391
392	if (serv == NULL)
393	{
394		if (port) *port = 0;
395		numeric = 1;
396	}
397	else
398	{
399		num = strtol(serv, &endptr, 10);
400		if ((serv[0] != '\0') && (*endptr == '\0') && (num >= 0) && (num <= UINT16_MAX))
401		{
402			numeric = 1;
403			if (port != NULL) *port = (uint16_t)num;
404		}
405	}
406
407	return numeric;
408}
409
410int
411_gai_serv_to_port(const char *serv, uint32_t proto, uint16_t *port)
412{
413	si_item_t *item;
414	struct servent *s;
415	const char *protoname = NULL;
416
417	if (_gai_numericserv(serv, port)) return 0;
418
419	if (proto == IPPROTO_UDP) protoname = "udp";
420	if (proto == IPPROTO_TCP) protoname = "tcp";
421
422	item = si_service_byname(si_search(), serv, protoname);
423	if (item == NULL) return -1;
424
425	s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
426	if (port) *port = ntohs(s->s_port);
427	si_item_release(item);
428
429	return 0;
430}
431
432si_item_t *
433si_addrinfo_v4(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname)
434{
435	socket_data_t sockdata;
436	struct sockaddr_in *sa;
437	int32_t len, v32;
438	uint64_t unused;
439
440	unused = 0;
441	len = sizeof(struct sockaddr_in);
442	memset(&sockdata, 0, sizeof(socket_data_t));
443	sa = (struct sockaddr_in *)&sockdata;
444
445	sa->sin_len = len;
446	sa->sin_family = AF_INET;
447	sa->sin_port = htons(port);
448	memcpy(&sa->sin_addr, addr, sizeof(sa->sin_addr));
449
450	/* Kludge: Jam the interface number into sin_zero (4 bytes). */
451	v32 = iface;
452	memmove(sa->sin_zero, &v32, sizeof(uint32_t));
453
454	return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET, sock, proto, len, sockdata, cname);
455}
456
457si_item_t *
458si_addrinfo_v4_mapped(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname)
459{
460	socket_data_t sockdata;
461	struct sockaddr_in6 *sa;
462	int32_t len;
463	uint64_t unused;
464
465	unused = 0;
466	len = sizeof(struct sockaddr_in6);
467	memset(&sockdata, 0, sizeof(socket_data_t));
468	sa = (struct sockaddr_in6 *)&sockdata;
469
470	sa->sin6_len = len;
471	sa->sin6_family = AF_INET6;
472	sa->sin6_port = htons(port);
473	memset(&(sa->sin6_addr.__u6_addr.__u6_addr8[10]), 0xff, 2);
474	memcpy(&(sa->sin6_addr.__u6_addr.__u6_addr8[12]), addr, sizeof(struct in_addr));
475
476	/* sin6_scope_id is in host byte order */
477	sa->sin6_scope_id = iface;
478
479	return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname);
480}
481
482
483si_item_t *
484si_addrinfo_v6(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr *addr, uint16_t iface, const char *cname)
485{
486	socket_data_t sockdata;
487	struct sockaddr_in6 *sa;
488	int32_t len;
489	uint64_t unused;
490
491	unused = 0;
492	len = sizeof(struct sockaddr_in6);
493	memset(&sockdata, 0, sizeof(socket_data_t));
494	sa = (struct sockaddr_in6 *)&sockdata;
495
496	sa->sin6_len = len;
497	sa->sin6_family = AF_INET6;
498	sa->sin6_port = htons(port);
499	memcpy(&sa->sin6_addr, addr, sizeof(sa->sin6_addr));
500
501	/* sin6_scope_id is in host byte order */
502	sa->sin6_scope_id = iface;
503
504	if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
505	{
506		/* check for embedded scopeid */
507		uint16_t esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]);
508		if (esid != 0)
509		{
510			sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
511			if (iface == 0) sa->sin6_scope_id = esid;
512		}
513	}
514
515	return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname);
516}
517
518si_list_t *
519si_addrinfo_list(si_mod_t *si, uint32_t flags, int socktype, int proto, struct in_addr *a4, struct in6_addr *a6, int port, int scopeid, const char *cname4, const char *cname6)
520{
521	int do_map = 0;
522	si_item_t *item = NULL;
523	si_list_t *out4 = NULL, *out6 = NULL;
524
525	if ((flags & AI_V4MAPPED) && ((flags & AI_ALL) || (a6 == NULL))) do_map = 1;
526
527	if (a6 != NULL)
528	{
529		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
530		{
531			item = si_addrinfo_v6(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, cname6);
532			out6 = si_list_add(out6, item);
533			si_item_release(item);
534		}
535
536		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
537		{
538			item = si_addrinfo_v6(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, cname6);
539			out6 = si_list_add(out6, item);
540			si_item_release(item);
541		}
542
543		if (proto == IPPROTO_ICMPV6)
544		{
545			item = si_addrinfo_v6(si, 0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, cname6);
546			out6 = si_list_add(out6, item);
547			si_item_release(item);
548		}
549	}
550
551	if (a4 != NULL)
552	{
553		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
554		{
555			if (do_map == 0)
556			{
557				item = si_addrinfo_v4(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
558				out4 = si_list_add(out4, item);
559			}
560			else
561			{
562				item = si_addrinfo_v4_mapped(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
563				out6 = si_list_add(out6, item);
564			}
565
566			si_item_release(item);
567		}
568
569		if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
570		{
571			if (do_map == 0)
572			{
573				item = si_addrinfo_v4(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
574				out4 = si_list_add(out4, item);
575			}
576			else
577			{
578				item = si_addrinfo_v4_mapped(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
579				out6 = si_list_add(out6, item);
580			}
581
582			si_item_release(item);
583		}
584
585		if (proto == IPPROTO_ICMP)
586		{
587			if (do_map == 0)
588			{
589				item = si_addrinfo_v4(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
590				out4 = si_list_add(out4, item);
591			}
592			else
593			{
594				item = si_addrinfo_v4_mapped(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
595				out6 = si_list_add(out6, item);
596			}
597
598			si_item_release(item);
599		}
600	}
601
602	out6 = si_list_concat(out6, out4);
603	si_list_release(out4);
604
605	return out6;
606}
607
608/*
609 * _gai_numerichost
610 * Determines whether the given host name is a numeric IPv4 or IPv6 address,
611 * based on the address family input value.  If the input addres family is
612 * unspecified, a more specific value will be provided on output if possible.
613 * Returns 1 if host name is numeric or 0 if not, or -1 on error.
614 */
615static int
616_gai_numerichost(const char* nodename, uint32_t *family, int flags, struct in_addr *a4, struct in6_addr *a6, int *scope)
617{
618	int numerichost, passive;
619
620	numerichost = 0;
621
622	if (nodename == NULL)
623	{
624		/* return loopback or passive addresses */
625		passive = (flags & AI_PASSIVE);
626
627		if (((*family == AF_UNSPEC) || (*family == AF_INET)) || ((*family == AF_INET6) && (flags & AI_V4MAPPED) && (flags & AI_ALL)))
628		{
629			if (passive) a4->s_addr = 0;
630			else a4->s_addr = htonl(INADDR_LOOPBACK);
631		}
632
633		if ((*family == AF_UNSPEC) || (*family == AF_INET6))
634		{
635			memset(a6, 0, sizeof(*a6));
636			if (!passive) a6->__u6_addr.__u6_addr32[3] = htonl(1);
637		}
638
639		numerichost = 1;
640	}
641	else
642	{
643		/*
644		 * numeric IPv4 host valid for AF_UNSPEC and AF_INET
645		 * also valid for AF_INET6 with AI_V4MAPPED
646		 */
647		numerichost = inet_pton(AF_INET, nodename, a4);
648		if (numerichost == 0)
649		{
650			/* inet_pton doesn't allow "a", "a.b", or "a.b.c" forms, so we re-check */
651			numerichost = _inet_aton_check(nodename, a4, 1);
652		}
653
654		if (numerichost == 1)
655		{
656			if (*family == AF_UNSPEC)
657			{
658				*family = AF_INET;
659			}
660			else if (*family == AF_INET6)
661			{
662				if (flags & AI_V4MAPPED)
663				{
664					memset(a6, 0, sizeof(struct in6_addr));
665					memset(&(a6->__u6_addr.__u6_addr8[10]), 0xff, 2);
666					memcpy(&(a6->__u6_addr.__u6_addr8[12]), a4, sizeof(struct in_addr));
667				}
668				else
669				{
670					numerichost = -1;
671				}
672			}
673
674			return numerichost;
675		}
676
677		/* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
678		numerichost = inet_pton(AF_INET6, nodename, a6);
679		if (numerichost == 1)
680		{
681			/* check for scope/zone id */
682			char *p = strrchr(nodename, SCOPE_DELIMITER);
683			if (p != NULL)
684			{
685				int i, d;
686				char *x;
687
688				p++;
689				d = 1;
690				for (x = p; (*x != '\0') && (d == 1); x++)
691				{
692					i = *x;
693					d = isdigit(i);
694				}
695
696				if (d == 1) *scope = atoi(p);
697				else *scope = if_nametoindex(p);
698			}
699
700			if (*family == AF_UNSPEC) *family = AF_INET6;
701			else if (*family == AF_INET) numerichost = -1;
702
703			return numerichost;
704		}
705	}
706
707	return numerichost;
708}
709
710/* si_addrinfo_list_from_hostent
711 * Returns an addrinfo list from IPv4 and IPv6 hostent entries
712 */
713si_list_t *
714si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t flags, uint32_t socktype, uint32_t proto, uint16_t port, uint16_t scope, const struct hostent *h4, const struct hostent *h6)
715{
716	int i;
717	si_list_t *out = NULL;
718	si_list_t *list;
719
720	if ((h6 != NULL) && (h6->h_addr_list != NULL))
721	{
722		for (i = 0; h6->h_addr_list[i] != NULL; i++)
723		{
724			struct in6_addr a6;
725			memcpy(&a6, h6->h_addr_list[i], h6->h_length);
726			list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6, port, scope, NULL, h6->h_name);
727			out = si_list_concat(out, list);
728			si_list_release(list);
729		}
730	}
731
732	if ((h4 != NULL) && (h4->h_addr_list != NULL))
733	{
734		for (i = 0; h4->h_addr_list[i] != NULL; i++)
735		{
736			struct in_addr a4;
737			memcpy(&a4, h4->h_addr_list[i], h4->h_length);
738			list = si_addrinfo_list(si, flags, socktype, proto, &a4, NULL, port, 0, h4->h_name, NULL);
739			out = si_list_concat(out, list);
740			si_list_release(list);
741		}
742	}
743
744	return out;
745}
746
747int
748_gai_addr_sort(const void *a, const void *b)
749{
750	si_item_t **item_a, **item_b;
751	si_addrinfo_t *p, *q;
752	struct sockaddr *sp, *sq;
753
754	item_a = (si_item_t **)a;
755	item_b = (si_item_t **)b;
756
757	p = (si_addrinfo_t *)((uintptr_t)*item_a + sizeof(si_item_t));
758	q = (si_addrinfo_t *)((uintptr_t)*item_b + sizeof(si_item_t));
759
760	sp = (struct sockaddr *)p->ai_addr.x;
761	sq = (struct sockaddr *)q->ai_addr.x;
762
763	/*
764	 * sa_dst_compare(A,B) returns -1 if A is less desirable than B,
765	 * 0 if they are equally desirable, and 1 if A is more desirable.
766	 * qsort() expects the inverse, so we swap sp and sq.
767	 */
768	return sa_dst_compare(sq, sp, 0);
769}
770
771static si_list_t *
772_gai_sort_list(si_list_t *in, uint32_t flags)
773{
774	si_list_t *out;
775	int filter_mapped;
776	uint32_t i;
777	uint32_t v4mapped_count = 0;
778	uint32_t v6_count = 0;
779	si_addrinfo_t *a;
780
781	if (in == NULL) return NULL;
782
783	for (i = 0; i < in->count; i++)
784	{
785		a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
786		if (a->ai_family == AF_INET6)
787		{
788			struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x;
789			if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr))) v4mapped_count++;
790			else v6_count++;
791		}
792	}
793
794	filter_mapped = 1;
795	if ((flags & AI_V4MAPPED) && ((v6_count == 0) || (flags & AI_ALL))) filter_mapped = 0;
796
797	out = in;
798
799	if ((filter_mapped == 1) && (v4mapped_count > 0))
800	{
801		i = in->count - v4mapped_count;
802		if (i == 0) return NULL;
803
804		out = (si_list_t *)calloc(1, sizeof(si_list_t));
805		if (out == NULL) return in;
806
807		out->count = i;
808		out->refcount = in->refcount;
809
810		out->entry = (si_item_t **)calloc(out->count, sizeof(si_item_t *));
811		if (out->entry == NULL)
812		{
813			free(out);
814			return in;
815		}
816
817		out->curr = 0;
818
819		for (i = 0; i < in->count; i++)
820		{
821			a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
822			if (a->ai_family == AF_INET6)
823			{
824				struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x;
825				if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr)))
826				{
827					si_item_release(in->entry[i]);
828					continue;
829				}
830			}
831
832			out->entry[out->curr++] = in->entry[i];
833		}
834
835		out->curr = 0;
836
837		free(in->entry);
838		free(in);
839	}
840
841	qsort(&out->entry[0], out->count, sizeof(si_item_t *), _gai_addr_sort);
842	return out;
843}
844
845/* _gai_simple
846 * Simple lookup via gethostbyname2(3) mechanism.
847 */
848si_list_t *
849_gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
850{
851	si_item_t *h4_item = NULL, *h6_item = NULL;
852	struct hostent *h4 = NULL, *h6 = NULL;
853	si_list_t *out = NULL;
854	uint16_t port;
855
856	if ((flags & AI_NUMERICSERV) != 0)
857	{
858		port = *(uint16_t*)servptr;
859	}
860	else
861	{
862		if (_gai_serv_to_port(servptr, proto, &port) != 0)
863		{
864			if (err) *err = SI_STATUS_EAI_NONAME;
865			return NULL;
866		}
867	}
868
869	if ((flags & AI_NUMERICHOST) != 0)
870	{
871		if (family == AF_INET)
872		{
873			h4_item = si_host_byaddr(si, nodeptr, AF_INET, interface, NULL);
874		}
875		else if (family == AF_INET6)
876		{
877			h6_item = si_host_byaddr(si, nodeptr, AF_INET6, interface, NULL);
878		}
879	}
880	else
881	{
882		if ((family == AF_INET) || (family == AF_UNSPEC))
883		{
884			h4_item = si_host_byname(si, nodeptr, AF_INET, interface, NULL);
885		}
886
887		if ((family == AF_INET6) || (family == AF_UNSPEC))
888		{
889			h6_item = si_host_byname(si, nodeptr, AF_INET6, interface, NULL);
890		}
891	}
892
893	if (h4_item != NULL)
894	{
895		h4 = (struct hostent *)((uintptr_t)h4_item + sizeof(si_item_t));
896	}
897
898	if (h6_item != NULL)
899	{
900		h6 = (struct hostent *)((uintptr_t)h6_item + sizeof(si_item_t));
901	}
902
903	out = si_addrinfo_list_from_hostent(si, flags, socktype, proto, port, 0, h4, h6);
904	si_item_release(h4_item);
905	si_item_release(h6_item);
906
907	return _gai_sort_list(out, flags);
908}
909
910si_list_t *
911si_srv_byname(si_mod_t *si, const char *qname, const char *interface, uint32_t *err)
912{
913	if (si == NULL) return 0;
914	if (si->vtable->sim_srv_byname == NULL) return 0;
915
916	return si->vtable->sim_srv_byname(si, qname, interface, err);
917}
918
919int
920si_wants_addrinfo(si_mod_t *si)
921{
922	if (si == NULL) return 0;
923	if (si->vtable->sim_addrinfo == NULL) return 0;
924	if (si->vtable->sim_wants_addrinfo == NULL) return 0;
925
926	return si->vtable->sim_wants_addrinfo(si);
927}
928
929static si_list_t *
930_gai_srv(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
931{
932	int i;
933	char *qname;
934	si_srv_t *srv;
935	si_item_t *item;
936
937	si_list_t *list = NULL;
938	si_list_t *result = NULL;
939
940	/* Minimum SRV priority is zero. Start below that. */
941	int lastprio = -1;
942	int currprio;
943
944	if (node == NULL || serv == NULL) return NULL;
945
946	asprintf(&qname, "%s.%s", serv, node);
947	list = si_srv_byname(si, qname, interface, err);
948	free(qname);
949
950	/* Iterate the SRV records starting at lowest priority and attempt to
951	 * lookup the target host name. Returns the first successful lookup.
952	 * It's an O(n^2) algorithm but data sets are small (less than 100) and
953	 * sorting overhead is dwarfed by network I/O for each element.
954	 */
955	while (list != NULL && result == NULL)
956	{
957		/* Find the next lowest priority level. */
958		/* Maximum SRV priority is UINT16_MAX. Start above that. */
959		currprio = INT_MAX;
960
961		for (i = 0; i < list->count; ++i)
962		{
963			item = list->entry[i];
964			srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
965
966			if (srv->priority > lastprio && srv->priority < currprio)
967			{
968				currprio = srv->priority;
969			}
970		}
971
972		if (currprio == INT_MAX)
973		{
974			/* All priorities have been evaluated. Done. */
975			break;
976		}
977		else
978		{
979			lastprio = currprio;
980		}
981
982		/* Lookup hosts at the current priority level. Return first match. */
983		for (i = 0; i < list->count; ++i)
984		{
985			item = list->entry[i];
986			srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
987
988			if (srv->priority == currprio)
989			{
990				/* So that _gai_simple expects an integer service. */
991				flags |= AI_NUMERICSERV;
992
993				result = _gai_simple(si, srv->target, &srv->port, family, socktype, proto, flags, interface, err);
994				if (result)
995				{
996					break;
997				}
998			}
999		}
1000	}
1001
1002	if (list != NULL)
1003	{
1004		si_list_release(list);
1005	}
1006
1007	return result;
1008}
1009
1010si_list_t *
1011si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
1012{
1013	int numerichost, numericserv = 0;
1014	int scope = 0;
1015	const void *nodeptr = NULL, *servptr = NULL;
1016	uint16_t port;
1017	struct in_addr a4, *p4;
1018	struct in6_addr a6, *p6;
1019	const char *cname;
1020	si_list_t *out;
1021
1022	if (err != NULL) *err = SI_STATUS_NO_ERROR;
1023
1024	if (si == NULL)
1025	{
1026		if (err != NULL) *err = SI_STATUS_EAI_FAIL;
1027		return NULL;
1028	}
1029
1030	/* treat empty strings as NULL */
1031	if ((node != NULL) && (node[0] == '\0')) node = NULL;
1032	if ((serv != NULL) && (serv[0] == '\0')) serv = NULL;
1033
1034	/* make sure we have a query */
1035	if ((node == NULL) && (serv == NULL))
1036	{
1037		if (err != NULL) *err = SI_STATUS_EAI_NONAME;
1038		return NULL;
1039	}
1040
1041	/* verify family is supported */
1042	switch (family)
1043	{
1044		case AF_UNSPEC:
1045		case AF_INET:
1046		case AF_INET6:
1047			break;
1048		default:
1049			if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
1050			return NULL;
1051	}
1052
1053	/* verify socket type is supported */
1054	switch (socktype)
1055	{
1056		case SOCK_UNSPEC:
1057		case SOCK_RAW:
1058		case SOCK_DGRAM:
1059		case SOCK_STREAM:
1060			break;
1061		default:
1062			if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
1063			return NULL;
1064	}
1065
1066	/* verify protocol is supported */
1067	switch (proto)
1068	{
1069		case IPPROTO_UNSPEC:
1070		case IPPROTO_UDP:
1071		case IPPROTO_TCP:
1072		case IPPROTO_ICMP:
1073		case IPPROTO_ICMPV6:
1074			break;
1075		default:
1076			if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
1077			return NULL;
1078	}
1079
1080	/* verify socket type compatible with protocol */
1081	if (((socktype == SOCK_DGRAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_UDP)) || ((socktype == SOCK_STREAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_TCP)))
1082	{
1083		if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
1084		return NULL;
1085	}
1086
1087	/* check AI_V4MAPPED and AI_ALL */
1088	if (family != AF_INET6)
1089	{
1090		/* unset AI_V4MAPPED and AI_ALL unless family is AF_INET6 */
1091		flags &= ~(AI_V4MAPPED | AI_ALL);
1092	}
1093	else if ((flags & AI_V4MAPPED) == 0)
1094	{
1095		/* unset AI_ALL unless family is AF_INET6 and AI_V4MAPPED is set */
1096		flags &= ~AI_ALL;
1097	}
1098
1099	memset(&a4, 0, sizeof(struct in_addr));
1100	memset(&a6, 0, sizeof(struct in6_addr));
1101
1102	/* determine the protocol if possible */
1103	if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_DGRAM)) proto = IPPROTO_UDP;
1104	if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_STREAM)) proto = IPPROTO_TCP;
1105
1106	port = 0;
1107
1108	if ((flags & AI_SRV) != 0)
1109	{
1110		/* AI_SRV SPI */
1111		out = _gai_srv(si, node, serv, family, socktype, proto, flags, interface, err);
1112		return _gai_sort_list(out, flags);
1113	}
1114	else
1115	{
1116		/* Usual service lookup */
1117		numericserv = _gai_numericserv(serv, &port);
1118	}
1119
1120	if ((flags & AI_NUMERICSERV) && (numericserv == 0))
1121	{
1122		/* FreeBSD returns SI_STATUS_EAI_SERVICE */
1123		if (err != NULL) *err = SI_STATUS_EAI_NONAME;
1124		return NULL;
1125	}
1126
1127	if ((serv != NULL) && (strcmp(serv, "0") != 0))
1128	{
1129		if (numericserv == 1)
1130		{
1131			flags |= AI_NUMERICSERV;
1132			servptr = &port;
1133		}
1134		else
1135		{
1136			servptr = serv;
1137		}
1138	}
1139
1140	numerichost = _gai_numerichost(node, &family, flags, &a4, &a6, &scope);
1141	if ((numerichost == -1) || ((flags & AI_NUMERICHOST) && (numerichost == 0)))
1142	{
1143		if (err != NULL) *err = SI_STATUS_EAI_NONAME;
1144		return NULL;
1145	}
1146
1147	if (numerichost == 1)
1148	{
1149		flags |= AI_NUMERICHOST;
1150		if (family == AF_INET)
1151		{
1152			nodeptr = &a4;
1153		}
1154		else if (family == AF_INET6)
1155		{
1156			nodeptr = &a6;
1157		}
1158	}
1159	else
1160	{
1161		nodeptr = node;
1162	}
1163
1164	if ((numerichost == 1) && (numericserv == 0))
1165	{
1166		/* only service lookup needed.  convert to port and perform a trivial getaddrinfo */
1167		if (_gai_serv_to_port(serv, proto, &port) != 0)
1168		{
1169			if (err != NULL) *err = SI_STATUS_EAI_NONAME;
1170			return NULL;
1171		}
1172		else
1173		{
1174			flags |= AI_NUMERICSERV;
1175			servptr = &port;
1176			numericserv = 1;
1177		}
1178	}
1179
1180	if ((numerichost == 1) && (numericserv == 1))
1181	{
1182		p4 = &a4;
1183		p6 = &a6;
1184		cname = NULL;
1185
1186		if (family == AF_INET) p6 = NULL;
1187		if (family == AF_INET6) p4 = NULL;
1188		if (node == NULL) cname = "localhost";
1189
1190		/* allow nodename to be a mapped IPv4 address, e.g. "::ffff:10.0.0.1" */
1191		if (p6 != NULL) flags |= AI_V4MAPPED;
1192
1193		/* handle trivial questions */
1194		out = si_addrinfo_list(si, flags, socktype, proto, p4, p6, port, scope, cname, cname);
1195		return _gai_sort_list(out, flags);
1196	}
1197	else if (si_wants_addrinfo(si))
1198	{
1199		/* or let the current module handle the host lookups intelligently */
1200		out = si->vtable->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, interface, err);
1201		return _gai_sort_list(out, flags);
1202	}
1203
1204	/* fall back to a default path */
1205	out = _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, interface, err);
1206	return _gai_sort_list(out, flags);
1207}
1208
1209static struct addrinfo *
1210si_item_to_addrinfo(si_item_t *item)
1211{
1212	si_addrinfo_t *a;
1213	struct addrinfo *out;
1214
1215	if (item == NULL) return NULL;
1216
1217	a = (si_addrinfo_t *)((uintptr_t)item + sizeof(si_item_t));
1218
1219	out = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
1220	if (out == NULL) return NULL;
1221
1222	out->ai_flags = a->ai_flags;
1223	out->ai_family = a->ai_family;
1224	out->ai_socktype = a->ai_socktype;
1225	out->ai_protocol = a->ai_protocol;
1226	out->ai_addrlen = a->ai_addrlen;
1227
1228	out->ai_addr = (struct sockaddr *)calloc(1, out->ai_addrlen);
1229	if (out->ai_addr == NULL)
1230	{
1231		free(out);
1232		return NULL;
1233	}
1234
1235	memcpy(out->ai_addr, a->ai_addr.x, out->ai_addrlen);
1236
1237	if (a->ai_canonname != NULL)
1238	{
1239		out->ai_canonname = strdup(a->ai_canonname);
1240		if (out->ai_canonname == NULL)
1241		{
1242			free(out);
1243			return NULL;
1244		}
1245	}
1246
1247	return out;
1248}
1249
1250struct addrinfo *
1251si_list_to_addrinfo(si_list_t *list)
1252{
1253	struct addrinfo *tail, *out;
1254	int i;
1255
1256	if (list == NULL) return NULL;
1257	if (list->count == 0) return NULL;
1258
1259	i = list->count - 1;
1260
1261	out = si_item_to_addrinfo(list->entry[i]);
1262	tail = out;
1263
1264	for (i--; i >= 0; i--)
1265	{
1266		out = si_item_to_addrinfo(list->entry[i]);
1267		if (out == NULL)
1268		{
1269			freeaddrinfo(tail);
1270			return NULL;
1271		}
1272
1273		out->ai_next = tail;
1274		tail = out;
1275	}
1276
1277	return out;
1278}
1279
1280/* getipnodebyname */
1281
1282static si_item_t *
1283make_hostent(si_mod_t *si, const char *name, struct in_addr addr)
1284{
1285	char *addrs[2];
1286	char *aliases[1];
1287	uint64_t unused;
1288
1289	if (name == NULL) return NULL;
1290
1291	unused = 0;
1292
1293	addrs[0] = (char *)&(addr.s_addr);
1294	addrs[1] = NULL;
1295	aliases[0] = NULL;
1296
1297	return (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, unused, unused, name, aliases, AF_INET, IPV4_ADDR_LEN, addrs);
1298}
1299
1300static si_item_t *
1301make_hostent6(si_mod_t *si, const char *name, struct in6_addr addr)
1302{
1303	char *addrs[2];
1304	char *aliases[1];
1305	uint64_t unused;
1306
1307	if (name == NULL) return NULL;
1308
1309	unused = 0;
1310
1311	addrs[0] = (char *)&(addr.__u6_addr.__u6_addr32[0]);
1312	addrs[1] = NULL;
1313	aliases[0] = NULL;
1314
1315	return (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, name, aliases, AF_INET6, IPV6_ADDR_LEN, addrs);
1316}
1317
1318static char *
1319lower_case(const char *s)
1320{
1321	int i;
1322	char *t;
1323
1324	if (s == NULL) return NULL;
1325
1326	t = malloc(strlen(s) + 1);
1327
1328	for (i = 0; s[i] != '\0'; i++)
1329	{
1330		if ((s[i] >= 'A') && (s[i] <= 'Z')) t[i] = s[i] + 32;
1331		else t[i] = s[i];
1332	}
1333
1334	t[i] = '\0';
1335
1336	return t;
1337}
1338
1339static int
1340merge_alias(const char *name, build_hostent_t *h)
1341{
1342	int i;
1343
1344	if (name == NULL) return 0;
1345	if (h == NULL) return 0;
1346
1347	if ((h->host.h_name != NULL) && (string_equal(name, h->host.h_name))) return 0;
1348
1349	for (i = 0; i < h->alias_count; i++)
1350	{
1351		if (string_equal(name, h->host.h_aliases[i])) return 0;
1352	}
1353
1354	if (h->alias_count == 0) h->host.h_aliases = (char **)calloc(2, sizeof(char *));
1355	else h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count + 2) * sizeof(char *));
1356
1357	if (h->host.h_aliases == NULL)
1358	{
1359		h->alias_count = 0;
1360		return -1;
1361	}
1362
1363	h->host.h_aliases[h->alias_count] = lower_case(name);
1364	h->alias_count++;
1365	h->host.h_aliases[h->alias_count] = NULL;
1366
1367	return 0;
1368}
1369
1370static int
1371append_addr(const char *addr, uint32_t len, build_hostent_t *h)
1372{
1373	if (addr == NULL) return 0;
1374	if (h == NULL) return 0;
1375
1376	if (h->addr_count == 0) h->host.h_addr_list = (char **)calloc(2, sizeof(char *));
1377	else h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count + 2) * sizeof(char *));
1378
1379	if (h->host.h_addr_list == NULL)
1380	{
1381		h->addr_count = 0;
1382		return -1;
1383	}
1384
1385	h->host.h_addr_list[h->addr_count] = malloc(len);
1386	if (h->host.h_addr_list[h->addr_count] == NULL) return -1;
1387
1388	memcpy(h->host.h_addr_list[h->addr_count], addr, len);
1389	h->addr_count++;
1390	h->host.h_addr_list[h->addr_count] = NULL;
1391
1392	return 0;
1393}
1394
1395static void
1396free_build_hostent(build_hostent_t *h)
1397{
1398	uint32_t i;
1399	char **aliases;
1400
1401	if (h == NULL) return;
1402
1403	if (h->host.h_name != NULL) free(h->host.h_name);
1404	h->host.h_name = NULL;
1405
1406	aliases = h->host.h_aliases;
1407	if (aliases != NULL)
1408	{
1409		while (*aliases != NULL) free(*aliases++);
1410		free(h->host.h_aliases);
1411	}
1412
1413	h->host.h_aliases = NULL;
1414
1415	if (h->host.h_addr_list != NULL)
1416	{
1417		for (i = 0; h->host.h_addr_list[i] != NULL; i++) free(h->host.h_addr_list[i]);
1418		free(h->host.h_addr_list);
1419	}
1420
1421	h->host.h_addr_list = NULL;
1422	free(h);
1423}
1424
1425si_item_t *
1426si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err)
1427{
1428	int i, status, want;
1429	uint32_t if4, if6;
1430	struct in_addr addr4;
1431	struct in6_addr addr6;
1432	si_item_t *item4, *item6;
1433	build_hostent_t *out;
1434	struct hostent *h;
1435	uint64_t unused;
1436
1437	memset(&addr4, 0, sizeof(struct in_addr));
1438	memset(&addr6, 0, sizeof(struct in6_addr));
1439
1440	if (err != NULL) *err = 0;
1441
1442	if (family == AF_INET)
1443	{
1444		status = inet_aton(name, &addr4);
1445		if (status == 1)
1446		{
1447			/* create a host entry */
1448			item4 = make_hostent(si, name, addr4);
1449			if (item4 == NULL)
1450			{
1451				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1452				return NULL;
1453			}
1454
1455			return item4;
1456		}
1457	}
1458	else if (family == AF_INET6)
1459	{
1460		status = inet_pton(family, name, &addr6);
1461		if (status == 1)
1462		{
1463			/* create a host entry */
1464			item6 = make_hostent6(si, name, addr6);
1465			if (item6 == NULL)
1466			{
1467				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1468				return NULL;
1469			}
1470
1471			return item6;
1472		}
1473
1474		status = inet_aton(name, &addr4);
1475		if (status == 1)
1476		{
1477			if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)))
1478			{
1479				if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1480				return NULL;
1481			}
1482
1483			addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1484			addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1485			addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1486			memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);
1487
1488			/* create a host entry */
1489			item6 = make_hostent6(si, name, addr6);
1490			if (item6 == NULL)
1491			{
1492				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1493				return NULL;
1494			}
1495
1496			return item6;
1497		}
1498	}
1499	else
1500	{
1501		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1502		return NULL;
1503	}
1504
1505	/*
1506	 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1507	 */
1508
1509	if4 = 0;
1510	if6 = 0;
1511
1512	if (flags & AI_ADDRCONFIG)
1513	{
1514		if (si_inet_config(&if4, &if6) < 0)
1515		{
1516			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1517			return NULL;
1518		}
1519
1520		/* Bail out if there are no interfaces */
1521		if ((if4 == 0) && (if6 == 0))
1522		{
1523			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1524			return NULL;
1525		}
1526	}
1527
1528	/*
1529	 * Figure out what we want.
1530	 * If user asked for AF_INET, we only want V4 addresses.
1531	 */
1532	want = WANT_A4_ONLY;
1533
1534	if (family == AF_INET)
1535	{
1536		if ((flags & AI_ADDRCONFIG) && (if4 == 0))
1537		{
1538			if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1539			return NULL;
1540		}
1541	}
1542	else if (family == AF_INET6)
1543	{
1544		/* family == AF_INET6 */
1545		want = WANT_A6_ONLY;
1546
1547		if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))
1548		{
1549			if (flags & AI_ALL)
1550			{
1551				want = WANT_A6_PLUS_MAPPED_A4;
1552			}
1553			else
1554			{
1555				want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
1556			}
1557		}
1558		else
1559		{
1560			if ((flags & AI_ADDRCONFIG) && (if6 == 0))
1561			{
1562				if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1563				return NULL;
1564			}
1565		}
1566	}
1567	else
1568	{
1569		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1570		return NULL;
1571	}
1572
1573	item6 = NULL;
1574	item4 = NULL;
1575
1576	/* fetch IPv6 data if required */
1577	if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4))
1578	{
1579		item6 = si_host_byname(si, name, AF_INET6, interface, (uint32_t *)err);
1580	}
1581
1582	/* fetch IPv4 data if required */
1583	if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL)))
1584	{
1585		item4 = si_host_byname(si, name, AF_INET, interface, (uint32_t *)err);
1586	}
1587
1588	if (want == WANT_A4_ONLY)
1589	{
1590		si_item_release(item6);
1591		if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1592		return item4;
1593	}
1594
1595	if (want == WANT_A6_ONLY)
1596	{
1597		si_item_release(item4);
1598		if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1599		return item6;
1600	}
1601
1602	if ((item6 == NULL) && (item4 == NULL))
1603	{
1604		if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1605		return NULL;
1606	}
1607
1608	/* output item will have IPv6 + mapped IPv4 addresses */
1609
1610	out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t));
1611	if (out == NULL)
1612	{
1613		si_item_release(item4);
1614		si_item_release(item6);
1615		if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1616		return NULL;
1617	}
1618
1619	if (item4 != NULL)
1620	{
1621		h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t));
1622
1623		out->host.h_name = lower_case(h->h_name);
1624
1625		if (h->h_aliases != NULL)
1626		{
1627			for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
1628		}
1629
1630		for (i = 0; h->h_addr_list[i] != 0; i++)
1631		{
1632			addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1633			addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1634			addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1635			memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN);
1636			append_addr((const char *)&addr6, IPV6_ADDR_LEN, out);
1637		}
1638	}
1639
1640	if (item6 != NULL)
1641	{
1642		h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t));
1643
1644		if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name);
1645
1646		if (h->h_aliases != NULL)
1647		{
1648			for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
1649		}
1650
1651		for (i = 0; h->h_addr_list[i] != 0; i++) append_addr(h->h_addr_list[i], IPV6_ADDR_LEN, out);
1652	}
1653
1654	si_item_release(item4);
1655	si_item_release(item6);
1656
1657	unused = 0;
1658
1659	item6 = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, out->host.h_name, out->host.h_aliases, AF_INET6, IPV6_ADDR_LEN, out->host.h_addr_list);
1660
1661	free_build_hostent(out);
1662
1663	return item6;
1664}
1665