1/*++
2/* NAME
3/*	myaddrinfo 3
4/* SUMMARY
5/*	addrinfo encapsulation and emulation
6/* SYNOPSIS
7/*	#include <myaddrinfo.h>
8/*
9/*	#define MAI_V4ADDR_BITS ...
10/*	#define MAI_V6ADDR_BITS ...
11/*	#define MAI_V4ADDR_BYTES ...
12/*	#define MAI_V6ADDR_BYTES ...
13/*
14/*	typedef struct { char buf[....]; } MAI_HOSTNAME_STR;
15/*	typedef struct { char buf[....]; } MAI_HOSTADDR_STR;
16/*	typedef struct { char buf[....]; } MAI_SERVNAME_STR;
17/*	typedef struct { char buf[....]; } MAI_SERVPORT_STR;
18/*
19/*	int	hostname_to_sockaddr(hostname, service, socktype, result)
20/*	const char *hostname;
21/*	const char *service;
22/*	int	socktype;
23/*	struct addrinfo **result;
24/*
25/*	int	hostname_to_sockaddr_pf(hostname, pf, service, socktype, result)
26/*	const char *hostname;
27/*	int	pf;
28/*	const char *service;
29/*	int	socktype;
30/*	struct addrinfo **result;
31/*
32/*	int	hostaddr_to_sockaddr(hostaddr, service, socktype, result)
33/*	const char *hostaddr;
34/*	const char *service;
35/*	int	socktype;
36/*	struct addrinfo **result;
37/*
38/*	int	sockaddr_to_hostaddr(sa, salen, hostaddr, portnum, socktype)
39/*	const struct sockaddr *sa;
40/*	SOCKADDR_SIZE salen;
41/*	MAI_HOSTADDR_STR *hostaddr;
42/*	MAI_SERVPORT_STR *portnum;
43/*	int	socktype;
44/*
45/*	int	sockaddr_to_hostname(sa, salen, hostname, service, socktype)
46/*	const struct sockaddr *sa;
47/*	SOCKADDR_SIZE salen;
48/*	MAI_HOSTNAME_STR *hostname;
49/*	MAI_SERVNAME_STR *service;
50/*	int	socktype;
51/*
52/*	const char *MAI_STRERROR(error)
53/*	int	error;
54/* DESCRIPTION
55/*	This module provides a simplified user interface to the
56/*	getaddrinfo(3) and getnameinfo(3) routines (which provide
57/*	a unified interface to manipulate IPv4 and IPv6 socket
58/*	address structures).
59/*
60/*	On systems without getaddrinfo(3) and getnameinfo(3) support,
61/*	emulation for IPv4 only can be enabled by defining
62/*	EMULATE_IPV4_ADDRINFO.
63/*
64/*	hostname_to_sockaddr() looks up the binary addresses for
65/*	the specified symbolic hostname or numeric address.  The
66/*	result should be destroyed with freeaddrinfo(). A null host
67/*	pointer converts to the null host address.
68/*
69/*	hostname_to_sockaddr_pf() is an extended interface that
70/*	provides a protocol family override.
71/*
72/*	hostaddr_to_sockaddr() converts a printable network address
73/*	into the corresponding binary form.  The result should be
74/*	destroyed with freeaddrinfo(). A null host pointer converts
75/*	to the null host address.
76/*
77/*	sockaddr_to_hostaddr() converts a binary network address
78/*	into printable form. The result buffers should be large
79/*	enough to hold the printable address or port including the
80/*	null terminator.
81/*	This function strips off the IPv6 datalink suffix.
82/*
83/*	sockaddr_to_hostname() converts a binary network address
84/*	into a hostname or service.  The result buffer should be
85/*	large enough to hold the hostname or service including the
86/*	null terminator. This routine rejects malformed hostnames
87/*	or numeric hostnames and pretends that the lookup failed.
88/*
89/*	MAI_STRERROR() is an unsafe macro (it evaluates the argument
90/*	multiple times) that invokes strerror() or gai_strerror()
91/*	as appropriate.
92/*
93/*	This module exports the following constants that should be
94/*	user for storage allocation of name or address information:
95/* .IP MAI_V4ADDR_BITS
96/* .IP MAI_V6ADDR_BITS
97/* .IP MAI_V4ADDR_BYTES
98/* .IP MAI_V6ADDR_BYTES
99/*	The number of bits or bytes needed to store a binary
100/*	IPv4 or IPv6 network address.
101/* .PP
102/*	The types MAI_HOST{NAME,ADDR}_STR and MAI_SERV{NAME,PORT}_STR
103/*	implement buffers for the storage of the string representations
104/*	of symbolic or numerical hosts or services. Do not use
105/*	buffer types other than the ones that are expected here,
106/*	or things will blow up with buffer overflow problems.
107/*
108/*	Arguments:
109/* .IP hostname
110/*	On input to hostname_to_sockaddr(), a numeric or symbolic
111/*	hostname, or a null pointer (meaning the wild-card listen
112/*	address).  On output from sockaddr_to_hostname(), storage
113/*	for the result hostname, or a null pointer.
114/* .IP pf
115/*	Protocol type: PF_UNSPEC (meaning: use any protocol that is
116/*	available), PF_INET, or PF_INET6.  This argument is ignored
117/*	in EMULATE_IPV4_ADDRINFO mode.
118/* .IP hostaddr
119/*	On input to hostaddr_to_sockaddr(), a numeric hostname,
120/*	or a null pointer (meaning the wild-card listen address).
121/*	On output from sockaddr_to_hostaddr(), storage for the
122/*	result hostaddress, or a null pointer.
123/* .IP service
124/*	On input to hostname/addr_to_sockaddr(), a numeric or
125/*	symbolic service name, or a null pointer in which case the
126/*	socktype argument is ignored.  On output from
127/*	sockaddr_to_hostname/addr(), storage for the result service
128/*	name, or a null pointer.
129/* .IP portnum
130/*	Storage for the result service port number, or a null pointer.
131/* .IP socktype
132/*	Socket type: SOCK_STREAM, SOCK_DGRAM, etc. This argument is
133/*	ignored when no service or port are specified.
134/* .IP sa
135/*	Protocol-independent socket address structure.
136/* .IP salen
137/*	Protocol-dependent socket address structure size in bytes.
138/* SEE ALSO
139/*	getaddrinfo(3), getnameinfo(3), freeaddrinfo(3), gai_strerror(3)
140/* DIAGNOSTICS
141/*	All routines either return 0 upon success, or an error code
142/*	that is compatible with gai_strerror().
143/*
144/*	On systems where addrinfo support is emulated by Postfix,
145/*	some out-of-memory errors are not reported to the caller,
146/*	but are handled by mymalloc().
147/* BUGS
148/*	The IPv4-only emulation code does not support requests that
149/*	specify a service but no socket type. It returns an error
150/*	indication, instead of enumerating all the possible answers.
151/*
152/*	The hostname/addr_to_sockaddr() routines should accept a
153/*	list of address families that the caller is interested in,
154/*	and they should return only information of those types.
155/*
156/*	Unfortunately, it is not possible to remove unwanted address
157/*	family results from hostname_to_sockaddr(), because we
158/*	don't know how the system library routine getaddrinfo()
159/*	allocates memory.  For example, getaddrinfo() could save
160/*	space by referencing the same string object from multiple
161/*	addrinfo structures; or it could allocate a string object
162/*	and the addrinfo structure as one memory block.
163/*
164/*	We could get around this by copying getaddrinfo() results
165/*	to our own private data structures, but that would only
166/*	make an already expensive API even more expensive.
167/*
168/*	A better workaround is to return a vector of addrinfo
169/*	pointers to the elements that contain only the elements
170/*	that the caller is interested in. The pointer to the
171/*	original getaddrinfo() result can be hidden at the end
172/*	after the null terminator, or before the first element.
173/* LICENSE
174/* .ad
175/* .fi
176/*	The Secure Mailer license must be distributed with this software.
177/* AUTHOR(S)
178/*	Wietse Venema
179/*	IBM T.J. Watson Research
180/*	P.O. Box 704
181/*	Yorktown Heights, NY 10598, USA
182/*--*/
183
184/* System library. */
185
186#include <sys_defs.h>
187#include <sys/types.h>
188#include <sys/socket.h>
189#include <netinet/in.h>
190#include <arpa/inet.h>
191#include <netdb.h>
192#include <string.h>
193#include <errno.h>
194#include <stdlib.h>
195#include <stdio.h>			/* sprintf() */
196
197/* Utility library. */
198
199#include <mymalloc.h>
200#include <valid_hostname.h>
201#include <sock_addr.h>
202#include <stringops.h>
203#include <msg.h>
204#include <inet_proto.h>
205#include <myaddrinfo.h>
206#include <split_at.h>
207
208/* Application-specific. */
209
210 /*
211  * Use an old trick to save some space: allocate space for two objects in
212  * one. In Postfix we often use this trick for structures that have an array
213  * of things at the end.
214  */
215struct ipv4addrinfo {
216    struct addrinfo info;
217    struct sockaddr_in sin;
218};
219
220 /*
221  * When we're not interested in service ports, we must pick a socket type
222  * otherwise getaddrinfo() will give us duplicate results: one set for TCP,
223  * and another set for UDP. For consistency, we'll use the same default
224  * socket type for the results from emulation mode.
225  */
226#define MAI_SOCKTYPE	SOCK_STREAM	/* getaddrinfo() query */
227
228#ifdef EMULATE_IPV4_ADDRINFO
229
230/* clone_ipv4addrinfo - clone ipv4addrinfo structure */
231
232static struct ipv4addrinfo *clone_ipv4addrinfo(struct ipv4addrinfo * tp)
233{
234    struct ipv4addrinfo *ip;
235
236    ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
237    *ip = *tp;
238    ip->info.ai_addr = (struct sockaddr *) & (ip->sin);
239    return (ip);
240}
241
242/* init_ipv4addrinfo - initialize an ipv4addrinfo structure */
243
244static void init_ipv4addrinfo(struct ipv4addrinfo * ip, int socktype)
245{
246
247    /*
248     * Portability: null pointers aren't necessarily all-zero bits, so we
249     * make explicit assignments to all the pointers that we're aware of.
250     */
251    memset((char *) ip, 0, sizeof(*ip));
252    ip->info.ai_family = PF_INET;
253    ip->info.ai_socktype = socktype;
254    ip->info.ai_protocol = 0;			/* XXX */
255    ip->info.ai_addrlen = sizeof(ip->sin);
256    ip->info.ai_canonname = 0;
257    ip->info.ai_addr = (struct sockaddr *) & (ip->sin);
258    ip->info.ai_next = 0;
259    ip->sin.sin_family = AF_INET;
260#ifdef HAS_SA_LEN
261    ip->sin.sin_len = sizeof(ip->sin);
262#endif
263}
264
265/* find_service - translate numeric or symbolic service name */
266
267static int find_service(const char *service, int socktype)
268{
269    struct servent *sp;
270    const char *proto;
271    unsigned port;
272
273    if (alldig(service)) {
274	port = atoi(service);
275	return (port < 65536 ? htons(port) : -1);
276    }
277    if (socktype == SOCK_STREAM) {
278	proto = "tcp";
279    } else if (socktype == SOCK_DGRAM) {
280	proto = "udp";
281    } else {
282	return (-1);
283    }
284    if ((sp = getservbyname(service, proto)) != 0) {
285	return (sp->s_port);
286    } else {
287	return (-1);
288    }
289}
290
291#endif
292
293/* hostname_to_sockaddr_pf - hostname to binary address form */
294
295int     hostname_to_sockaddr_pf(const char *hostname, int pf,
296			             const char *service, int socktype,
297			             struct addrinfo ** res)
298{
299#ifdef EMULATE_IPV4_ADDRINFO
300
301    /*
302     * Emulated getaddrinfo(3) version.
303     */
304    static struct ipv4addrinfo template;
305    struct ipv4addrinfo *ip;
306    struct ipv4addrinfo *prev;
307    struct in_addr addr;
308    struct hostent *hp;
309    char  **name_list;
310    int     port;
311
312    /*
313     * Validate the service.
314     */
315    if (service) {
316	if ((port = find_service(service, socktype)) < 0)
317	    return (EAI_SERVICE);
318    } else {
319	port = 0;
320	socktype = MAI_SOCKTYPE;
321    }
322
323    /*
324     * No host means INADDR_ANY.
325     */
326    if (hostname == 0) {
327	ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
328	init_ipv4addrinfo(ip, socktype);
329	ip->sin.sin_addr.s_addr = INADDR_ANY;
330	ip->sin.sin_port = port;
331	*res = &(ip->info);
332	return (0);
333    }
334
335    /*
336     * Numeric host.
337     */
338    if (inet_pton(AF_INET, hostname, (void *) &addr) == 1) {
339	ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
340	init_ipv4addrinfo(ip, socktype);
341	ip->sin.sin_addr = addr;
342	ip->sin.sin_port = port;
343	*res = &(ip->info);
344	return (0);
345    }
346
347    /*
348     * Look up the IPv4 address list.
349     */
350    if ((hp = gethostbyname(hostname)) == 0)
351	return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NODATA);
352    if (hp->h_addrtype != AF_INET
353	|| hp->h_length != sizeof(template.sin.sin_addr))
354	return (EAI_NODATA);
355
356    /*
357     * Initialize the result template.
358     */
359    if (template.info.ai_addrlen == 0)
360	init_ipv4addrinfo(&template, socktype);
361
362    /*
363     * Copy the address information into an addrinfo structure.
364     */
365    prev = &template;
366    for (name_list = hp->h_addr_list; name_list[0]; name_list++) {
367	ip = clone_ipv4addrinfo(prev);
368	ip->sin.sin_addr = IN_ADDR(name_list[0]);
369	ip->sin.sin_port = port;
370	if (prev == &template)
371	    *res = &(ip->info);
372	else
373	    prev->info.ai_next = &(ip->info);
374	prev = ip;
375    }
376    return (0);
377#else
378
379    /*
380     * Native getaddrinfo(3) version.
381     *
382     * XXX Wild-card listener issues.
383     *
384     * With most IPv4 plus IPv6 systems, an IPv6 wild-card listener also listens
385     * on the IPv4 wild-card address. Connections from IPv4 clients appear as
386     * IPv4-in-IPv6 addresses; when Postfix support for IPv4 is turned on,
387     * Postfix automatically maps these embedded addresses to their original
388     * IPv4 form. So everything seems to be fine.
389     *
390     * However, some applications prefer to use separate listener sockets for
391     * IPv4 and IPv6. The Postfix IPv6 patch provided such an example. And
392     * this is where things become tricky. On many systems the IPv6 and IPv4
393     * wild-card listeners cannot coexist. When one is already active, the
394     * other fails with EADDRINUSE. Solaris 9, however, will automagically
395     * "do the right thing" and allow both listeners to coexist.
396     *
397     * Recent systems have the IPV6_V6ONLY feature (RFC 3493), which tells the
398     * system that we really mean IPv6 when we say IPv6. This allows us to
399     * set up separate wild-card listener sockets for IPv4 and IPv6. So
400     * everything seems to be fine again.
401     *
402     * The following workaround disables the wild-card IPv4 listener when
403     * IPV6_V6ONLY is unavailable. This is necessary for some Linux versions,
404     * but is not needed for Solaris 9 (which allows IPv4 and IPv6 wild-card
405     * listeners to coexist). Solaris 10 beta already has IPV6_V6ONLY.
406     *
407     * XXX This workaround obviously breaks if we want to support protocols in
408     * addition to IPv6 and IPv4, but it is needed only until IPv6
409     * implementations catch up with RFC 3493. A nicer fix is to filter the
410     * getaddrinfo() result, and to return a vector of addrinfo pointers to
411     * only those types of elements that the caller has expressed interested
412     * in.
413     *
414     * XXX Vanilla AIX 5.1 getaddrinfo() does not support a null hostname with
415     * AI_PASSIVE. And since we don't know how getaddrinfo() manages its
416     * memory we can't bypass it for this special case, or freeaddrinfo()
417     * might blow up. Instead we turn off IPV6_V6ONLY in inet_listen(), and
418     * supply a protocol-dependent hard-coded string value to getaddrinfo()
419     * below, so that it will convert into the appropriate wild-card address.
420     *
421     * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null
422     * service argument is specified.
423     */
424    struct addrinfo hints;
425    int     err;
426
427    memset((char *) &hints, 0, sizeof(hints));
428    hints.ai_family = (pf != PF_UNSPEC) ? pf : inet_proto_info()->ai_family;
429    hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
430    if (!hostname) {
431	hints.ai_flags = AI_PASSIVE;
432#if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
433	switch (hints.ai_family) {
434	case PF_UNSPEC:
435	    hints.ai_family = PF_INET6;
436#ifdef BROKEN_AI_PASSIVE_NULL_HOST
437	case PF_INET6:
438	    hostname = "::";
439	    break;
440	case PF_INET:
441	    hostname = "0.0.0.0";
442	    break;
443#endif
444	}
445#endif
446    }
447    err = getaddrinfo(hostname, service, &hints, res);
448#if defined(BROKEN_AI_NULL_SERVICE)
449    if (service == 0 && err == 0) {
450	struct addrinfo *r;
451	unsigned short *portp;
452
453	for (r = *res; r != 0; r = r->ai_next)
454	    if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0)
455		*portp = 0;
456    }
457#endif
458    return (err);
459#endif
460}
461
462/* hostaddr_to_sockaddr - printable address to binary address form */
463
464int     hostaddr_to_sockaddr(const char *hostaddr, const char *service,
465			             int socktype, struct addrinfo ** res)
466{
467#ifdef EMULATE_IPV4_ADDRINFO
468
469    /*
470     * Emulated getaddrinfo(3) version.
471     */
472    struct ipv4addrinfo *ip;
473    struct in_addr addr;
474    int     port;
475
476    /*
477     * Validate the service.
478     */
479    if (service) {
480	if ((port = find_service(service, socktype)) < 0)
481	    return (EAI_SERVICE);
482    } else {
483	port = 0;
484	socktype = MAI_SOCKTYPE;
485    }
486
487    /*
488     * No host means INADDR_ANY.
489     */
490    if (hostaddr == 0) {
491	ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
492	init_ipv4addrinfo(ip, socktype);
493	ip->sin.sin_addr.s_addr = INADDR_ANY;
494	ip->sin.sin_port = port;
495	*res = &(ip->info);
496	return (0);
497    }
498
499    /*
500     * Deal with bad address forms.
501     */
502    switch (inet_pton(AF_INET, hostaddr, (void *) &addr)) {
503    case 1:					/* Success */
504	break;
505    default:					/* Unparsable */
506	return (EAI_NONAME);
507    case -1:					/* See errno */
508	return (EAI_SYSTEM);
509    }
510
511    /*
512     * Initialize the result structure.
513     */
514    ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
515    init_ipv4addrinfo(ip, socktype);
516
517    /*
518     * And copy the result.
519     */
520    ip->sin.sin_addr = addr;
521    ip->sin.sin_port = port;
522    *res = &(ip->info);
523
524    return (0);
525#else
526
527    /*
528     * Native getaddrinfo(3) version. See comments in hostname_to_sockaddr().
529     *
530     * XXX Vanilla AIX 5.1 getaddrinfo() returns multiple results when
531     * converting a printable ipv4 or ipv6 address to socket address with
532     * ai_family=PF_UNSPEC, ai_flags=AI_NUMERICHOST, ai_socktype=SOCK_STREAM,
533     * ai_protocol=0 or IPPROTO_TCP, and service=0. The workaround is to
534     * ignore all but the first result.
535     *
536     * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null
537     * service argument is specified.
538     */
539    struct addrinfo hints;
540    int     err;
541
542    memset(&hints, 0, sizeof(hints));
543    hints.ai_family = inet_proto_info()->ai_family;
544    hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
545    hints.ai_flags = AI_NUMERICHOST;
546    if (!hostaddr) {
547	hints.ai_flags |= AI_PASSIVE;
548#if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
549	switch (hints.ai_family) {
550	case PF_UNSPEC:
551	    hints.ai_family = PF_INET6;
552#ifdef BROKEN_AI_PASSIVE_NULL_HOST
553	case PF_INET6:
554	    hostaddr = "::";
555	    break;
556	case PF_INET:
557	    hostaddr = "0.0.0.0";
558	    break;
559#endif
560	}
561#endif
562    }
563    err = getaddrinfo(hostaddr, service, &hints, res);
564#if defined(BROKEN_AI_NULL_SERVICE)
565    if (service == 0 && err == 0) {
566	struct addrinfo *r;
567	unsigned short *portp;
568
569	for (r = *res; r != 0; r = r->ai_next)
570	    if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0)
571		*portp = 0;
572    }
573#endif
574    return (err);
575#endif
576}
577
578/* sockaddr_to_hostaddr - binary address to printable address form */
579
580int     sockaddr_to_hostaddr(const struct sockaddr * sa, SOCKADDR_SIZE salen,
581			             MAI_HOSTADDR_STR *hostaddr,
582			             MAI_SERVPORT_STR *portnum,
583			             int unused_socktype)
584{
585#ifdef EMULATE_IPV4_ADDRINFO
586    char    portbuf[sizeof("65535")];
587    ssize_t len;
588
589    /*
590     * Emulated getnameinfo(3) version. The buffer length includes the space
591     * for the null terminator.
592     */
593    if (sa->sa_family != AF_INET) {
594	errno = EAFNOSUPPORT;
595	return (EAI_SYSTEM);
596    }
597    if (hostaddr != 0) {
598	if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)),
599		      hostaddr->buf, sizeof(hostaddr->buf)) == 0)
600	    return (EAI_SYSTEM);
601    }
602    if (portnum != 0) {
603	sprintf(portbuf, "%d", ntohs(SOCK_ADDR_IN_PORT(sa)) & 0xffff);
604	if ((len = strlen(portbuf)) >= sizeof(portnum->buf)) {
605	    errno = ENOSPC;
606	    return (EAI_SYSTEM);
607	}
608	memcpy(portnum->buf, portbuf, len + 1);
609    }
610    return (0);
611#else
612    int     ret;
613
614    /*
615     * Native getnameinfo(3) version.
616     */
617    ret = getnameinfo(sa, salen,
618		      hostaddr ? hostaddr->buf : (char *) 0,
619		      hostaddr ? sizeof(hostaddr->buf) : 0,
620		      portnum ? portnum->buf : (char *) 0,
621		      portnum ? sizeof(portnum->buf) : 0,
622		      NI_NUMERICHOST | NI_NUMERICSERV);
623    if (hostaddr != 0 && ret == 0 && sa->sa_family == AF_INET6)
624	(void) split_at(hostaddr->buf, '%');
625    return (ret);
626#endif
627}
628
629/* sockaddr_to_hostname - binary address to printable hostname */
630
631int     sockaddr_to_hostname(const struct sockaddr * sa, SOCKADDR_SIZE salen,
632			             MAI_HOSTNAME_STR *hostname,
633			             MAI_SERVNAME_STR *service,
634			             int socktype)
635{
636#ifdef EMULATE_IPV4_ADDRINFO
637
638    /*
639     * Emulated getnameinfo(3) version.
640     */
641    struct hostent *hp;
642    struct servent *sp;
643    size_t  len;
644
645    /*
646     * Sanity check.
647     */
648    if (sa->sa_family != AF_INET)
649	return (EAI_NODATA);
650
651    /*
652     * Look up the host name.
653     */
654    if (hostname != 0) {
655	if ((hp = gethostbyaddr((char *) &(SOCK_ADDR_IN_ADDR(sa)),
656				sizeof(SOCK_ADDR_IN_ADDR(sa)),
657				AF_INET)) == 0)
658	    return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NONAME);
659
660	/*
661	 * Save the result. The buffer length includes the space for the null
662	 * terminator. Hostname sanity checks are at the end of this
663	 * function.
664	 */
665	if ((len = strlen(hp->h_name)) >= sizeof(hostname->buf)) {
666	    errno = ENOSPC;
667	    return (EAI_SYSTEM);
668	}
669	memcpy(hostname->buf, hp->h_name, len + 1);
670    }
671
672    /*
673     * Look up the service.
674     */
675    if (service != 0) {
676	if ((sp = getservbyport(ntohs(SOCK_ADDR_IN_PORT(sa)),
677			      socktype == SOCK_DGRAM ? "udp" : "tcp")) == 0)
678	    return (EAI_NONAME);
679
680	/*
681	 * Save the result. The buffer length includes the space for the null
682	 * terminator.
683	 */
684	if ((len = strlen(sp->s_name)) >= sizeof(service->buf)) {
685	    errno = ENOSPC;
686	    return (EAI_SYSTEM);
687	}
688	memcpy(service->buf, sp->s_name, len + 1);
689    }
690#else
691
692    /*
693     * Native getnameinfo(3) version.
694     */
695    int     err;
696
697    err = getnameinfo(sa, salen,
698		      hostname ? hostname->buf : (char *) 0,
699		      hostname ? sizeof(hostname->buf) : 0,
700		      service ? service->buf : (char *) 0,
701		      service ? sizeof(service->buf) : 0,
702		      socktype == SOCK_DGRAM ?
703		      NI_NAMEREQD | NI_DGRAM : NI_NAMEREQD);
704    if (err != 0)
705	return (err);
706#endif
707
708    /*
709     * Hostname sanity checks.
710     */
711    if (hostname != 0) {
712	if (valid_hostaddr(hostname->buf, DONT_GRIPE)) {
713	    msg_warn("numeric hostname: %s", hostname->buf);
714	    return (EAI_NONAME);
715	}
716	if (!valid_hostname(hostname->buf, DO_GRIPE))
717	    return (EAI_NONAME);
718    }
719    return (0);
720}
721
722/* myaddrinfo_control - fine control */
723
724void    myaddrinfo_control(int name,...)
725{
726    const char *myname = "myaddrinfo_control";
727    va_list ap;
728
729    for (va_start(ap, name); name != 0; name = va_arg(ap, int)) {
730	switch (name) {
731	default:
732	    msg_panic("%s: bad name %d", myname, name);
733	}
734    }
735    va_end(ap);
736}
737
738#ifdef EMULATE_IPV4_ADDRINFO
739
740/* freeaddrinfo - release storage */
741
742void    freeaddrinfo(struct addrinfo * ai)
743{
744    struct addrinfo *ap;
745    struct addrinfo *next;
746
747    /*
748     * Artefact of implementation: tolerate a null pointer argument.
749     */
750    for (ap = ai; ap != 0; ap = next) {
751	next = ap->ai_next;
752	if (ap->ai_canonname)
753	    myfree(ap->ai_canonname);
754	/* ap->ai_addr is allocated within this memory block */
755	myfree((char *) ap);
756    }
757}
758
759static char *ai_errlist[] = {
760    "Success",
761    "Address family for hostname not supported",	/* EAI_ADDRFAMILY */
762    "Temporary failure in name resolution",	/* EAI_AGAIN	 */
763    "Invalid value for ai_flags",	/* EAI_BADFLAGS   */
764    "Non-recoverable failure in name resolution",	/* EAI_FAIL	 */
765    "ai_family not supported",		/* EAI_FAMILY     */
766    "Memory allocation failure",	/* EAI_MEMORY     */
767    "No address associated with hostname",	/* EAI_NODATA     */
768    "hostname nor servname provided, or not known",	/* EAI_NONAME     */
769    "service name not supported for ai_socktype",	/* EAI_SERVICE    */
770    "ai_socktype not supported",	/* EAI_SOCKTYPE   */
771    "System error returned in errno",	/* EAI_SYSTEM     */
772    "Invalid value for hints",		/* EAI_BADHINTS   */
773    "Resolved protocol is unknown",	/* EAI_PROTOCOL   */
774    "Unknown error",			/* EAI_MAX	  */
775};
776
777/* gai_strerror - error number to string */
778
779char   *gai_strerror(int ecode)
780{
781
782    /*
783     * Note: EAI_SYSTEM errors are not automatically handed over to
784     * strerror(). The application decides.
785     */
786    if (ecode < 0 || ecode > EAI_MAX)
787	ecode = EAI_MAX;
788    return (ai_errlist[ecode]);
789}
790
791#endif
792
793#ifdef TEST
794
795 /*
796  * A test program that takes some info from the command line and runs it
797  * forward and backward through the above conversion routines.
798  */
799#include <msg.h>
800#include <vstream.h>
801#include <msg_vstream.h>
802
803int     main(int argc, char **argv)
804{
805    struct addrinfo *info;
806    struct addrinfo *ip;
807    MAI_HOSTNAME_STR host;
808    MAI_HOSTADDR_STR addr;
809    int     err;
810
811    msg_vstream_init(argv[0], VSTREAM_ERR);
812
813    if (argc != 4)
814	msg_fatal("usage: %s protocols hostname hostaddress", argv[0]);
815
816    inet_proto_init(argv[0], argv[1]);
817
818    msg_info("=== hostname %s ===", argv[2]);
819
820    if ((err = hostname_to_sockaddr(argv[2], (char *) 0, 0, &info)) != 0) {
821	msg_info("hostname_to_sockaddr(%s): %s",
822	  argv[2], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
823    } else {
824	for (ip = info; ip != 0; ip = ip->ai_next) {
825	    if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
826					 (MAI_SERVPORT_STR *) 0, 0)) != 0) {
827		msg_info("sockaddr_to_hostaddr: %s",
828		   err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
829		continue;
830	    }
831	    msg_info("%s -> family=%d sock=%d proto=%d %s", argv[2],
832		 ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf);
833	    if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
834					 (MAI_SERVNAME_STR *) 0, 0)) != 0) {
835		msg_info("sockaddr_to_hostname: %s",
836		   err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
837		continue;
838	    }
839	    msg_info("%s -> %s", addr.buf, host.buf);
840	}
841	freeaddrinfo(info);
842    }
843
844    msg_info("=== host address %s ===", argv[3]);
845
846    if ((err = hostaddr_to_sockaddr(argv[3], (char *) 0, 0, &ip)) != 0) {
847	msg_info("hostaddr_to_sockaddr(%s): %s",
848	  argv[3], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
849    } else {
850	if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
851					(MAI_SERVPORT_STR *) 0, 0)) != 0) {
852	    msg_info("sockaddr_to_hostaddr: %s",
853		   err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
854	} else {
855	    msg_info("%s -> family=%d sock=%d proto=%d %s", argv[3],
856		 ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf);
857	    if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
858					 (MAI_SERVNAME_STR *) 0, 0)) != 0) {
859		msg_info("sockaddr_to_hostname: %s",
860		   err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
861	    } else
862		msg_info("%s -> %s", addr.buf, host.buf);
863	    freeaddrinfo(ip);
864	}
865    }
866    exit(0);
867}
868
869#endif
870