xref: /netbsd-src/external/bsd/unbound/dist/compat/fake-rfc2553.c (revision 3b6c3722d8f990f9a667d638078aee8ccdc3c0f3)
1*3b6c3722Schristos /* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */
2*3b6c3722Schristos /*
3*3b6c3722Schristos  * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
4*3b6c3722Schristos  * Copyright (C) 1999 WIDE Project.  All rights reserved.
5*3b6c3722Schristos  *
6*3b6c3722Schristos  * Redistribution and use in source and binary forms, with or without
7*3b6c3722Schristos  * modification, are permitted provided that the following conditions
8*3b6c3722Schristos  * are met:
9*3b6c3722Schristos  * 1. Redistributions of source code must retain the above copyright
10*3b6c3722Schristos  *    notice, this list of conditions and the following disclaimer.
11*3b6c3722Schristos  * 2. Redistributions in binary form must reproduce the above copyright
12*3b6c3722Schristos  *    notice, this list of conditions and the following disclaimer in the
13*3b6c3722Schristos  *    documentation and/or other materials provided with the distribution.
14*3b6c3722Schristos  * 3. Neither the name of the project nor the names of its contributors
15*3b6c3722Schristos  *    may be used to endorse or promote products derived from this software
16*3b6c3722Schristos  *    without specific prior written permission.
17*3b6c3722Schristos  *
18*3b6c3722Schristos  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19*3b6c3722Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*3b6c3722Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*3b6c3722Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22*3b6c3722Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*3b6c3722Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*3b6c3722Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*3b6c3722Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*3b6c3722Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*3b6c3722Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*3b6c3722Schristos  * SUCH DAMAGE.
29*3b6c3722Schristos  */
30*3b6c3722Schristos 
31*3b6c3722Schristos /*
32*3b6c3722Schristos  * Pseudo-implementation of RFC2553 name / address resolution functions
33*3b6c3722Schristos  *
34*3b6c3722Schristos  * But these functions are not implemented correctly. The minimum subset
35*3b6c3722Schristos  * is implemented for ssh use only. For example, this routine assumes
36*3b6c3722Schristos  * that ai_family is AF_INET. Don't use it for another purpose.
37*3b6c3722Schristos  */
38*3b6c3722Schristos 
39*3b6c3722Schristos #include <unistd.h>
40*3b6c3722Schristos #include <string.h>
41*3b6c3722Schristos #include <stdio.h>
42*3b6c3722Schristos #include <stdlib.h>
43*3b6c3722Schristos #include "compat/fake-rfc2553.h"
44*3b6c3722Schristos 
45*3b6c3722Schristos #ifndef HAVE_GETNAMEINFO
getnameinfo(const struct sockaddr * sa,size_t ATTR_UNUSED (salen),char * host,size_t hostlen,char * serv,size_t servlen,int flags)46*3b6c3722Schristos int getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host,
47*3b6c3722Schristos                 size_t hostlen, char *serv, size_t servlen, int flags)
48*3b6c3722Schristos {
49*3b6c3722Schristos 	struct sockaddr_in *sin = (struct sockaddr_in *)sa;
50*3b6c3722Schristos 	struct hostent *hp;
51*3b6c3722Schristos 	char tmpserv[16];
52*3b6c3722Schristos 
53*3b6c3722Schristos 	if (serv != NULL) {
54*3b6c3722Schristos 		snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
55*3b6c3722Schristos 		if (strlcpy(serv, tmpserv, servlen) >= servlen)
56*3b6c3722Schristos 			return (EAI_MEMORY);
57*3b6c3722Schristos 	}
58*3b6c3722Schristos 
59*3b6c3722Schristos 	if (host != NULL) {
60*3b6c3722Schristos 		if (flags & NI_NUMERICHOST) {
61*3b6c3722Schristos 			if (strlcpy(host, inet_ntoa(sin->sin_addr),
62*3b6c3722Schristos 			    hostlen) >= hostlen)
63*3b6c3722Schristos 				return (EAI_MEMORY);
64*3b6c3722Schristos 			else
65*3b6c3722Schristos 				return (0);
66*3b6c3722Schristos 		} else {
67*3b6c3722Schristos 			hp = gethostbyaddr((char *)&sin->sin_addr,
68*3b6c3722Schristos 			    sizeof(struct in_addr), AF_INET);
69*3b6c3722Schristos 			if (hp == NULL)
70*3b6c3722Schristos 				return (EAI_NODATA);
71*3b6c3722Schristos 
72*3b6c3722Schristos 			if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
73*3b6c3722Schristos 				return (EAI_MEMORY);
74*3b6c3722Schristos 			else
75*3b6c3722Schristos 				return (0);
76*3b6c3722Schristos 		}
77*3b6c3722Schristos 	}
78*3b6c3722Schristos 	return (0);
79*3b6c3722Schristos }
80*3b6c3722Schristos #endif /* !HAVE_GETNAMEINFO */
81*3b6c3722Schristos 
82*3b6c3722Schristos #ifndef HAVE_GAI_STRERROR
83*3b6c3722Schristos #ifdef HAVE_CONST_GAI_STRERROR_PROTO
84*3b6c3722Schristos const char *
85*3b6c3722Schristos #else
86*3b6c3722Schristos char *
87*3b6c3722Schristos #endif
gai_strerror(int err)88*3b6c3722Schristos gai_strerror(int err)
89*3b6c3722Schristos {
90*3b6c3722Schristos 	switch (err) {
91*3b6c3722Schristos 	case EAI_NODATA:
92*3b6c3722Schristos 		return ("no address associated with name");
93*3b6c3722Schristos 	case EAI_MEMORY:
94*3b6c3722Schristos 		return ("memory allocation failure.");
95*3b6c3722Schristos 	case EAI_NONAME:
96*3b6c3722Schristos 		return ("nodename nor servname provided, or not known");
97*3b6c3722Schristos 	default:
98*3b6c3722Schristos 		return ("unknown/invalid error.");
99*3b6c3722Schristos 	}
100*3b6c3722Schristos }
101*3b6c3722Schristos #endif /* !HAVE_GAI_STRERROR */
102*3b6c3722Schristos 
103*3b6c3722Schristos #ifndef HAVE_FREEADDRINFO
104*3b6c3722Schristos void
freeaddrinfo(struct addrinfo * ai)105*3b6c3722Schristos freeaddrinfo(struct addrinfo *ai)
106*3b6c3722Schristos {
107*3b6c3722Schristos 	struct addrinfo *next;
108*3b6c3722Schristos 
109*3b6c3722Schristos 	for(; ai != NULL;) {
110*3b6c3722Schristos 		next = ai->ai_next;
111*3b6c3722Schristos 		free(ai);
112*3b6c3722Schristos 		ai = next;
113*3b6c3722Schristos 	}
114*3b6c3722Schristos }
115*3b6c3722Schristos #endif /* !HAVE_FREEADDRINFO */
116*3b6c3722Schristos 
117*3b6c3722Schristos #ifndef HAVE_GETADDRINFO
118*3b6c3722Schristos static struct
malloc_ai(int port,u_long addr,const struct addrinfo * hints)119*3b6c3722Schristos addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
120*3b6c3722Schristos {
121*3b6c3722Schristos 	struct addrinfo *ai;
122*3b6c3722Schristos 
123*3b6c3722Schristos 	ai = calloc(1, sizeof(*ai) + sizeof(struct sockaddr_in));
124*3b6c3722Schristos 	if (ai == NULL)
125*3b6c3722Schristos 		return (NULL);
126*3b6c3722Schristos 
127*3b6c3722Schristos 	ai->ai_addr = (struct sockaddr *)(ai + 1);
128*3b6c3722Schristos 	/* XXX -- ssh doesn't use sa_len */
129*3b6c3722Schristos 	ai->ai_addrlen = sizeof(struct sockaddr_in);
130*3b6c3722Schristos 	ai->ai_addr->sa_family = ai->ai_family = AF_INET;
131*3b6c3722Schristos 
132*3b6c3722Schristos 	((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
133*3b6c3722Schristos 	((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
134*3b6c3722Schristos 
135*3b6c3722Schristos 	/* XXX: the following is not generally correct, but does what we want */
136*3b6c3722Schristos 	if (hints->ai_socktype)
137*3b6c3722Schristos 		ai->ai_socktype = hints->ai_socktype;
138*3b6c3722Schristos 	else
139*3b6c3722Schristos 		ai->ai_socktype = SOCK_STREAM;
140*3b6c3722Schristos 
141*3b6c3722Schristos 	if (hints->ai_protocol)
142*3b6c3722Schristos 		ai->ai_protocol = hints->ai_protocol;
143*3b6c3722Schristos 
144*3b6c3722Schristos 	return (ai);
145*3b6c3722Schristos }
146*3b6c3722Schristos 
147*3b6c3722Schristos int
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)148*3b6c3722Schristos getaddrinfo(const char *hostname, const char *servname,
149*3b6c3722Schristos     const struct addrinfo *hints, struct addrinfo **res)
150*3b6c3722Schristos {
151*3b6c3722Schristos 	struct hostent *hp;
152*3b6c3722Schristos 	struct servent *sp;
153*3b6c3722Schristos 	struct in_addr in;
154*3b6c3722Schristos 	int i;
155*3b6c3722Schristos 	long int port;
156*3b6c3722Schristos 	u_long addr;
157*3b6c3722Schristos 
158*3b6c3722Schristos 	port = 0;
159*3b6c3722Schristos 	if (servname != NULL) {
160*3b6c3722Schristos 		char *cp;
161*3b6c3722Schristos 
162*3b6c3722Schristos 		port = strtol(servname, &cp, 10);
163*3b6c3722Schristos 		if (port > 0 && port <= 65535 && *cp == '\0')
164*3b6c3722Schristos 			port = htons(port);
165*3b6c3722Schristos 		else if ((sp = getservbyname(servname, NULL)) != NULL)
166*3b6c3722Schristos 			port = sp->s_port;
167*3b6c3722Schristos 		else
168*3b6c3722Schristos 			port = 0;
169*3b6c3722Schristos 	}
170*3b6c3722Schristos 
171*3b6c3722Schristos 	if (hints && hints->ai_flags & AI_PASSIVE) {
172*3b6c3722Schristos 		addr = htonl(0x00000000);
173*3b6c3722Schristos 		if (hostname && inet_aton(hostname, &in) != 0)
174*3b6c3722Schristos 			addr = in.s_addr;
175*3b6c3722Schristos 		*res = malloc_ai(port, addr, hints);
176*3b6c3722Schristos 		if (*res == NULL)
177*3b6c3722Schristos 			return (EAI_MEMORY);
178*3b6c3722Schristos 		return (0);
179*3b6c3722Schristos 	}
180*3b6c3722Schristos 
181*3b6c3722Schristos 	if (!hostname) {
182*3b6c3722Schristos 		*res = malloc_ai(port, htonl(0x7f000001), hints);
183*3b6c3722Schristos 		if (*res == NULL)
184*3b6c3722Schristos 			return (EAI_MEMORY);
185*3b6c3722Schristos 		return (0);
186*3b6c3722Schristos 	}
187*3b6c3722Schristos 
188*3b6c3722Schristos 	if (inet_aton(hostname, &in)) {
189*3b6c3722Schristos 		*res = malloc_ai(port, in.s_addr, hints);
190*3b6c3722Schristos 		if (*res == NULL)
191*3b6c3722Schristos 			return (EAI_MEMORY);
192*3b6c3722Schristos 		return (0);
193*3b6c3722Schristos 	}
194*3b6c3722Schristos 
195*3b6c3722Schristos 	/* Don't try DNS if AI_NUMERICHOST is set */
196*3b6c3722Schristos 	if (hints && hints->ai_flags & AI_NUMERICHOST)
197*3b6c3722Schristos 		return (EAI_NONAME);
198*3b6c3722Schristos 
199*3b6c3722Schristos 	hp = gethostbyname(hostname);
200*3b6c3722Schristos 	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
201*3b6c3722Schristos 		struct addrinfo *cur, *prev;
202*3b6c3722Schristos 
203*3b6c3722Schristos 		cur = prev = *res = NULL;
204*3b6c3722Schristos 		for (i = 0; hp->h_addr_list[i]; i++) {
205*3b6c3722Schristos 			struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
206*3b6c3722Schristos 
207*3b6c3722Schristos 			cur = malloc_ai(port, in->s_addr, hints);
208*3b6c3722Schristos 			if (cur == NULL) {
209*3b6c3722Schristos 				if (*res != NULL)
210*3b6c3722Schristos 					freeaddrinfo(*res);
211*3b6c3722Schristos 				return (EAI_MEMORY);
212*3b6c3722Schristos 			}
213*3b6c3722Schristos 			if (prev)
214*3b6c3722Schristos 				prev->ai_next = cur;
215*3b6c3722Schristos 			else
216*3b6c3722Schristos 				*res = cur;
217*3b6c3722Schristos 
218*3b6c3722Schristos 			prev = cur;
219*3b6c3722Schristos 		}
220*3b6c3722Schristos 		return (0);
221*3b6c3722Schristos 	}
222*3b6c3722Schristos 
223*3b6c3722Schristos 	return (EAI_NODATA);
224*3b6c3722Schristos }
225*3b6c3722Schristos #endif /* !HAVE_GETADDRINFO */
226