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