1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Issues to be discussed: 8 * - Thread safe-ness must be checked 9 */ 10 11 /* 12 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 13 * All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 3. All advertising materials mentioning features or use of this software 24 * must display the following acknowledgement: 25 * This product includes software developed by WIDE Project and 26 * its contributors. 27 * 4. Neither the name of the project nor the names of its contributors 28 * may be used to endorse or promote products derived from this software 29 * without specific prior written permission. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 * SUCH DAMAGE. 42 */ 43 44 #pragma ident "%Z%%M% %I% %E% SMI" 45 46 #include <port_before.h> 47 48 #include <sys/types.h> 49 #include <sys/socket.h> 50 51 #include <netinet/in.h> 52 #include <arpa/nameser.h> 53 #include <arpa/inet.h> 54 #include <net/if.h> 55 56 #include <netdb.h> 57 #include <resolv.h> 58 #include <string.h> 59 #include <stddef.h> 60 61 #include <port_after.h> 62 63 /* 64 * Note that a_off will be dynamically adjusted so that to be consistent 65 * with the definition of sockaddr_in{,6}. 66 * The value presented below is just a guess. 67 */ 68 static struct afd { 69 int a_af; 70 int a_addrlen; 71 size_t a_socklen; 72 int a_off; 73 } afdl [] = { 74 /* first entry is linked last... */ 75 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), 76 offsetof(struct sockaddr_in, sin_addr)}, 77 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), 78 offsetof(struct sockaddr_in6, sin6_addr)}, 79 {0, 0, 0, 0}, 80 }; 81 82 struct sockinet { 83 #ifdef HAVE_SA_LEN 84 u_char si_len; 85 #endif 86 u_char si_family; 87 u_short si_port; 88 }; 89 90 static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, 91 size_t, int)); 92 #ifdef HAVE_SIN6_SCOPE_ID 93 static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int)); 94 #endif 95 96 int 97 getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) 98 const struct sockaddr *sa; 99 #ifdef ORIGINAL_ISC_CODE 100 size_t salen; 101 #else 102 socklen_t salen; 103 #endif 104 char *host; 105 #ifdef ORIGINAL_ISC_CODE 106 size_t hostlen; 107 #else 108 socklen_t hostlen; 109 #endif 110 char *serv; 111 #ifdef ORIGINAL_ISC_CODE 112 size_t servlen; 113 #else 114 socklen_t servlen; 115 #endif 116 int flags; 117 { 118 struct afd *afd; 119 struct servent *sp; 120 struct hostent *hp; 121 u_short port; 122 #ifdef HAVE_SA_LEN 123 size_t len; 124 #endif 125 int family, i; 126 const char *addr; 127 char *p; 128 char numserv[512]; 129 char numaddr[512]; 130 const struct sockaddr_in6 *sin6; 131 132 if (sa == NULL) 133 return EAI_FAIL; 134 135 #ifdef HAVE_SA_LEN 136 len = sa->sa_len; 137 if (len != salen) return EAI_FAIL; 138 #endif 139 140 family = sa->sa_family; 141 for (i = 0; afdl[i].a_af; i++) 142 if (afdl[i].a_af == family) { 143 afd = &afdl[i]; 144 goto found; 145 } 146 return EAI_FAMILY; 147 148 found: 149 if (salen != afd->a_socklen) return EAI_FAIL; 150 151 port = ((const struct sockinet *)sa)->si_port; /* network byte order */ 152 addr = (const char *)sa + afd->a_off; 153 154 if (serv == NULL || servlen == 0) { 155 /* 156 * rfc2553bis says that serv == NULL or servlen == 0 means that 157 * the caller does not want the result. 158 */ 159 } else if (flags & NI_NUMERICSERV) { 160 sprintf(numserv, "%d", ntohs(port)); 161 if (strlen(numserv) > servlen) 162 return EAI_MEMORY; 163 strcpy(serv, numserv); 164 } else { 165 sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); 166 if (sp) { 167 if (strlen(sp->s_name) + 1 > servlen) 168 return EAI_MEMORY; 169 strcpy(serv, sp->s_name); 170 } else 171 return EAI_NONAME; 172 } 173 174 switch (sa->sa_family) { 175 case AF_INET: 176 if (ntohl(*(const u_long *)addr) >> IN_CLASSA_NSHIFT == 0) 177 flags |= NI_NUMERICHOST; 178 break; 179 case AF_INET6: 180 sin6 = (const struct sockaddr_in6 *)sa; 181 switch (sin6->sin6_addr.s6_addr[0]) { 182 case 0x00: 183 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 184 ; 185 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) 186 ; 187 else 188 flags |= NI_NUMERICHOST; 189 break; 190 default: 191 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 192 flags |= NI_NUMERICHOST; 193 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 194 flags |= NI_NUMERICHOST; 195 break; 196 } 197 break; 198 } 199 if (host == NULL || hostlen == 0) { 200 /* 201 * rfc2553bis says that host == NULL or hostlen == 0 means that 202 * the caller does not want the result. 203 */ 204 } else if (flags & NI_NUMERICHOST) { 205 goto numeric; 206 } else { 207 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); 208 209 if (hp) { 210 if (flags & NI_NOFQDN) { 211 p = strchr(hp->h_name, '.'); 212 if (p) *p = '\0'; 213 } 214 if (strlen(hp->h_name) + 1 > hostlen) 215 return EAI_MEMORY; 216 strcpy(host, hp->h_name); 217 } else { 218 if (flags & NI_NAMEREQD) 219 return EAI_NONAME; 220 numeric: 221 switch(afd->a_af) { 222 case AF_INET6: 223 { 224 int error; 225 226 if ((error = ip6_parsenumeric(sa, addr, host, 227 hostlen, 228 flags)) != 0) 229 return(error); 230 break; 231 } 232 233 default: 234 if (inet_ntop(afd->a_af, addr, numaddr, 235 sizeof(numaddr)) == NULL) 236 return EAI_NONAME; 237 if (strlen(numaddr) + 1 > hostlen) 238 return EAI_MEMORY; 239 strcpy(host, numaddr); 240 } 241 } 242 } 243 return(0); 244 } 245 246 static int 247 ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host, 248 size_t hostlen, int flags) 249 { 250 size_t numaddrlen; 251 char numaddr[512]; 252 253 #ifndef HAVE_SIN6_SCOPE_ID 254 UNUSED(sa); 255 UNUSED(flags); 256 #endif 257 258 if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) 259 == NULL) 260 return EAI_SYSTEM; 261 262 numaddrlen = strlen(numaddr); 263 if (numaddrlen + 1 > hostlen) /* don't forget terminator */ 264 return EAI_MEMORY; 265 strcpy(host, numaddr); 266 267 #ifdef HAVE_SIN6_SCOPE_ID 268 if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { 269 char scopebuf[MAXHOSTNAMELEN]; /* XXX */ 270 int scopelen; 271 272 /* ip6_sa2str never fails */ 273 scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa, 274 scopebuf, sizeof(scopebuf), flags); 275 276 if (scopelen + 1 + numaddrlen + 1 > hostlen) 277 return EAI_MEMORY; 278 279 /* construct <numeric-addr><delim><scopeid> */ 280 memcpy(host + numaddrlen + 1, scopebuf, 281 scopelen); 282 host[numaddrlen] = SCOPE_DELIMITER; 283 host[numaddrlen + 1 + scopelen] = '\0'; 284 } 285 #endif 286 287 return 0; 288 } 289 290 #ifdef HAVE_SIN6_SCOPE_ID 291 /* ARGSUSED */ 292 static int 293 ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, 294 size_t bufsiz, int flags) 295 { 296 #ifdef USE_IFNAMELINKID 297 unsigned int ifindex = (unsigned int)sa6->sin6_scope_id; 298 const struct in6_addr *a6 = &sa6->sin6_addr; 299 #endif 300 char tmp[64]; 301 302 #ifdef NI_NUMERICSCOPE 303 if (flags & NI_NUMERICSCOPE) { 304 sprintf(tmp, "%u", sa6->sin6_scope_id); 305 if (bufsiz != 0) { 306 strncpy(buf, tmp, bufsiz - 1); 307 buf[bufsiz - 1] = '\0'; 308 } 309 return(strlen(tmp)); 310 } 311 #endif 312 313 #ifdef USE_IFNAMELINKID 314 /* 315 * For a link-local address, convert the index to an interface 316 * name, assuming a one-to-one mapping between links and interfaces. 317 * Note, however, that this assumption is stronger than the 318 * specification of the scoped address architecture; the 319 * specficication says that more than one interfaces can belong to 320 * a single link. 321 */ 322 323 /* if_indextoname() does not take buffer size. not a good api... */ 324 if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && 325 bufsiz >= IF_NAMESIZE) { 326 char *p = if_indextoname(ifindex, buf); 327 if (p) { 328 return(strlen(p)); 329 } 330 } 331 #endif 332 333 /* last resort */ 334 sprintf(tmp, "%u", sa6->sin6_scope_id); 335 if (bufsiz != 0) { 336 strncpy(buf, tmp, bufsiz - 1); 337 buf[bufsiz - 1] = '\0'; 338 } 339 return(strlen(tmp)); 340 } 341 #endif 342