xref: /minix3/external/bsd/tcpdump/dist/missing/getnameinfo.c (revision b636d99d91c3d54204248f643c14627405d4afd1)
1*b636d99dSDavid van Moolenbroek /*
2*b636d99dSDavid van Moolenbroek  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3*b636d99dSDavid van Moolenbroek  * All rights reserved.
4*b636d99dSDavid van Moolenbroek  *
5*b636d99dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
6*b636d99dSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
7*b636d99dSDavid van Moolenbroek  * are met:
8*b636d99dSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
9*b636d99dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
10*b636d99dSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
11*b636d99dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
12*b636d99dSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
13*b636d99dSDavid van Moolenbroek  * 3. Neither the name of the project nor the names of its contributors
14*b636d99dSDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
15*b636d99dSDavid van Moolenbroek  *    without specific prior written permission.
16*b636d99dSDavid van Moolenbroek  *
17*b636d99dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18*b636d99dSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*b636d99dSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*b636d99dSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21*b636d99dSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*b636d99dSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*b636d99dSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*b636d99dSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*b636d99dSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*b636d99dSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*b636d99dSDavid van Moolenbroek  * SUCH DAMAGE.
28*b636d99dSDavid van Moolenbroek  */
29*b636d99dSDavid van Moolenbroek 
30*b636d99dSDavid van Moolenbroek /*
31*b636d99dSDavid van Moolenbroek  * Issues to be discussed:
32*b636d99dSDavid van Moolenbroek  * - Thread safe-ness must be checked
33*b636d99dSDavid van Moolenbroek  * - Return values.  There seems to be no standard for return value (RFC2553)
34*b636d99dSDavid van Moolenbroek  *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
35*b636d99dSDavid van Moolenbroek  * - RFC2553 says that we should raise error on short buffer.  X/Open says
36*b636d99dSDavid van Moolenbroek  *   we need to truncate the result.  We obey RFC2553 (and X/Open should be
37*b636d99dSDavid van Moolenbroek  *   modified).
38*b636d99dSDavid van Moolenbroek  */
39*b636d99dSDavid van Moolenbroek 
40*b636d99dSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
41*b636d99dSDavid van Moolenbroek #include <config.h>
42*b636d99dSDavid van Moolenbroek #endif
43*b636d99dSDavid van Moolenbroek 
44*b636d99dSDavid van Moolenbroek #include <sys/types.h>
45*b636d99dSDavid van Moolenbroek #include <sys/socket.h>
46*b636d99dSDavid van Moolenbroek #include <net/if.h>
47*b636d99dSDavid van Moolenbroek #include <netinet/in.h>
48*b636d99dSDavid van Moolenbroek #include <arpa/inet.h>
49*b636d99dSDavid van Moolenbroek #include <arpa/nameser.h>
50*b636d99dSDavid van Moolenbroek #include <netdb.h>
51*b636d99dSDavid van Moolenbroek #include <resolv.h>
52*b636d99dSDavid van Moolenbroek #include <string.h>
53*b636d99dSDavid van Moolenbroek #include <stddef.h>
54*b636d99dSDavid van Moolenbroek #include <errno.h>
55*b636d99dSDavid van Moolenbroek 
56*b636d99dSDavid van Moolenbroek #ifdef NEED_ADDRINFO_H
57*b636d99dSDavid van Moolenbroek #include "addrinfo.h"
58*b636d99dSDavid van Moolenbroek #endif
59*b636d99dSDavid van Moolenbroek 
60*b636d99dSDavid van Moolenbroek #define SUCCESS 0
61*b636d99dSDavid van Moolenbroek #define ANY 0
62*b636d99dSDavid van Moolenbroek #define YES 1
63*b636d99dSDavid van Moolenbroek #define NO  0
64*b636d99dSDavid van Moolenbroek 
65*b636d99dSDavid van Moolenbroek static struct afd {
66*b636d99dSDavid van Moolenbroek 	int a_af;
67*b636d99dSDavid van Moolenbroek 	int a_addrlen;
68*b636d99dSDavid van Moolenbroek 	int a_socklen;
69*b636d99dSDavid van Moolenbroek 	int a_off;
70*b636d99dSDavid van Moolenbroek } afdl [] = {
71*b636d99dSDavid van Moolenbroek #ifdef INET6
72*b636d99dSDavid van Moolenbroek 	{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
73*b636d99dSDavid van Moolenbroek 		offsetof(struct sockaddr_in6, sin6_addr)},
74*b636d99dSDavid van Moolenbroek #endif
75*b636d99dSDavid van Moolenbroek 	{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
76*b636d99dSDavid van Moolenbroek 		offsetof(struct sockaddr_in, sin_addr)},
77*b636d99dSDavid van Moolenbroek 	{0, 0, 0},
78*b636d99dSDavid van Moolenbroek };
79*b636d99dSDavid van Moolenbroek 
80*b636d99dSDavid van Moolenbroek struct sockinet {
81*b636d99dSDavid van Moolenbroek 	u_char	si_len;
82*b636d99dSDavid van Moolenbroek 	u_char	si_family;
83*b636d99dSDavid van Moolenbroek 	u_short	si_port;
84*b636d99dSDavid van Moolenbroek };
85*b636d99dSDavid van Moolenbroek 
86*b636d99dSDavid van Moolenbroek #define ENI_NOSOCKET 	0
87*b636d99dSDavid van Moolenbroek #define ENI_NOSERVNAME	1
88*b636d99dSDavid van Moolenbroek #define ENI_NOHOSTNAME	2
89*b636d99dSDavid van Moolenbroek #define ENI_MEMORY	3
90*b636d99dSDavid van Moolenbroek #define ENI_SYSTEM	4
91*b636d99dSDavid van Moolenbroek #define ENI_FAMILY	5
92*b636d99dSDavid van Moolenbroek #define ENI_SALEN	6
93*b636d99dSDavid van Moolenbroek 
94*b636d99dSDavid van Moolenbroek int
getnameinfo(sa,salen,host,hostlen,serv,servlen,flags)95*b636d99dSDavid van Moolenbroek getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
96*b636d99dSDavid van Moolenbroek 	const struct sockaddr *sa;
97*b636d99dSDavid van Moolenbroek 	size_t salen;
98*b636d99dSDavid van Moolenbroek 	char *host;
99*b636d99dSDavid van Moolenbroek 	size_t hostlen;
100*b636d99dSDavid van Moolenbroek 	char *serv;
101*b636d99dSDavid van Moolenbroek 	size_t servlen;
102*b636d99dSDavid van Moolenbroek 	int flags;
103*b636d99dSDavid van Moolenbroek {
104*b636d99dSDavid van Moolenbroek 	struct afd *afd;
105*b636d99dSDavid van Moolenbroek 	struct servent *sp;
106*b636d99dSDavid van Moolenbroek 	struct hostent *hp;
107*b636d99dSDavid van Moolenbroek 	u_short port;
108*b636d99dSDavid van Moolenbroek 	int family, i;
109*b636d99dSDavid van Moolenbroek 	char *addr, *p;
110*b636d99dSDavid van Moolenbroek 	uint32_t v4a;
111*b636d99dSDavid van Moolenbroek 	int h_error;
112*b636d99dSDavid van Moolenbroek 	char numserv[512];
113*b636d99dSDavid van Moolenbroek 	char numaddr[512];
114*b636d99dSDavid van Moolenbroek 
115*b636d99dSDavid van Moolenbroek 	if (sa == NULL)
116*b636d99dSDavid van Moolenbroek 		return ENI_NOSOCKET;
117*b636d99dSDavid van Moolenbroek 
118*b636d99dSDavid van Moolenbroek #ifdef HAVE_SA_LEN	/*XXX*/
119*b636d99dSDavid van Moolenbroek 	if (sa->sa_len != salen)
120*b636d99dSDavid van Moolenbroek 		return ENI_SALEN;
121*b636d99dSDavid van Moolenbroek #endif
122*b636d99dSDavid van Moolenbroek 
123*b636d99dSDavid van Moolenbroek 	family = sa->sa_family;
124*b636d99dSDavid van Moolenbroek 	for (i = 0; afdl[i].a_af; i++)
125*b636d99dSDavid van Moolenbroek 		if (afdl[i].a_af == family) {
126*b636d99dSDavid van Moolenbroek 			afd = &afdl[i];
127*b636d99dSDavid van Moolenbroek 			goto found;
128*b636d99dSDavid van Moolenbroek 		}
129*b636d99dSDavid van Moolenbroek 	return ENI_FAMILY;
130*b636d99dSDavid van Moolenbroek 
131*b636d99dSDavid van Moolenbroek  found:
132*b636d99dSDavid van Moolenbroek 	if (salen != afd->a_socklen)
133*b636d99dSDavid van Moolenbroek 		return ENI_SALEN;
134*b636d99dSDavid van Moolenbroek 
135*b636d99dSDavid van Moolenbroek 	port = ((struct sockinet *)sa)->si_port; /* network byte order */
136*b636d99dSDavid van Moolenbroek 	addr = (char *)sa + afd->a_off;
137*b636d99dSDavid van Moolenbroek 
138*b636d99dSDavid van Moolenbroek 	if (serv == NULL || servlen == 0) {
139*b636d99dSDavid van Moolenbroek 		/*
140*b636d99dSDavid van Moolenbroek 		 * do nothing in this case.
141*b636d99dSDavid van Moolenbroek 		 * in case you are wondering if "&&" is more correct than
142*b636d99dSDavid van Moolenbroek 		 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
143*b636d99dSDavid van Moolenbroek 		 * means that the caller does not want the result.
144*b636d99dSDavid van Moolenbroek 		 */
145*b636d99dSDavid van Moolenbroek 	} else {
146*b636d99dSDavid van Moolenbroek 		if (flags & NI_NUMERICSERV)
147*b636d99dSDavid van Moolenbroek 			sp = NULL;
148*b636d99dSDavid van Moolenbroek 		else {
149*b636d99dSDavid van Moolenbroek 			sp = getservbyport(port,
150*b636d99dSDavid van Moolenbroek 				(flags & NI_DGRAM) ? "udp" : "tcp");
151*b636d99dSDavid van Moolenbroek 		}
152*b636d99dSDavid van Moolenbroek 		if (sp) {
153*b636d99dSDavid van Moolenbroek 			if (strlen(sp->s_name) + 1 > servlen)
154*b636d99dSDavid van Moolenbroek 				return ENI_MEMORY;
155*b636d99dSDavid van Moolenbroek 			strcpy(serv, sp->s_name);
156*b636d99dSDavid van Moolenbroek 		} else {
157*b636d99dSDavid van Moolenbroek 			snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
158*b636d99dSDavid van Moolenbroek 			if (strlen(numserv) + 1 > servlen)
159*b636d99dSDavid van Moolenbroek 				return ENI_MEMORY;
160*b636d99dSDavid van Moolenbroek 			strcpy(serv, numserv);
161*b636d99dSDavid van Moolenbroek 		}
162*b636d99dSDavid van Moolenbroek 	}
163*b636d99dSDavid van Moolenbroek 
164*b636d99dSDavid van Moolenbroek 	switch (sa->sa_family) {
165*b636d99dSDavid van Moolenbroek 	case AF_INET:
166*b636d99dSDavid van Moolenbroek                 v4a = (uint32_t)
167*b636d99dSDavid van Moolenbroek 			ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
168*b636d99dSDavid van Moolenbroek 		if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
169*b636d99dSDavid van Moolenbroek 			flags |= NI_NUMERICHOST;
170*b636d99dSDavid van Moolenbroek 		v4a >>= IN_CLASSA_NSHIFT;
171*b636d99dSDavid van Moolenbroek 		if (v4a == 0)
172*b636d99dSDavid van Moolenbroek 			flags |= NI_NUMERICHOST;
173*b636d99dSDavid van Moolenbroek 		break;
174*b636d99dSDavid van Moolenbroek #ifdef INET6
175*b636d99dSDavid van Moolenbroek 	case AF_INET6:
176*b636d99dSDavid van Moolenbroek 	    {
177*b636d99dSDavid van Moolenbroek 		struct sockaddr_in6 *sin6;
178*b636d99dSDavid van Moolenbroek 		sin6 = (struct sockaddr_in6 *)sa;
179*b636d99dSDavid van Moolenbroek 		switch (sin6->sin6_addr.s6_addr[0]) {
180*b636d99dSDavid van Moolenbroek 		case 0x00:
181*b636d99dSDavid van Moolenbroek 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
182*b636d99dSDavid van Moolenbroek 				;
183*b636d99dSDavid van Moolenbroek 			else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
184*b636d99dSDavid van Moolenbroek 				;
185*b636d99dSDavid van Moolenbroek 			else
186*b636d99dSDavid van Moolenbroek 				flags |= NI_NUMERICHOST;
187*b636d99dSDavid van Moolenbroek 			break;
188*b636d99dSDavid van Moolenbroek 		default:
189*b636d99dSDavid van Moolenbroek 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
190*b636d99dSDavid van Moolenbroek 				flags |= NI_NUMERICHOST;
191*b636d99dSDavid van Moolenbroek 			}
192*b636d99dSDavid van Moolenbroek 			else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
193*b636d99dSDavid van Moolenbroek 				flags |= NI_NUMERICHOST;
194*b636d99dSDavid van Moolenbroek 			break;
195*b636d99dSDavid van Moolenbroek 		}
196*b636d99dSDavid van Moolenbroek 	    }
197*b636d99dSDavid van Moolenbroek 		break;
198*b636d99dSDavid van Moolenbroek #endif
199*b636d99dSDavid van Moolenbroek 	}
200*b636d99dSDavid van Moolenbroek 	if (host == NULL || hostlen == 0) {
201*b636d99dSDavid van Moolenbroek 		/*
202*b636d99dSDavid van Moolenbroek 		 * do nothing in this case.
203*b636d99dSDavid van Moolenbroek 		 * in case you are wondering if "&&" is more correct than
204*b636d99dSDavid van Moolenbroek 		 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
205*b636d99dSDavid van Moolenbroek 		 * means that the caller does not want the result.
206*b636d99dSDavid van Moolenbroek 		 */
207*b636d99dSDavid van Moolenbroek 	} else if (flags & NI_NUMERICHOST) {
208*b636d99dSDavid van Moolenbroek 		/* NUMERICHOST and NAMEREQD conflicts with each other */
209*b636d99dSDavid van Moolenbroek 		if (flags & NI_NAMEREQD)
210*b636d99dSDavid van Moolenbroek 			return ENI_NOHOSTNAME;
211*b636d99dSDavid van Moolenbroek 		if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
212*b636d99dSDavid van Moolenbroek 		    == NULL)
213*b636d99dSDavid van Moolenbroek 			return ENI_SYSTEM;
214*b636d99dSDavid van Moolenbroek 		if (strlen(numaddr) + 1 > hostlen)
215*b636d99dSDavid van Moolenbroek 			return ENI_MEMORY;
216*b636d99dSDavid van Moolenbroek 		strcpy(host, numaddr);
217*b636d99dSDavid van Moolenbroek #if defined(INET6) && defined(NI_WITHSCOPEID)
218*b636d99dSDavid van Moolenbroek 		if (afd->a_af == AF_INET6 &&
219*b636d99dSDavid van Moolenbroek 		    (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
220*b636d99dSDavid van Moolenbroek 		     IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
221*b636d99dSDavid van Moolenbroek 		    ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
222*b636d99dSDavid van Moolenbroek #ifndef ALWAYS_WITHSCOPE
223*b636d99dSDavid van Moolenbroek 			if (flags & NI_WITHSCOPEID)
224*b636d99dSDavid van Moolenbroek #endif /* !ALWAYS_WITHSCOPE */
225*b636d99dSDavid van Moolenbroek 			{
226*b636d99dSDavid van Moolenbroek 				char *ep = strchr(host, '\0');
227*b636d99dSDavid van Moolenbroek 				unsigned int ifindex =
228*b636d99dSDavid van Moolenbroek 					((struct sockaddr_in6 *)sa)->sin6_scope_id;
229*b636d99dSDavid van Moolenbroek 
230*b636d99dSDavid van Moolenbroek 				*ep = SCOPE_DELIMITER;
231*b636d99dSDavid van Moolenbroek 				if ((if_indextoname(ifindex, ep + 1)) == NULL)
232*b636d99dSDavid van Moolenbroek 					/* XXX what should we do? */
233*b636d99dSDavid van Moolenbroek 					strncpy(ep + 1, "???", 3);
234*b636d99dSDavid van Moolenbroek 			}
235*b636d99dSDavid van Moolenbroek 		}
236*b636d99dSDavid van Moolenbroek #endif /* INET6 */
237*b636d99dSDavid van Moolenbroek 	} else {
238*b636d99dSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
239*b636d99dSDavid van Moolenbroek 		hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
240*b636d99dSDavid van Moolenbroek #else
241*b636d99dSDavid van Moolenbroek 		hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
242*b636d99dSDavid van Moolenbroek #ifdef HAVE_H_ERRNO
243*b636d99dSDavid van Moolenbroek 		h_error = h_errno;
244*b636d99dSDavid van Moolenbroek #else
245*b636d99dSDavid van Moolenbroek 		h_error = EINVAL;
246*b636d99dSDavid van Moolenbroek #endif
247*b636d99dSDavid van Moolenbroek #endif
248*b636d99dSDavid van Moolenbroek 
249*b636d99dSDavid van Moolenbroek 		if (hp) {
250*b636d99dSDavid van Moolenbroek 			if (flags & NI_NOFQDN) {
251*b636d99dSDavid van Moolenbroek 				p = strchr(hp->h_name, '.');
252*b636d99dSDavid van Moolenbroek 				if (p) *p = '\0';
253*b636d99dSDavid van Moolenbroek 			}
254*b636d99dSDavid van Moolenbroek 			if (strlen(hp->h_name) + 1 > hostlen) {
255*b636d99dSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
256*b636d99dSDavid van Moolenbroek 				freehostent(hp);
257*b636d99dSDavid van Moolenbroek #endif
258*b636d99dSDavid van Moolenbroek 				return ENI_MEMORY;
259*b636d99dSDavid van Moolenbroek 			}
260*b636d99dSDavid van Moolenbroek 			strcpy(host, hp->h_name);
261*b636d99dSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
262*b636d99dSDavid van Moolenbroek 			freehostent(hp);
263*b636d99dSDavid van Moolenbroek #endif
264*b636d99dSDavid van Moolenbroek 		} else {
265*b636d99dSDavid van Moolenbroek 			if (flags & NI_NAMEREQD)
266*b636d99dSDavid van Moolenbroek 				return ENI_NOHOSTNAME;
267*b636d99dSDavid van Moolenbroek 			if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
268*b636d99dSDavid van Moolenbroek 			    == NULL)
269*b636d99dSDavid van Moolenbroek 				return ENI_NOHOSTNAME;
270*b636d99dSDavid van Moolenbroek 			if (strlen(numaddr) + 1 > hostlen)
271*b636d99dSDavid van Moolenbroek 				return ENI_MEMORY;
272*b636d99dSDavid van Moolenbroek 			strcpy(host, numaddr);
273*b636d99dSDavid van Moolenbroek 		}
274*b636d99dSDavid van Moolenbroek 	}
275*b636d99dSDavid van Moolenbroek 	return SUCCESS;
276*b636d99dSDavid van Moolenbroek }
277