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