fake-rfc2553.c revision 238106
1238106Sdes/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */ 2238106Sdes/* 3238106Sdes * Copyright (C) 2000-2003 Damien Miller. All rights reserved. 4238106Sdes * Copyright (C) 1999 WIDE Project. All rights reserved. 5238106Sdes * 6238106Sdes * Redistribution and use in source and binary forms, with or without 7238106Sdes * modification, are permitted provided that the following conditions 8238106Sdes * are met: 9238106Sdes * 1. Redistributions of source code must retain the above copyright 10238106Sdes * notice, this list of conditions and the following disclaimer. 11238106Sdes * 2. Redistributions in binary form must reproduce the above copyright 12238106Sdes * notice, this list of conditions and the following disclaimer in the 13238106Sdes * documentation and/or other materials provided with the distribution. 14238106Sdes * 3. Neither the name of the project nor the names of its contributors 15238106Sdes * may be used to endorse or promote products derived from this software 16238106Sdes * without specific prior written permission. 17238106Sdes * 18238106Sdes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 19238106Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20238106Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21238106Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 22238106Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23238106Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24238106Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25238106Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26238106Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27238106Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28238106Sdes * SUCH DAMAGE. 29238106Sdes */ 30238106Sdes 31238106Sdes/* 32238106Sdes * Pseudo-implementation of RFC2553 name / address resolution functions 33238106Sdes * 34238106Sdes * But these functions are not implemented correctly. The minimum subset 35238106Sdes * is implemented for ssh use only. For example, this routine assumes 36238106Sdes * that ai_family is AF_INET. Don't use it for another purpose. 37238106Sdes */ 38238106Sdes 39238106Sdes#include <unistd.h> 40238106Sdes#include <string.h> 41238106Sdes#include <stdio.h> 42238106Sdes#include <stdlib.h> 43238106Sdes#include "compat/fake-rfc2553.h" 44238106Sdes 45238106Sdes#ifndef HAVE_GETNAMEINFO 46238106Sdesint getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host, 47238106Sdes size_t hostlen, char *serv, size_t servlen, int flags) 48238106Sdes{ 49238106Sdes struct sockaddr_in *sin = (struct sockaddr_in *)sa; 50238106Sdes struct hostent *hp; 51238106Sdes char tmpserv[16]; 52238106Sdes 53238106Sdes if (serv != NULL) { 54238106Sdes snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port)); 55238106Sdes if (strlcpy(serv, tmpserv, servlen) >= servlen) 56238106Sdes return (EAI_MEMORY); 57238106Sdes } 58238106Sdes 59238106Sdes if (host != NULL) { 60238106Sdes if (flags & NI_NUMERICHOST) { 61238106Sdes if (strlcpy(host, inet_ntoa(sin->sin_addr), 62238106Sdes hostlen) >= hostlen) 63238106Sdes return (EAI_MEMORY); 64238106Sdes else 65238106Sdes return (0); 66238106Sdes } else { 67238106Sdes hp = gethostbyaddr((char *)&sin->sin_addr, 68238106Sdes sizeof(struct in_addr), AF_INET); 69238106Sdes if (hp == NULL) 70238106Sdes return (EAI_NODATA); 71238106Sdes 72238106Sdes if (strlcpy(host, hp->h_name, hostlen) >= hostlen) 73238106Sdes return (EAI_MEMORY); 74238106Sdes else 75238106Sdes return (0); 76238106Sdes } 77238106Sdes } 78238106Sdes return (0); 79238106Sdes} 80238106Sdes#endif /* !HAVE_GETNAMEINFO */ 81238106Sdes 82238106Sdes#ifndef HAVE_GAI_STRERROR 83238106Sdes#ifdef HAVE_CONST_GAI_STRERROR_PROTO 84238106Sdesconst char * 85238106Sdes#else 86238106Sdeschar * 87238106Sdes#endif 88238106Sdesgai_strerror(int err) 89238106Sdes{ 90238106Sdes switch (err) { 91238106Sdes case EAI_NODATA: 92238106Sdes return ("no address associated with name"); 93238106Sdes case EAI_MEMORY: 94238106Sdes return ("memory allocation failure."); 95238106Sdes case EAI_NONAME: 96238106Sdes return ("nodename nor servname provided, or not known"); 97238106Sdes default: 98238106Sdes return ("unknown/invalid error."); 99238106Sdes } 100238106Sdes} 101238106Sdes#endif /* !HAVE_GAI_STRERROR */ 102238106Sdes 103238106Sdes#ifndef HAVE_FREEADDRINFO 104238106Sdesvoid 105238106Sdesfreeaddrinfo(struct addrinfo *ai) 106238106Sdes{ 107238106Sdes struct addrinfo *next; 108238106Sdes 109238106Sdes for(; ai != NULL;) { 110238106Sdes next = ai->ai_next; 111238106Sdes free(ai); 112238106Sdes ai = next; 113238106Sdes } 114238106Sdes} 115238106Sdes#endif /* !HAVE_FREEADDRINFO */ 116238106Sdes 117238106Sdes#ifndef HAVE_GETADDRINFO 118238106Sdesstatic struct 119238106Sdesaddrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints) 120238106Sdes{ 121238106Sdes struct addrinfo *ai; 122238106Sdes 123238106Sdes ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in)); 124238106Sdes if (ai == NULL) 125238106Sdes return (NULL); 126238106Sdes 127238106Sdes memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in)); 128238106Sdes 129238106Sdes ai->ai_addr = (struct sockaddr *)(ai + 1); 130238106Sdes /* XXX -- ssh doesn't use sa_len */ 131238106Sdes ai->ai_addrlen = sizeof(struct sockaddr_in); 132238106Sdes ai->ai_addr->sa_family = ai->ai_family = AF_INET; 133238106Sdes 134238106Sdes ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; 135238106Sdes ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; 136238106Sdes 137238106Sdes /* XXX: the following is not generally correct, but does what we want */ 138238106Sdes if (hints->ai_socktype) 139238106Sdes ai->ai_socktype = hints->ai_socktype; 140238106Sdes else 141238106Sdes ai->ai_socktype = SOCK_STREAM; 142238106Sdes 143238106Sdes if (hints->ai_protocol) 144238106Sdes ai->ai_protocol = hints->ai_protocol; 145238106Sdes 146238106Sdes return (ai); 147238106Sdes} 148238106Sdes 149238106Sdesint 150238106Sdesgetaddrinfo(const char *hostname, const char *servname, 151238106Sdes const struct addrinfo *hints, struct addrinfo **res) 152238106Sdes{ 153238106Sdes struct hostent *hp; 154238106Sdes struct servent *sp; 155238106Sdes struct in_addr in; 156238106Sdes int i; 157238106Sdes long int port; 158238106Sdes u_long addr; 159238106Sdes 160238106Sdes port = 0; 161238106Sdes if (servname != NULL) { 162238106Sdes char *cp; 163238106Sdes 164238106Sdes port = strtol(servname, &cp, 10); 165238106Sdes if (port > 0 && port <= 65535 && *cp == '\0') 166238106Sdes port = htons(port); 167238106Sdes else if ((sp = getservbyname(servname, NULL)) != NULL) 168238106Sdes port = sp->s_port; 169238106Sdes else 170238106Sdes port = 0; 171238106Sdes } 172238106Sdes 173238106Sdes if (hints && hints->ai_flags & AI_PASSIVE) { 174238106Sdes addr = htonl(0x00000000); 175238106Sdes if (hostname && inet_aton(hostname, &in) != 0) 176238106Sdes addr = in.s_addr; 177238106Sdes *res = malloc_ai(port, addr, hints); 178238106Sdes if (*res == NULL) 179238106Sdes return (EAI_MEMORY); 180238106Sdes return (0); 181238106Sdes } 182238106Sdes 183238106Sdes if (!hostname) { 184238106Sdes *res = malloc_ai(port, htonl(0x7f000001), hints); 185238106Sdes if (*res == NULL) 186238106Sdes return (EAI_MEMORY); 187238106Sdes return (0); 188238106Sdes } 189238106Sdes 190238106Sdes if (inet_aton(hostname, &in)) { 191238106Sdes *res = malloc_ai(port, in.s_addr, hints); 192238106Sdes if (*res == NULL) 193238106Sdes return (EAI_MEMORY); 194238106Sdes return (0); 195238106Sdes } 196238106Sdes 197238106Sdes /* Don't try DNS if AI_NUMERICHOST is set */ 198238106Sdes if (hints && hints->ai_flags & AI_NUMERICHOST) 199238106Sdes return (EAI_NONAME); 200238106Sdes 201238106Sdes hp = gethostbyname(hostname); 202238106Sdes if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { 203238106Sdes struct addrinfo *cur, *prev; 204238106Sdes 205238106Sdes cur = prev = *res = NULL; 206238106Sdes for (i = 0; hp->h_addr_list[i]; i++) { 207238106Sdes struct in_addr *in = (struct in_addr *)hp->h_addr_list[i]; 208238106Sdes 209238106Sdes cur = malloc_ai(port, in->s_addr, hints); 210238106Sdes if (cur == NULL) { 211238106Sdes if (*res != NULL) 212238106Sdes freeaddrinfo(*res); 213238106Sdes return (EAI_MEMORY); 214238106Sdes } 215238106Sdes if (prev) 216238106Sdes prev->ai_next = cur; 217238106Sdes else 218238106Sdes *res = cur; 219238106Sdes 220238106Sdes prev = cur; 221238106Sdes } 222238106Sdes return (0); 223238106Sdes } 224238106Sdes 225238106Sdes return (EAI_NODATA); 226238106Sdes} 227238106Sdes#endif /* !HAVE_GETADDRINFO */ 228