1 1.60 christos /* $NetBSD: getnameinfo.c,v 1.60 2023/09/08 18:17:41 christos Exp $ */ 2 1.22 itojun /* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */ 3 1.2 itojun 4 1.1 itojun /* 5 1.32 bjh21 * Copyright (c) 2000 Ben Harris. 6 1.1 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 1.1 itojun * All rights reserved. 8 1.18 itojun * 9 1.1 itojun * Redistribution and use in source and binary forms, with or without 10 1.1 itojun * modification, are permitted provided that the following conditions 11 1.1 itojun * are met: 12 1.1 itojun * 1. Redistributions of source code must retain the above copyright 13 1.1 itojun * notice, this list of conditions and the following disclaimer. 14 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 itojun * notice, this list of conditions and the following disclaimer in the 16 1.1 itojun * documentation and/or other materials provided with the distribution. 17 1.1 itojun * 3. Neither the name of the project nor the names of its contributors 18 1.1 itojun * may be used to endorse or promote products derived from this software 19 1.1 itojun * without specific prior written permission. 20 1.18 itojun * 21 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 itojun * SUCH DAMAGE. 32 1.1 itojun */ 33 1.1 itojun 34 1.1 itojun /* 35 1.1 itojun * Issues to be discussed: 36 1.1 itojun * - Thread safe-ness must be checked 37 1.5 itojun * - RFC2553 says that we should raise error on short buffer. X/Open says 38 1.5 itojun * we need to truncate the result. We obey RFC2553 (and X/Open should be 39 1.21 itojun * modified). ipngwg rough consensus seems to follow RFC2553. 40 1.16 itojun * - What is "local" in NI_FQDN? 41 1.16 itojun * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. 42 1.34 itojun * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if 43 1.34 itojun * sin6_scope_id is filled - standardization status? 44 1.34 itojun * XXX breaks backward compat for code that expects no scopeid. 45 1.34 itojun * beware on merge. 46 1.1 itojun */ 47 1.15 itojun 48 1.15 itojun #include <sys/cdefs.h> 49 1.15 itojun #if defined(LIBC_SCCS) && !defined(lint) 50 1.60 christos __RCSID("$NetBSD: getnameinfo.c,v 1.60 2023/09/08 18:17:41 christos Exp $"); 51 1.15 itojun #endif /* LIBC_SCCS and not lint */ 52 1.1 itojun 53 1.55 ozaki #ifndef RUMP_ACTION 54 1.14 itojun #include "namespace.h" 55 1.55 ozaki #endif 56 1.1 itojun #include <sys/types.h> 57 1.1 itojun #include <sys/socket.h> 58 1.53 christos #include <sys/un.h> 59 1.5 itojun #include <net/if.h> 60 1.32 bjh21 #include <net/if_dl.h> 61 1.32 bjh21 #include <net/if_ieee1394.h> 62 1.32 bjh21 #include <net/if_types.h> 63 1.48 is #include <netatalk/at.h> 64 1.1 itojun #include <netinet/in.h> 65 1.1 itojun #include <arpa/inet.h> 66 1.1 itojun #include <arpa/nameser.h> 67 1.24 lukem #include <assert.h> 68 1.32 bjh21 #include <limits.h> 69 1.1 itojun #include <netdb.h> 70 1.1 itojun #include <resolv.h> 71 1.24 lukem #include <stddef.h> 72 1.1 itojun #include <string.h> 73 1.14 itojun 74 1.44 christos #include "servent.h" 75 1.54 christos #include "hostent.h" 76 1.44 christos 77 1.56 joerg #ifndef RUMP_ACTION 78 1.14 itojun #ifdef __weak_alias 79 1.14 itojun __weak_alias(getnameinfo,_getnameinfo) 80 1.14 itojun #endif 81 1.56 joerg #endif 82 1.1 itojun 83 1.25 jdolecek static const struct afd { 84 1.27 kleink int a_af; 85 1.27 kleink socklen_t a_addrlen; 86 1.27 kleink socklen_t a_socklen; 87 1.27 kleink int a_off; 88 1.1 itojun } afdl [] = { 89 1.1 itojun #ifdef INET6 90 1.1 itojun {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), 91 1.1 itojun offsetof(struct sockaddr_in6, sin6_addr)}, 92 1.1 itojun #endif 93 1.1 itojun {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), 94 1.1 itojun offsetof(struct sockaddr_in, sin_addr)}, 95 1.45 christos {0, 0, 0, 0}, 96 1.1 itojun }; 97 1.1 itojun 98 1.1 itojun struct sockinet { 99 1.1 itojun u_char si_len; 100 1.1 itojun u_char si_family; 101 1.1 itojun u_short si_port; 102 1.1 itojun }; 103 1.1 itojun 104 1.52 matt static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *, 105 1.52 matt socklen_t, char *, socklen_t, int); 106 1.10 itojun #ifdef INET6 107 1.52 matt static int ip6_parsenumeric(const struct sockaddr *, const char *, char *, 108 1.52 matt socklen_t, int); 109 1.52 matt static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int); 110 1.18 itojun #endif 111 1.52 matt static int getnameinfo_atalk(const struct sockaddr *, socklen_t, char *, 112 1.52 matt socklen_t, char *, socklen_t, int); 113 1.53 christos static int getnameinfo_local(const struct sockaddr *, socklen_t, char *, 114 1.53 christos socklen_t, char *, socklen_t, int); 115 1.48 is 116 1.52 matt static int getnameinfo_link(const struct sockaddr *, socklen_t, char *, 117 1.52 matt socklen_t, char *, socklen_t, int); 118 1.52 matt static int hexname(const uint8_t *, size_t, char *, socklen_t); 119 1.10 itojun 120 1.32 bjh21 /* 121 1.32 bjh21 * Top-level getnameinfo() code. Look at the address family, and pick an 122 1.32 bjh21 * appropriate function to call. 123 1.32 bjh21 */ 124 1.1 itojun int 125 1.52 matt getnameinfo(const struct sockaddr *sa, socklen_t salen, 126 1.52 matt char *host, socklen_t hostlen, 127 1.52 matt char *serv, socklen_t servlen, 128 1.52 matt int flags) 129 1.32 bjh21 { 130 1.32 bjh21 131 1.60 christos /* 132 1.60 christos * getnameinfo() accepts an salen of sizeof(struct sockaddr_storage) 133 1.60 christos * at maximum as shown in RFC 4038 Sec.6.2.3. 134 1.60 christos */ 135 1.60 christos if (salen > sizeof(struct sockaddr_storage)) 136 1.60 christos return EAI_FAMILY; 137 1.60 christos 138 1.32 bjh21 switch (sa->sa_family) { 139 1.48 is case AF_APPLETALK: 140 1.48 is return getnameinfo_atalk(sa, salen, host, hostlen, 141 1.48 is serv, servlen, flags); 142 1.32 bjh21 case AF_INET: 143 1.32 bjh21 case AF_INET6: 144 1.32 bjh21 return getnameinfo_inet(sa, salen, host, hostlen, 145 1.32 bjh21 serv, servlen, flags); 146 1.32 bjh21 case AF_LINK: 147 1.32 bjh21 return getnameinfo_link(sa, salen, host, hostlen, 148 1.32 bjh21 serv, servlen, flags); 149 1.53 christos case AF_LOCAL: 150 1.53 christos return getnameinfo_local(sa, salen, host, hostlen, 151 1.53 christos serv, servlen, flags); 152 1.32 bjh21 default: 153 1.32 bjh21 return EAI_FAMILY; 154 1.32 bjh21 } 155 1.35 sommerfe } 156 1.32 bjh21 157 1.48 is /* 158 1.48 is * getnameinfo_atalk(): 159 1.48 is * Format an AppleTalk address into a printable format. 160 1.48 is */ 161 1.48 is /* ARGSUSED */ 162 1.48 is static int 163 1.48 is getnameinfo_atalk(const struct sockaddr *sa, socklen_t salen, 164 1.48 is char *host, socklen_t hostlen, char *serv, socklen_t servlen, 165 1.48 is int flags) 166 1.48 is { 167 1.48 is char numserv[8]; 168 1.49 is int n, m=0; 169 1.48 is 170 1.48 is const struct sockaddr_at *sat = 171 1.48 is (const struct sockaddr_at *)(const void *)sa; 172 1.48 is 173 1.48 is if (serv != NULL && servlen > 0) { 174 1.48 is snprintf(numserv, sizeof(numserv), "%u", sat->sat_port); 175 1.48 is if (strlen(numserv) + 1 > servlen) 176 1.48 is return EAI_MEMORY; 177 1.48 is strlcpy(serv, numserv, servlen); 178 1.48 is } 179 1.48 is 180 1.49 is n = snprintf(host, hostlen, "%u.%u", 181 1.49 is ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 182 1.49 is 183 1.49 is if (n < 0 || (socklen_t)(m+n) >= hostlen) 184 1.49 is goto errout; 185 1.49 is 186 1.49 is m += n; 187 1.49 is 188 1.48 is if (sat->sat_range.r_netrange.nr_phase) { 189 1.49 is n = snprintf(host+m, hostlen-m, " phase %u", 190 1.48 is sat->sat_range.r_netrange.nr_phase); 191 1.49 is 192 1.49 is if (n < 0 || (socklen_t)(m+n) >= hostlen) 193 1.49 is goto errout; 194 1.49 is 195 1.49 is m += n; 196 1.48 is } 197 1.49 is if (sat->sat_range.r_netrange.nr_firstnet) { 198 1.49 is n = snprintf(host+m, hostlen-m, " range %u - %u", 199 1.49 is ntohs(sat->sat_range.r_netrange.nr_firstnet), 200 1.49 is ntohs(sat->sat_range.r_netrange.nr_lastnet )); 201 1.49 is 202 1.49 is if (n < 0 || (socklen_t)(m+n) >= hostlen) 203 1.49 is goto errout; 204 1.48 is 205 1.49 is m += n; 206 1.48 is } 207 1.49 is 208 1.48 is return 0; 209 1.49 is 210 1.49 is errout: 211 1.49 is if (host && hostlen>0) 212 1.49 is host[m] = '\0'; /* XXX ??? */ 213 1.49 is 214 1.49 is return EAI_MEMORY; 215 1.48 is } 216 1.32 bjh21 217 1.32 bjh21 /* 218 1.53 christos * getnameinfo_local(): 219 1.53 christos * Format an local address into a printable format. 220 1.53 christos */ 221 1.53 christos /* ARGSUSED */ 222 1.53 christos static int 223 1.53 christos getnameinfo_local(const struct sockaddr *sa, socklen_t salen, 224 1.53 christos char *host, socklen_t hostlen, char *serv, socklen_t servlen, 225 1.53 christos int flags) 226 1.53 christos { 227 1.53 christos const struct sockaddr_un *sun = 228 1.53 christos (const struct sockaddr_un *)(const void *)sa; 229 1.53 christos 230 1.60 christos if (salen <= sizeof(*sun) - sizeof(sun->sun_path)) 231 1.60 christos return EAI_FAMILY; 232 1.60 christos 233 1.53 christos if (serv != NULL && servlen > 0) 234 1.53 christos serv[0] = '\0'; 235 1.53 christos 236 1.53 christos if (host && hostlen > 0) 237 1.53 christos strlcpy(host, sun->sun_path, 238 1.53 christos MIN(sizeof(sun->sun_path) + 1, hostlen)); 239 1.53 christos 240 1.53 christos return 0; 241 1.53 christos } 242 1.53 christos 243 1.53 christos /* 244 1.32 bjh21 * getnameinfo_inet(): 245 1.32 bjh21 * Format an IPv4 or IPv6 sockaddr into a printable string. 246 1.32 bjh21 */ 247 1.32 bjh21 static int 248 1.52 matt getnameinfo_inet(const struct sockaddr *sa, socklen_t salen, 249 1.52 matt char *host, socklen_t hostlen, 250 1.52 matt char *serv, socklen_t servlen, 251 1.52 matt int flags) 252 1.1 itojun { 253 1.25 jdolecek const struct afd *afd; 254 1.1 itojun struct servent *sp; 255 1.1 itojun struct hostent *hp; 256 1.1 itojun u_short port; 257 1.5 itojun int family, i; 258 1.16 itojun const char *addr; 259 1.52 matt uint32_t v4a; 260 1.1 itojun char numserv[512]; 261 1.1 itojun char numaddr[512]; 262 1.1 itojun 263 1.24 lukem /* sa is checked below */ 264 1.24 lukem /* host may be NULL */ 265 1.24 lukem /* serv may be NULL */ 266 1.24 lukem 267 1.1 itojun if (sa == NULL) 268 1.33 itojun return EAI_FAIL; 269 1.1 itojun 270 1.1 itojun family = sa->sa_family; 271 1.1 itojun for (i = 0; afdl[i].a_af; i++) 272 1.1 itojun if (afdl[i].a_af == family) { 273 1.1 itojun afd = &afdl[i]; 274 1.1 itojun goto found; 275 1.1 itojun } 276 1.33 itojun return EAI_FAMILY; 277 1.33 itojun 278 1.1 itojun found: 279 1.60 christos if (salen < afd->a_socklen) 280 1.60 christos return EAI_FAMILY; 281 1.33 itojun 282 1.16 itojun /* network byte order */ 283 1.20 christos port = ((const struct sockinet *)(const void *)sa)->si_port; 284 1.20 christos addr = (const char *)(const void *)sa + afd->a_off; 285 1.1 itojun 286 1.1 itojun if (serv == NULL || servlen == 0) { 287 1.5 itojun /* 288 1.5 itojun * do nothing in this case. 289 1.5 itojun * in case you are wondering if "&&" is more correct than 290 1.33 itojun * "||" here: rfc2553bis-03 says that serv == NULL OR 291 1.33 itojun * servlen == 0 means that the caller does not want the result. 292 1.5 itojun */ 293 1.1 itojun } else { 294 1.47 seanb struct servent_data svd; 295 1.47 seanb struct servent sv; 296 1.47 seanb 297 1.5 itojun if (flags & NI_NUMERICSERV) 298 1.5 itojun sp = NULL; 299 1.5 itojun else { 300 1.44 christos (void)memset(&svd, 0, sizeof(svd)); 301 1.44 christos sp = getservbyport_r(port, 302 1.44 christos (flags & NI_DGRAM) ? "udp" : "tcp", &sv, &svd); 303 1.5 itojun } 304 1.1 itojun if (sp) { 305 1.47 seanb if (strlen(sp->s_name) + 1 > servlen) { 306 1.47 seanb endservent_r(&svd); 307 1.33 itojun return EAI_MEMORY; 308 1.47 seanb } 309 1.38 itojun strlcpy(serv, sp->s_name, servlen); 310 1.47 seanb endservent_r(&svd); 311 1.5 itojun } else { 312 1.40 itojun snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); 313 1.22 itojun if (strlen(numserv) + 1 > servlen) 314 1.33 itojun return EAI_MEMORY; 315 1.38 itojun strlcpy(serv, numserv, servlen); 316 1.5 itojun } 317 1.1 itojun } 318 1.1 itojun 319 1.1 itojun switch (sa->sa_family) { 320 1.1 itojun case AF_INET: 321 1.52 matt v4a = (uint32_t) 322 1.20 christos ntohl(((const struct sockaddr_in *) 323 1.20 christos (const void *)sa)->sin_addr.s_addr); 324 1.1 itojun if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) 325 1.1 itojun flags |= NI_NUMERICHOST; 326 1.1 itojun v4a >>= IN_CLASSA_NSHIFT; 327 1.7 itojun if (v4a == 0) 328 1.35 sommerfe flags |= NI_NUMERICHOST; 329 1.1 itojun break; 330 1.1 itojun #ifdef INET6 331 1.1 itojun case AF_INET6: 332 1.3 itojun { 333 1.16 itojun const struct sockaddr_in6 *sin6; 334 1.20 christos sin6 = (const struct sockaddr_in6 *)(const void *)sa; 335 1.5 itojun switch (sin6->sin6_addr.s6_addr[0]) { 336 1.3 itojun case 0x00: 337 1.3 itojun if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 338 1.3 itojun ; 339 1.3 itojun else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) 340 1.3 itojun ; 341 1.3 itojun else 342 1.3 itojun flags |= NI_NUMERICHOST; 343 1.3 itojun break; 344 1.3 itojun default: 345 1.5 itojun if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 346 1.3 itojun flags |= NI_NUMERICHOST; 347 1.5 itojun } 348 1.3 itojun else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 349 1.3 itojun flags |= NI_NUMERICHOST; 350 1.3 itojun break; 351 1.3 itojun } 352 1.3 itojun } 353 1.1 itojun break; 354 1.1 itojun #endif 355 1.1 itojun } 356 1.1 itojun if (host == NULL || hostlen == 0) { 357 1.5 itojun /* 358 1.5 itojun * do nothing in this case. 359 1.5 itojun * in case you are wondering if "&&" is more correct than 360 1.33 itojun * "||" here: rfc2553bis-03 says that host == NULL or 361 1.33 itojun * hostlen == 0 means that the caller does not want the result. 362 1.5 itojun */ 363 1.1 itojun } else if (flags & NI_NUMERICHOST) { 364 1.41 thorpej size_t numaddrlen; 365 1.10 itojun 366 1.3 itojun /* NUMERICHOST and NAMEREQD conflicts with each other */ 367 1.3 itojun if (flags & NI_NAMEREQD) 368 1.33 itojun return EAI_NONAME; 369 1.5 itojun 370 1.16 itojun switch(afd->a_af) { 371 1.16 itojun #ifdef INET6 372 1.16 itojun case AF_INET6: 373 1.16 itojun { 374 1.16 itojun int error; 375 1.16 itojun 376 1.16 itojun if ((error = ip6_parsenumeric(sa, addr, host, 377 1.16 itojun hostlen, flags)) != 0) 378 1.16 itojun return(error); 379 1.16 itojun break; 380 1.16 itojun } 381 1.11 itojun #endif 382 1.16 itojun default: 383 1.51 christos if (inet_ntop(afd->a_af, addr, numaddr, 384 1.51 christos (socklen_t)sizeof(numaddr)) == NULL) 385 1.33 itojun return EAI_SYSTEM; 386 1.16 itojun numaddrlen = strlen(numaddr); 387 1.16 itojun if (numaddrlen + 1 > hostlen) /* don't forget terminator */ 388 1.33 itojun return EAI_MEMORY; 389 1.38 itojun strlcpy(host, numaddr, hostlen); 390 1.16 itojun break; 391 1.5 itojun } 392 1.1 itojun } else { 393 1.54 christos struct hostent hent; 394 1.54 christos char hbuf[4096]; 395 1.54 christos int he; 396 1.54 christos hp = gethostbyaddr_r(addr, afd->a_addrlen, afd->a_af, &hent, 397 1.54 christos hbuf, sizeof(hbuf), &he); 398 1.1 itojun 399 1.1 itojun if (hp) { 400 1.16 itojun #if 0 401 1.16 itojun /* 402 1.16 itojun * commented out, since "for local host" is not 403 1.16 itojun * implemented here - see RFC2553 p30 404 1.16 itojun */ 405 1.1 itojun if (flags & NI_NOFQDN) { 406 1.16 itojun char *p; 407 1.1 itojun p = strchr(hp->h_name, '.'); 408 1.16 itojun if (p) 409 1.16 itojun *p = '\0'; 410 1.1 itojun } 411 1.16 itojun #endif 412 1.22 itojun if (strlen(hp->h_name) + 1 > hostlen) { 413 1.33 itojun return EAI_MEMORY; 414 1.1 itojun } 415 1.38 itojun strlcpy(host, hp->h_name, hostlen); 416 1.1 itojun } else { 417 1.58 christos switch (he) { 418 1.58 christos case NO_DATA: 419 1.58 christos case HOST_NOT_FOUND: 420 1.58 christos if (flags & NI_NAMEREQD) 421 1.58 christos return EAI_NONAME; 422 1.58 christos break; 423 1.58 christos case TRY_AGAIN: 424 1.58 christos return EAI_AGAIN; 425 1.58 christos case NETDB_SUCCESS: 426 1.59 christos case NETDB_INTERNAL: 427 1.59 christos case NO_RECOVERY: 428 1.58 christos /*FALLTHROUGH*/ 429 1.58 christos default: 430 1.59 christos return EAI_SYSTEM; 431 1.58 christos } 432 1.16 itojun switch(afd->a_af) { 433 1.16 itojun #ifdef INET6 434 1.16 itojun case AF_INET6: 435 1.16 itojun { 436 1.16 itojun int error; 437 1.16 itojun 438 1.16 itojun if ((error = ip6_parsenumeric(sa, addr, host, 439 1.16 itojun hostlen, 440 1.16 itojun flags)) != 0) 441 1.16 itojun return(error); 442 1.16 itojun break; 443 1.16 itojun } 444 1.16 itojun #endif 445 1.16 itojun default: 446 1.16 itojun if (inet_ntop(afd->a_af, addr, host, 447 1.16 itojun hostlen) == NULL) 448 1.33 itojun return EAI_SYSTEM; 449 1.16 itojun break; 450 1.16 itojun } 451 1.1 itojun } 452 1.1 itojun } 453 1.33 itojun return(0); 454 1.1 itojun } 455 1.10 itojun 456 1.10 itojun #ifdef INET6 457 1.16 itojun static int 458 1.52 matt ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host, 459 1.52 matt socklen_t hostlen, int flags) 460 1.16 itojun { 461 1.41 thorpej size_t numaddrlen; 462 1.16 itojun char numaddr[512]; 463 1.16 itojun 464 1.24 lukem _DIAGASSERT(sa != NULL); 465 1.24 lukem _DIAGASSERT(addr != NULL); 466 1.24 lukem _DIAGASSERT(host != NULL); 467 1.24 lukem 468 1.51 christos if (inet_ntop(AF_INET6, addr, numaddr, (socklen_t)sizeof(numaddr)) 469 1.51 christos == NULL) 470 1.33 itojun return EAI_SYSTEM; 471 1.16 itojun 472 1.16 itojun numaddrlen = strlen(numaddr); 473 1.16 itojun if (numaddrlen + 1 > hostlen) /* don't forget terminator */ 474 1.43 ginsbach return EAI_OVERFLOW; 475 1.38 itojun strlcpy(host, numaddr, hostlen); 476 1.16 itojun 477 1.20 christos if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) { 478 1.34 itojun char zonebuf[MAXHOSTNAMELEN]; 479 1.34 itojun int zonelen; 480 1.16 itojun 481 1.34 itojun zonelen = ip6_sa2str( 482 1.34 itojun (const struct sockaddr_in6 *)(const void *)sa, 483 1.34 itojun zonebuf, sizeof(zonebuf), flags); 484 1.34 itojun if (zonelen < 0) 485 1.43 ginsbach return EAI_OVERFLOW; 486 1.41 thorpej if ((size_t) zonelen + 1 + numaddrlen + 1 > hostlen) 487 1.43 ginsbach return EAI_OVERFLOW; 488 1.34 itojun /* construct <numeric-addr><delim><zoneid> */ 489 1.34 itojun memcpy(host + numaddrlen + 1, zonebuf, 490 1.34 itojun (size_t)zonelen); 491 1.34 itojun host[numaddrlen] = SCOPE_DELIMITER; 492 1.34 itojun host[numaddrlen + 1 + zonelen] = '\0'; 493 1.16 itojun } 494 1.16 itojun 495 1.16 itojun return 0; 496 1.16 itojun } 497 1.16 itojun 498 1.10 itojun /* ARGSUSED */ 499 1.16 itojun static int 500 1.52 matt ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags) 501 1.10 itojun { 502 1.24 lukem unsigned int ifindex; 503 1.24 lukem const struct in6_addr *a6; 504 1.28 itojun int n; 505 1.24 lukem 506 1.24 lukem _DIAGASSERT(sa6 != NULL); 507 1.24 lukem _DIAGASSERT(buf != NULL); 508 1.35 sommerfe 509 1.24 lukem ifindex = (unsigned int)sa6->sin6_scope_id; 510 1.24 lukem a6 = &sa6->sin6_addr; 511 1.10 itojun 512 1.28 itojun #ifdef NI_NUMERICSCOPE 513 1.28 itojun if ((flags & NI_NUMERICSCOPE) != 0) { 514 1.28 itojun n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); 515 1.46 lukem if (n < 0 || (size_t)n >= bufsiz) 516 1.28 itojun return -1; 517 1.28 itojun else 518 1.28 itojun return n; 519 1.10 itojun } 520 1.10 itojun #endif 521 1.18 itojun 522 1.16 itojun /* if_indextoname() does not take buffer size. not a good api... */ 523 1.16 itojun if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && 524 1.16 itojun bufsiz >= IF_NAMESIZE) { 525 1.16 itojun char *p = if_indextoname(ifindex, buf); 526 1.16 itojun if (p) { 527 1.51 christos return (int)strlen(p); 528 1.16 itojun } 529 1.16 itojun } 530 1.10 itojun 531 1.16 itojun /* last resort */ 532 1.28 itojun n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); 533 1.41 thorpej if (n < 0 || (size_t) n >= bufsiz) 534 1.28 itojun return -1; 535 1.28 itojun else 536 1.28 itojun return n; 537 1.10 itojun } 538 1.16 itojun #endif /* INET6 */ 539 1.32 bjh21 540 1.32 bjh21 541 1.32 bjh21 /* 542 1.32 bjh21 * getnameinfo_link(): 543 1.32 bjh21 * Format a link-layer address into a printable format, paying attention to 544 1.32 bjh21 * the interface type. 545 1.32 bjh21 */ 546 1.32 bjh21 /* ARGSUSED */ 547 1.32 bjh21 static int 548 1.32 bjh21 getnameinfo_link(const struct sockaddr *sa, socklen_t salen, 549 1.37 kleink char *host, socklen_t hostlen, char *serv, socklen_t servlen, 550 1.39 kleink int flags) 551 1.32 bjh21 { 552 1.32 bjh21 const struct sockaddr_dl *sdl = 553 1.32 bjh21 (const struct sockaddr_dl *)(const void *)sa; 554 1.32 bjh21 const struct ieee1394_hwaddr *iha; 555 1.32 bjh21 int n; 556 1.32 bjh21 557 1.60 christos if (salen <= sizeof(*sdl) - sizeof(sdl->sdl_data)) 558 1.60 christos return EAI_FAMILY; 559 1.60 christos 560 1.32 bjh21 if (serv != NULL && servlen > 0) 561 1.32 bjh21 *serv = '\0'; 562 1.32 bjh21 563 1.32 bjh21 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) { 564 1.40 itojun n = snprintf(host, hostlen, "link#%u", sdl->sdl_index); 565 1.57 christos goto out; 566 1.32 bjh21 } 567 1.32 bjh21 568 1.32 bjh21 switch (sdl->sdl_type) { 569 1.32 bjh21 #ifdef IFT_ECONET 570 1.32 bjh21 case IFT_ECONET: 571 1.32 bjh21 if (sdl->sdl_alen < 2) 572 1.32 bjh21 return EAI_FAMILY; 573 1.42 christos if (CLLADDR(sdl)[1] == 0) 574 1.42 christos n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]); 575 1.32 bjh21 else 576 1.40 itojun n = snprintf(host, hostlen, "%u.%u", 577 1.42 christos CLLADDR(sdl)[1], CLLADDR(sdl)[0]); 578 1.57 christos goto out; 579 1.32 bjh21 #endif 580 1.32 bjh21 case IFT_IEEE1394: 581 1.32 bjh21 if (sdl->sdl_alen < sizeof(iha->iha_uid)) 582 1.32 bjh21 return EAI_FAMILY; 583 1.32 bjh21 iha = 584 1.42 christos (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl); 585 1.32 bjh21 return hexname(iha->iha_uid, sizeof(iha->iha_uid), 586 1.32 bjh21 host, hostlen); 587 1.32 bjh21 /* 588 1.32 bjh21 * The following have zero-length addresses. 589 1.32 bjh21 * IFT_ATM (net/if_atmsubr.c) 590 1.32 bjh21 * IFT_FAITH (net/if_faith.c) 591 1.32 bjh21 * IFT_GIF (net/if_gif.c) 592 1.32 bjh21 * IFT_LOOP (net/if_loop.c) 593 1.32 bjh21 * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c) 594 1.32 bjh21 * IFT_SLIP (net/if_sl.c, net/if_strip.c) 595 1.32 bjh21 * IFT_STF (net/if_stf.c) 596 1.32 bjh21 * IFT_L2VLAN (net/if_vlan.c) 597 1.32 bjh21 * IFT_PROPVIRTUAL (net/if_bridge.h> 598 1.32 bjh21 */ 599 1.32 bjh21 /* 600 1.32 bjh21 * The following use IPv4 addresses as link-layer addresses: 601 1.32 bjh21 * IFT_OTHER (net/if_gre.c) 602 1.32 bjh21 */ 603 1.32 bjh21 case IFT_ARCNET: /* default below is believed correct for all these. */ 604 1.32 bjh21 case IFT_ETHER: 605 1.32 bjh21 case IFT_FDDI: 606 1.32 bjh21 case IFT_HIPPI: 607 1.32 bjh21 case IFT_ISO88025: 608 1.32 bjh21 default: 609 1.52 matt return hexname((const uint8_t *)CLLADDR(sdl), 610 1.42 christos (size_t)sdl->sdl_alen, host, hostlen); 611 1.32 bjh21 } 612 1.57 christos out: 613 1.57 christos if (n < 0 || (socklen_t) n >= hostlen) { 614 1.57 christos *host = '\0'; 615 1.57 christos return EAI_MEMORY; 616 1.57 christos } 617 1.57 christos return 0; 618 1.32 bjh21 } 619 1.32 bjh21 620 1.32 bjh21 static int 621 1.52 matt hexname(const uint8_t *cp, size_t len, char *host, socklen_t hostlen) 622 1.32 bjh21 { 623 1.41 thorpej int n; 624 1.41 thorpej size_t i; 625 1.32 bjh21 char *outp = host; 626 1.32 bjh21 627 1.32 bjh21 *outp = '\0'; 628 1.32 bjh21 for (i = 0; i < len; i++) { 629 1.32 bjh21 n = snprintf(outp, hostlen, "%s%02x", 630 1.32 bjh21 i ? ":" : "", cp[i]); 631 1.41 thorpej if (n < 0 || (socklen_t) n >= hostlen) { 632 1.32 bjh21 *host = '\0'; 633 1.32 bjh21 return EAI_MEMORY; 634 1.32 bjh21 } 635 1.32 bjh21 outp += n; 636 1.32 bjh21 hostlen -= n; 637 1.32 bjh21 } 638 1.32 bjh21 return 0; 639 1.32 bjh21 } 640