xref: /trueos/lib/libosxsupport/si_getaddrinfo.c (revision a7f9c1ab18631ff83a01ef6877231d2b57c29d00)
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 
59 static int net_config_token = -1;
60 static uint32_t net_v4_count = 0;
61 static uint32_t net_v6_count = 0;	// includes 6to4 addresses
62 static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
63 
64 // Libc SPI
65 int _inet_aton_check(const char *cp, struct in_addr *addr, int strict);
66 
67 typedef 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
si_inet_config(uint32_t * inet4,uint32_t * inet6)75 si_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 
136 void
freeaddrinfo(struct addrinfo * a)137 freeaddrinfo(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 
151 const char *
gai_strerror(int32_t err)152 gai_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  */
186 si_item_t *
si_nameinfo(si_mod_t * si,const struct sockaddr * sa,int flags,const char * interface,uint32_t * err)187 si_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 
383 static int
_gai_numericserv(const char * serv,uint16_t * port)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 
410 int
_gai_serv_to_port(const char * serv,uint32_t proto,uint16_t * port)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 
432 si_item_t *
si_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)433 si_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 
457 si_item_t *
si_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)458 si_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 
483 si_item_t *
si_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)484 si_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 
518 si_list_t *
si_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)519 si_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  */
615 static int
_gai_numerichost(const char * nodename,uint32_t * family,int flags,struct in_addr * a4,struct in6_addr * a6,int * scope)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  */
713 si_list_t *
si_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)714 si_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 
747 int
_gai_addr_sort(const void * a,const void * b)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 
771 static si_list_t *
_gai_sort_list(si_list_t * in,uint32_t flags)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  */
848 si_list_t *
_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)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 
910 si_list_t *
si_srv_byname(si_mod_t * si,const char * qname,const char * interface,uint32_t * err)911 si_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 
919 int
si_wants_addrinfo(si_mod_t * si)920 si_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 
929 static si_list_t *
_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)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 
1010 si_list_t *
si_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)1011 si_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 
1209 static struct addrinfo *
si_item_to_addrinfo(si_item_t * item)1210 si_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 
1250 struct addrinfo *
si_list_to_addrinfo(si_list_t * list)1251 si_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 
1282 static si_item_t *
make_hostent(si_mod_t * si,const char * name,struct in_addr addr)1283 make_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 
1300 static si_item_t *
make_hostent6(si_mod_t * si,const char * name,struct in6_addr addr)1301 make_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 
1318 static char *
lower_case(const char * s)1319 lower_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 
1339 static int
merge_alias(const char * name,build_hostent_t * h)1340 merge_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 
1370 static int
append_addr(const char * addr,uint32_t len,build_hostent_t * h)1371 append_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 
1395 static void
free_build_hostent(build_hostent_t * h)1396 free_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 
1425 si_item_t *
si_ipnode_byname(si_mod_t * si,const char * name,int family,int flags,const char * interface,uint32_t * err)1426 si_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