getnameinfo.c revision 199221
1236769Sobrien/* $KAME: getnameinfo.c,v 1.61 2002/06/27 09:25:47 itojun Exp $ */ 2236769Sobrien 3236769Sobrien/* 4236769Sobrien * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5236769Sobrien * Copyright (c) 2000 Ben Harris. 6236769Sobrien * All rights reserved. 7236769Sobrien * 8236769Sobrien * Redistribution and use in source and binary forms, with or without 9236769Sobrien * modification, are permitted provided that the following conditions 10236769Sobrien * are met: 11236769Sobrien * 1. Redistributions of source code must retain the above copyright 12236769Sobrien * notice, this list of conditions and the following disclaimer. 13236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer in the 15236769Sobrien * documentation and/or other materials provided with the distribution. 16236769Sobrien * 3. Neither the name of the project nor the names of its contributors 17236769Sobrien * may be used to endorse or promote products derived from this software 18236769Sobrien * without specific prior written permission. 19236769Sobrien * 20236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33/* 34 * Issues to be discussed: 35 * - Thread safe-ness must be checked 36 * - RFC2553 says that we should raise error on short buffer. X/Open says 37 * we need to truncate the result. We obey RFC2553 (and X/Open should be 38 * modified). ipngwg rough consensus seems to follow RFC2553. 39 * - What is "local" in NI_FQDN? 40 * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. 41 * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if 42 * sin6_scope_id is filled - standardization status? 43 * XXX breaks backward compat for code that expects no scopeid. 44 * beware on merge. 45 */ 46 47#include <sys/cdefs.h> 48__FBSDID("$FreeBSD: head/lib/libc/net/getnameinfo.c 199221 2009-11-12 11:54:12Z ume $"); 49 50#include <sys/types.h> 51#include <sys/socket.h> 52#include <net/if.h> 53#include <net/if_dl.h> 54#include <net/if_types.h> 55#include <net/firewire.h> 56#include <netinet/in.h> 57#include <arpa/inet.h> 58#include <arpa/nameser.h> 59#include <netdb.h> 60#include <resolv.h> 61#include <string.h> 62#include <stddef.h> 63#include <errno.h> 64 65static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *, 66 size_t, char *, size_t, int); 67#ifdef INET6 68static int ip6_parsenumeric(const struct sockaddr *, const char *, char *, 69 size_t, int); 70static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int); 71#endif 72static int getnameinfo_link(const struct sockaddr *, socklen_t, char *, 73 size_t, char *, size_t, int); 74static int hexname(const u_int8_t *, size_t, char *, size_t); 75 76int 77getnameinfo(const struct sockaddr *sa, socklen_t salen, 78 char *host, size_t hostlen, char *serv, size_t servlen, 79 int flags) 80{ 81 82 switch (sa->sa_family) { 83 case AF_INET: 84#ifdef INET6 85 case AF_INET6: 86#endif 87 return getnameinfo_inet(sa, salen, host, hostlen, serv, 88 servlen, flags); 89 case AF_LINK: 90 return getnameinfo_link(sa, salen, host, hostlen, serv, 91 servlen, flags); 92 default: 93 return EAI_FAMILY; 94 } 95} 96 97static const struct afd { 98 int a_af; 99 size_t a_addrlen; 100 socklen_t a_socklen; 101 int a_off; 102} afdl [] = { 103#ifdef INET6 104 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), 105 offsetof(struct sockaddr_in6, sin6_addr)}, 106#endif 107 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), 108 offsetof(struct sockaddr_in, sin_addr)}, 109 {0, 0, 0}, 110}; 111 112struct sockinet { 113 u_char si_len; 114 u_char si_family; 115 u_short si_port; 116}; 117 118static int 119getnameinfo_inet(const struct sockaddr *sa, socklen_t salen, 120 char *host, size_t hostlen, char *serv, size_t servlen, 121 int flags) 122{ 123 const struct afd *afd; 124 struct servent *sp; 125 struct hostent *hp; 126 u_short port; 127 int family, i; 128 const char *addr; 129 u_int32_t v4a; 130 int h_error; 131 char numserv[512]; 132 char numaddr[512]; 133 134 if (sa == NULL) 135 return EAI_FAIL; 136 137 family = sa->sa_family; 138 for (i = 0; afdl[i].a_af; i++) 139 if (afdl[i].a_af == family) { 140 afd = &afdl[i]; 141 goto found; 142 } 143 return EAI_FAMILY; 144 145 found: 146 if (salen != afd->a_socklen) 147 return EAI_FAIL; 148 149 /* network byte order */ 150 port = ((const struct sockinet *)sa)->si_port; 151 addr = (const char *)sa + afd->a_off; 152 153 if (serv == NULL || servlen == 0) { 154 /* 155 * do nothing in this case. 156 * in case you are wondering if "&&" is more correct than 157 * "||" here: rfc2553bis-03 says that serv == NULL OR 158 * servlen == 0 means that the caller does not want the result. 159 */ 160 } else { 161 if (flags & NI_NUMERICSERV) 162 sp = NULL; 163 else { 164 sp = getservbyport(port, 165 (flags & NI_DGRAM) ? "udp" : "tcp"); 166 } 167 if (sp) { 168 if (strlen(sp->s_name) + 1 > servlen) 169 return EAI_MEMORY; 170 strlcpy(serv, sp->s_name, servlen); 171 } else { 172 snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); 173 if (strlen(numserv) + 1 > servlen) 174 return EAI_MEMORY; 175 strlcpy(serv, numserv, servlen); 176 } 177 } 178 179 switch (sa->sa_family) { 180 case AF_INET: 181 v4a = (u_int32_t) 182 ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr); 183 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) 184 flags |= NI_NUMERICHOST; 185 v4a >>= IN_CLASSA_NSHIFT; 186 if (v4a == 0) 187 flags |= NI_NUMERICHOST; 188 break; 189#ifdef INET6 190 case AF_INET6: 191 { 192 const struct sockaddr_in6 *sin6; 193 sin6 = (const struct sockaddr_in6 *)sa; 194 switch (sin6->sin6_addr.s6_addr[0]) { 195 case 0x00: 196 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 197 ; 198 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) 199 ; 200 else 201 flags |= NI_NUMERICHOST; 202 break; 203 default: 204 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 205 flags |= NI_NUMERICHOST; 206 } 207 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 208 flags |= NI_NUMERICHOST; 209 break; 210 } 211 } 212 break; 213#endif 214 } 215 if (host == NULL || hostlen == 0) { 216 /* 217 * do nothing in this case. 218 * in case you are wondering if "&&" is more correct than 219 * "||" here: rfc2553bis-03 says that host == NULL or 220 * hostlen == 0 means that the caller does not want the result. 221 */ 222 } else if (flags & NI_NUMERICHOST) { 223 size_t numaddrlen; 224 225 /* NUMERICHOST and NAMEREQD conflicts with each other */ 226 if (flags & NI_NAMEREQD) 227 return EAI_NONAME; 228 229 switch(afd->a_af) { 230#ifdef INET6 231 case AF_INET6: 232 { 233 int error; 234 235 if ((error = ip6_parsenumeric(sa, addr, host, 236 hostlen, flags)) != 0) 237 return(error); 238 break; 239 } 240#endif 241 default: 242 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) 243 == NULL) 244 return EAI_SYSTEM; 245 numaddrlen = strlen(numaddr); 246 if (numaddrlen + 1 > hostlen) /* don't forget terminator */ 247 return EAI_MEMORY; 248 strlcpy(host, numaddr, hostlen); 249 break; 250 } 251 } else { 252 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); 253 254 if (hp) { 255#if 0 256 /* 257 * commented out, since "for local host" is not 258 * implemented here - see RFC2553 p30 259 */ 260 if (flags & NI_NOFQDN) { 261 char *p; 262 p = strchr(hp->h_name, '.'); 263 if (p) 264 *p = '\0'; 265 } 266#endif 267 if (strlen(hp->h_name) + 1 > hostlen) { 268 freehostent(hp); 269 return EAI_MEMORY; 270 } 271 strlcpy(host, hp->h_name, hostlen); 272 freehostent(hp); 273 } else { 274 if (flags & NI_NAMEREQD) 275 return EAI_NONAME; 276 switch(afd->a_af) { 277#ifdef INET6 278 case AF_INET6: 279 { 280 int error; 281 282 if ((error = ip6_parsenumeric(sa, addr, host, 283 hostlen, 284 flags)) != 0) 285 return(error); 286 break; 287 } 288#endif 289 default: 290 if (inet_ntop(afd->a_af, addr, host, 291 hostlen) == NULL) 292 return EAI_SYSTEM; 293 break; 294 } 295 } 296 } 297 return(0); 298} 299 300#ifdef INET6 301static int 302ip6_parsenumeric(const struct sockaddr *sa, const char *addr, 303 char *host, size_t hostlen, int flags) 304{ 305 size_t numaddrlen; 306 char numaddr[512]; 307 308 if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL) 309 return EAI_SYSTEM; 310 311 numaddrlen = strlen(numaddr); 312 if (numaddrlen + 1 > hostlen) /* don't forget terminator */ 313 return EAI_OVERFLOW; 314 strlcpy(host, numaddr, hostlen); 315 316 if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { 317 char zonebuf[MAXHOSTNAMELEN]; 318 int zonelen; 319 320 zonelen = ip6_sa2str( 321 (const struct sockaddr_in6 *)(const void *)sa, 322 zonebuf, sizeof(zonebuf), flags); 323 if (zonelen < 0) 324 return EAI_OVERFLOW; 325 if (zonelen + 1 + numaddrlen + 1 > hostlen) 326 return EAI_OVERFLOW; 327 328 /* construct <numeric-addr><delim><zoneid> */ 329 memcpy(host + numaddrlen + 1, zonebuf, 330 (size_t)zonelen); 331 host[numaddrlen] = SCOPE_DELIMITER; 332 host[numaddrlen + 1 + zonelen] = '\0'; 333 } 334 335 return 0; 336} 337 338/* ARGSUSED */ 339static int 340ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags) 341{ 342 unsigned int ifindex; 343 const struct in6_addr *a6; 344 int n; 345 346 ifindex = (unsigned int)sa6->sin6_scope_id; 347 a6 = &sa6->sin6_addr; 348 349#ifdef NI_NUMERICSCOPE 350 if ((flags & NI_NUMERICSCOPE) != 0) { 351 n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); 352 if (n < 0 || n >= bufsiz) 353 return -1; 354 else 355 return n; 356 } 357#endif 358 359 /* if_indextoname() does not take buffer size. not a good api... */ 360 if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || 361 IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) { 362 char *p = if_indextoname(ifindex, buf); 363 if (p) { 364 return(strlen(p)); 365 } 366 } 367 368 /* last resort */ 369 n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); 370 if (n < 0 || (size_t)n >= bufsiz) 371 return -1; 372 else 373 return n; 374} 375#endif /* INET6 */ 376 377/* 378 * getnameinfo_link(): 379 * Format a link-layer address into a printable format, paying attention to 380 * the interface type. 381 */ 382/* ARGSUSED */ 383static int 384getnameinfo_link(const struct sockaddr *sa, socklen_t salen, 385 char *host, size_t hostlen, char *serv, size_t servlen, int flags) 386{ 387 const struct sockaddr_dl *sdl = 388 (const struct sockaddr_dl *)(const void *)sa; 389 const struct fw_hwaddr *iha; 390 int n; 391 392 if (serv != NULL && servlen > 0) 393 *serv = '\0'; 394 395 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) { 396 n = snprintf(host, hostlen, "link#%d", sdl->sdl_index); 397 if (n > hostlen) { 398 *host = '\0'; 399 return EAI_MEMORY; 400 } 401 return 0; 402 } 403 404 switch (sdl->sdl_type) { 405 case IFT_IEEE1394: 406 if (sdl->sdl_alen < sizeof(iha->sender_unique_ID_hi) + 407 sizeof(iha->sender_unique_ID_lo)) 408 return EAI_FAMILY; 409 iha = (const struct fw_hwaddr *)(const void *)LLADDR(sdl); 410 return hexname((const u_int8_t *)&iha->sender_unique_ID_hi, 411 sizeof(iha->sender_unique_ID_hi) + 412 sizeof(iha->sender_unique_ID_lo), 413 host, hostlen); 414 /* 415 * The following have zero-length addresses. 416 * IFT_ATM (net/if_atmsubr.c) 417 * IFT_FAITH (net/if_faith.c) 418 * IFT_GIF (net/if_gif.c) 419 * IFT_LOOP (net/if_loop.c) 420 * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c) 421 * IFT_SLIP (net/if_sl.c, net/if_strip.c) 422 * IFT_STF (net/if_stf.c) 423 * IFT_L2VLAN (net/if_vlan.c) 424 * IFT_BRIDGE (net/if_bridge.h> 425 */ 426 /* 427 * The following use IPv4 addresses as link-layer addresses: 428 * IFT_OTHER (net/if_gre.c) 429 * IFT_OTHER (netinet/ip_ipip.c) 430 */ 431 /* default below is believed correct for all these. */ 432 case IFT_ARCNET: 433 case IFT_ETHER: 434 case IFT_FDDI: 435 case IFT_HIPPI: 436 case IFT_ISO88025: 437 default: 438 return hexname((u_int8_t *)LLADDR(sdl), (size_t)sdl->sdl_alen, 439 host, hostlen); 440 } 441} 442 443static int 444hexname(cp, len, host, hostlen) 445 const u_int8_t *cp; 446 char *host; 447 size_t len, hostlen; 448{ 449 int i, n; 450 char *outp = host; 451 452 *outp = '\0'; 453 for (i = 0; i < len; i++) { 454 n = snprintf(outp, hostlen, "%s%02x", 455 i ? ":" : "", cp[i]); 456 if (n < 0 || n >= hostlen) { 457 *host = '\0'; 458 return EAI_MEMORY; 459 } 460 outp += n; 461 hostlen -= n; 462 } 463 return 0; 464} 465