1124208Sdes/*
2124208Sdes * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
3124208Sdes * Copyright (C) 1999 WIDE Project.  All rights reserved.
4124208Sdes *
5124208Sdes * Redistribution and use in source and binary forms, with or without
6124208Sdes * modification, are permitted provided that the following conditions
7124208Sdes * are met:
8124208Sdes * 1. Redistributions of source code must retain the above copyright
9124208Sdes *    notice, this list of conditions and the following disclaimer.
10124208Sdes * 2. Redistributions in binary form must reproduce the above copyright
11124208Sdes *    notice, this list of conditions and the following disclaimer in the
12124208Sdes *    documentation and/or other materials provided with the distribution.
13124208Sdes * 3. Neither the name of the project nor the names of its contributors
14124208Sdes *    may be used to endorse or promote products derived from this software
15124208Sdes *    without specific prior written permission.
16124208Sdes *
17124208Sdes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18124208Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19124208Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20124208Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21124208Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22124208Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23124208Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24124208Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25124208Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26124208Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27124208Sdes * SUCH DAMAGE.
28124208Sdes */
29124208Sdes
30124208Sdes/*
31124208Sdes * Pseudo-implementation of RFC2553 name / address resolution functions
32124208Sdes *
33124208Sdes * But these functions are not implemented correctly. The minimum subset
34124208Sdes * is implemented for ssh use only. For example, this routine assumes
35124208Sdes * that ai_family is AF_INET. Don't use it for another purpose.
36124208Sdes */
37124208Sdes
38124208Sdes#include "includes.h"
39124208Sdes
40162852Sdes#include <stdlib.h>
41162852Sdes#include <string.h>
42124208Sdes
43162852Sdes#include <netinet/in.h>
44162852Sdes#include <arpa/inet.h>
45162852Sdes
46124208Sdes#ifndef HAVE_GETNAMEINFO
47124208Sdesint getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
48124208Sdes                size_t hostlen, char *serv, size_t servlen, int flags)
49124208Sdes{
50124208Sdes	struct sockaddr_in *sin = (struct sockaddr_in *)sa;
51124208Sdes	struct hostent *hp;
52124208Sdes	char tmpserv[16];
53124208Sdes
54181111Sdes	if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
55181111Sdes		return (EAI_FAMILY);
56124208Sdes	if (serv != NULL) {
57124208Sdes		snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
58124208Sdes		if (strlcpy(serv, tmpserv, servlen) >= servlen)
59124208Sdes			return (EAI_MEMORY);
60124208Sdes	}
61124208Sdes
62124208Sdes	if (host != NULL) {
63124208Sdes		if (flags & NI_NUMERICHOST) {
64124208Sdes			if (strlcpy(host, inet_ntoa(sin->sin_addr),
65124208Sdes			    hostlen) >= hostlen)
66124208Sdes				return (EAI_MEMORY);
67124208Sdes			else
68124208Sdes				return (0);
69124208Sdes		} else {
70124208Sdes			hp = gethostbyaddr((char *)&sin->sin_addr,
71124208Sdes			    sizeof(struct in_addr), AF_INET);
72124208Sdes			if (hp == NULL)
73124208Sdes				return (EAI_NODATA);
74124208Sdes
75124208Sdes			if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
76124208Sdes				return (EAI_MEMORY);
77124208Sdes			else
78124208Sdes				return (0);
79124208Sdes		}
80124208Sdes	}
81124208Sdes	return (0);
82124208Sdes}
83124208Sdes#endif /* !HAVE_GETNAMEINFO */
84124208Sdes
85124208Sdes#ifndef HAVE_GAI_STRERROR
86124208Sdes#ifdef HAVE_CONST_GAI_STRERROR_PROTO
87124208Sdesconst char *
88124208Sdes#else
89124208Sdeschar *
90124208Sdes#endif
91124208Sdesgai_strerror(int err)
92124208Sdes{
93124208Sdes	switch (err) {
94124208Sdes	case EAI_NODATA:
95124208Sdes		return ("no address associated with name");
96124208Sdes	case EAI_MEMORY:
97124208Sdes		return ("memory allocation failure.");
98124208Sdes	case EAI_NONAME:
99124208Sdes		return ("nodename nor servname provided, or not known");
100181111Sdes	case EAI_FAMILY:
101181111Sdes		return ("ai_family not supported");
102124208Sdes	default:
103124208Sdes		return ("unknown/invalid error.");
104124208Sdes	}
105124208Sdes}
106124208Sdes#endif /* !HAVE_GAI_STRERROR */
107124208Sdes
108124208Sdes#ifndef HAVE_FREEADDRINFO
109124208Sdesvoid
110124208Sdesfreeaddrinfo(struct addrinfo *ai)
111124208Sdes{
112124208Sdes	struct addrinfo *next;
113124208Sdes
114124208Sdes	for(; ai != NULL;) {
115124208Sdes		next = ai->ai_next;
116124208Sdes		free(ai);
117124208Sdes		ai = next;
118124208Sdes	}
119124208Sdes}
120124208Sdes#endif /* !HAVE_FREEADDRINFO */
121124208Sdes
122124208Sdes#ifndef HAVE_GETADDRINFO
123124208Sdesstatic struct
124124208Sdesaddrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
125124208Sdes{
126124208Sdes	struct addrinfo *ai;
127124208Sdes
128124208Sdes	ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
129124208Sdes	if (ai == NULL)
130124208Sdes		return (NULL);
131124208Sdes
132124208Sdes	memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
133124208Sdes
134124208Sdes	ai->ai_addr = (struct sockaddr *)(ai + 1);
135124208Sdes	/* XXX -- ssh doesn't use sa_len */
136124208Sdes	ai->ai_addrlen = sizeof(struct sockaddr_in);
137124208Sdes	ai->ai_addr->sa_family = ai->ai_family = AF_INET;
138124208Sdes
139124208Sdes	((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
140124208Sdes	((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
141124208Sdes
142124208Sdes	/* XXX: the following is not generally correct, but does what we want */
143124208Sdes	if (hints->ai_socktype)
144124208Sdes		ai->ai_socktype = hints->ai_socktype;
145124208Sdes	else
146124208Sdes		ai->ai_socktype = SOCK_STREAM;
147124208Sdes
148124208Sdes	if (hints->ai_protocol)
149124208Sdes		ai->ai_protocol = hints->ai_protocol;
150124208Sdes
151124208Sdes	return (ai);
152124208Sdes}
153124208Sdes
154124208Sdesint
155124208Sdesgetaddrinfo(const char *hostname, const char *servname,
156124208Sdes    const struct addrinfo *hints, struct addrinfo **res)
157124208Sdes{
158124208Sdes	struct hostent *hp;
159124208Sdes	struct servent *sp;
160124208Sdes	struct in_addr in;
161124208Sdes	int i;
162124208Sdes	long int port;
163124208Sdes	u_long addr;
164124208Sdes
165124208Sdes	port = 0;
166181111Sdes	if (hints && hints->ai_family != AF_UNSPEC &&
167181111Sdes	    hints->ai_family != AF_INET)
168181111Sdes		return (EAI_FAMILY);
169124208Sdes	if (servname != NULL) {
170124208Sdes		char *cp;
171124208Sdes
172124208Sdes		port = strtol(servname, &cp, 10);
173124208Sdes		if (port > 0 && port <= 65535 && *cp == '\0')
174124208Sdes			port = htons(port);
175124208Sdes		else if ((sp = getservbyname(servname, NULL)) != NULL)
176124208Sdes			port = sp->s_port;
177124208Sdes		else
178124208Sdes			port = 0;
179124208Sdes	}
180124208Sdes
181124208Sdes	if (hints && hints->ai_flags & AI_PASSIVE) {
182124208Sdes		addr = htonl(0x00000000);
183124208Sdes		if (hostname && inet_aton(hostname, &in) != 0)
184124208Sdes			addr = in.s_addr;
185124208Sdes		*res = malloc_ai(port, addr, hints);
186124208Sdes		if (*res == NULL)
187124208Sdes			return (EAI_MEMORY);
188124208Sdes		return (0);
189124208Sdes	}
190124208Sdes
191124208Sdes	if (!hostname) {
192124208Sdes		*res = malloc_ai(port, htonl(0x7f000001), hints);
193124208Sdes		if (*res == NULL)
194124208Sdes			return (EAI_MEMORY);
195124208Sdes		return (0);
196124208Sdes	}
197124208Sdes
198124208Sdes	if (inet_aton(hostname, &in)) {
199124208Sdes		*res = malloc_ai(port, in.s_addr, hints);
200124208Sdes		if (*res == NULL)
201124208Sdes			return (EAI_MEMORY);
202124208Sdes		return (0);
203124208Sdes	}
204124208Sdes
205124208Sdes	/* Don't try DNS if AI_NUMERICHOST is set */
206124208Sdes	if (hints && hints->ai_flags & AI_NUMERICHOST)
207124208Sdes		return (EAI_NONAME);
208124208Sdes
209124208Sdes	hp = gethostbyname(hostname);
210124208Sdes	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
211124208Sdes		struct addrinfo *cur, *prev;
212124208Sdes
213124208Sdes		cur = prev = *res = NULL;
214124208Sdes		for (i = 0; hp->h_addr_list[i]; i++) {
215124208Sdes			struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
216124208Sdes
217124208Sdes			cur = malloc_ai(port, in->s_addr, hints);
218124208Sdes			if (cur == NULL) {
219124208Sdes				if (*res != NULL)
220124208Sdes					freeaddrinfo(*res);
221124208Sdes				return (EAI_MEMORY);
222124208Sdes			}
223124208Sdes			if (prev)
224124208Sdes				prev->ai_next = cur;
225124208Sdes			else
226124208Sdes				*res = cur;
227124208Sdes
228124208Sdes			prev = cur;
229124208Sdes		}
230124208Sdes		return (0);
231124208Sdes	}
232124208Sdes
233124208Sdes	return (EAI_NODATA);
234124208Sdes}
235124208Sdes#endif /* !HAVE_GETADDRINFO */
236