1 /* $NetBSD: myaddrinfo.c,v 1.1.1.2 2011/03/02 19:32:44 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* myaddrinfo 3 6 /* SUMMARY 7 /* addrinfo encapsulation and emulation 8 /* SYNOPSIS 9 /* #include <myaddrinfo.h> 10 /* 11 /* #define MAI_V4ADDR_BITS ... 12 /* #define MAI_V6ADDR_BITS ... 13 /* #define MAI_V4ADDR_BYTES ... 14 /* #define MAI_V6ADDR_BYTES ... 15 /* 16 /* typedef struct { char buf[....]; } MAI_HOSTNAME_STR; 17 /* typedef struct { char buf[....]; } MAI_HOSTADDR_STR; 18 /* typedef struct { char buf[....]; } MAI_SERVNAME_STR; 19 /* typedef struct { char buf[....]; } MAI_SERVPORT_STR; 20 /* 21 /* int hostname_to_sockaddr(hostname, service, socktype, result) 22 /* const char *hostname; 23 /* const char *service; 24 /* int socktype; 25 /* struct addrinfo **result; 26 /* 27 /* int hostname_to_sockaddr_pf(hostname, pf, service, socktype, result) 28 /* const char *hostname; 29 /* int pf; 30 /* const char *service; 31 /* int socktype; 32 /* struct addrinfo **result; 33 /* 34 /* int hostaddr_to_sockaddr(hostaddr, service, socktype, result) 35 /* const char *hostaddr; 36 /* const char *service; 37 /* int socktype; 38 /* struct addrinfo **result; 39 /* 40 /* int sockaddr_to_hostaddr(sa, salen, hostaddr, portnum, socktype) 41 /* const struct sockaddr *sa; 42 /* SOCKADDR_SIZE salen; 43 /* MAI_HOSTADDR_STR *hostaddr; 44 /* MAI_SERVPORT_STR *portnum; 45 /* int socktype; 46 /* 47 /* int sockaddr_to_hostname(sa, salen, hostname, service, socktype) 48 /* const struct sockaddr *sa; 49 /* SOCKADDR_SIZE salen; 50 /* MAI_HOSTNAME_STR *hostname; 51 /* MAI_SERVNAME_STR *service; 52 /* int socktype; 53 /* 54 /* const char *MAI_STRERROR(error) 55 /* int error; 56 /* DESCRIPTION 57 /* This module provides a simplified user interface to the 58 /* getaddrinfo(3) and getnameinfo(3) routines (which provide 59 /* a unified interface to manipulate IPv4 and IPv6 socket 60 /* address structures). 61 /* 62 /* On systems without getaddrinfo(3) and getnameinfo(3) support, 63 /* emulation for IPv4 only can be enabled by defining 64 /* EMULATE_IPV4_ADDRINFO. 65 /* 66 /* hostname_to_sockaddr() looks up the binary addresses for 67 /* the specified symbolic hostname or numeric address. The 68 /* result should be destroyed with freeaddrinfo(). A null host 69 /* pointer converts to the null host address. 70 /* 71 /* hostname_to_sockaddr_pf() is an extended interface that 72 /* provides a protocol family override. 73 /* 74 /* hostaddr_to_sockaddr() converts a printable network address 75 /* into the corresponding binary form. The result should be 76 /* destroyed with freeaddrinfo(). A null host pointer converts 77 /* to the null host address. 78 /* 79 /* sockaddr_to_hostaddr() converts a binary network address 80 /* into printable form. The result buffers should be large 81 /* enough to hold the printable address or port including the 82 /* null terminator. 83 /* 84 /* sockaddr_to_hostname() converts a binary network address 85 /* into a hostname or service. The result buffer should be 86 /* large enough to hold the hostname or service including the 87 /* null terminator. This routine rejects malformed hostnames 88 /* or numeric hostnames and pretends that the lookup failed. 89 /* 90 /* MAI_STRERROR() is an unsafe macro (it evaluates the argument 91 /* multiple times) that invokes strerror() or gai_strerror() 92 /* as appropriate. 93 /* 94 /* This module exports the following constants that should be 95 /* user for storage allocation of name or address information: 96 /* .IP MAI_V4ADDR_BITS 97 /* .IP MAI_V6ADDR_BITS 98 /* .IP MAI_V4ADDR_BYTES 99 /* .IP MAI_V6ADDR_BYTES 100 /* The number of bits or bytes needed to store a binary 101 /* IPv4 or IPv6 network address. 102 /* .PP 103 /* The types MAI_HOST{NAME,ADDR}_STR and MAI_SERV{NAME,PORT}_STR 104 /* implement buffers for the storage of the string representations 105 /* of symbolic or numerical hosts or services. Do not use 106 /* buffer types other than the ones that are expected here, 107 /* or things will blow up with buffer overflow problems. 108 /* 109 /* Arguments: 110 /* .IP hostname 111 /* On input to hostname_to_sockaddr(), a numeric or symbolic 112 /* hostname, or a null pointer (meaning the wild-card listen 113 /* address). On output from sockaddr_to_hostname(), storage 114 /* for the result hostname, or a null pointer. 115 /* .IP pf 116 /* Protocol type: PF_UNSPEC (meaning: use any protocol that is 117 /* available), PF_INET, or PF_INET6. This argument is ignored 118 /* in EMULATE_IPV4_ADDRINFO mode. 119 /* .IP hostaddr 120 /* On input to hostaddr_to_sockaddr(), a numeric hostname, 121 /* or a null pointer (meaning the wild-card listen address). 122 /* On output from sockaddr_to_hostaddr(), storage for the 123 /* result hostaddress, or a null pointer. 124 /* .IP service 125 /* On input to hostname/addr_to_sockaddr(), a numeric or 126 /* symbolic service name, or a null pointer in which case the 127 /* socktype argument is ignored. On output from 128 /* sockaddr_to_hostname/addr(), storage for the result service 129 /* name, or a null pointer. 130 /* .IP portnum 131 /* Storage for the result service port number, or a null pointer. 132 /* .IP socktype 133 /* Socket type: SOCK_STREAM, SOCK_DGRAM, etc. This argument is 134 /* ignored when no service or port are specified. 135 /* .IP sa 136 /* Protocol-independent socket address structure. 137 /* .IP salen 138 /* Protocol-dependent socket address structure size in bytes. 139 /* SEE ALSO 140 /* getaddrinfo(3), getnameinfo(3), freeaddrinfo(3), gai_strerror(3) 141 /* DIAGNOSTICS 142 /* All routines either return 0 upon success, or an error code 143 /* that is compatible with gai_strerror(). 144 /* 145 /* On systems where addrinfo support is emulated by Postfix, 146 /* some out-of-memory errors are not reported to the caller, 147 /* but are handled by mymalloc(). 148 /* BUGS 149 /* The IPv4-only emulation code does not support requests that 150 /* specify a service but no socket type. It returns an error 151 /* indication, instead of enumerating all the possible answers. 152 /* 153 /* The hostname/addr_to_sockaddr() routines should accept a 154 /* list of address families that the caller is interested in, 155 /* and they should return only information of those types. 156 /* 157 /* Unfortunately, it is not possible to remove unwanted address 158 /* family results from hostname_to_sockaddr(), because we 159 /* don't know how the system library routine getaddrinfo() 160 /* allocates memory. For example, getaddrinfo() could save 161 /* space by referencing the same string object from multiple 162 /* addrinfo structures; or it could allocate a string object 163 /* and the addrinfo structure as one memory block. 164 /* 165 /* We could get around this by copying getaddrinfo() results 166 /* to our own private data structures, but that would only 167 /* make an already expensive API even more expensive. 168 /* 169 /* A better workaround is to return a vector of addrinfo 170 /* pointers to the elements that contain only the elements 171 /* that the caller is interested in. The pointer to the 172 /* original getaddrinfo() result can be hidden at the end 173 /* after the null terminator, or before the first element. 174 /* LICENSE 175 /* .ad 176 /* .fi 177 /* The Secure Mailer license must be distributed with this software. 178 /* AUTHOR(S) 179 /* Wietse Venema 180 /* IBM T.J. Watson Research 181 /* P.O. Box 704 182 /* Yorktown Heights, NY 10598, USA 183 /*--*/ 184 185 /* System library. */ 186 187 #include <sys_defs.h> 188 #include <sys/types.h> 189 #include <sys/socket.h> 190 #include <netinet/in.h> 191 #include <arpa/inet.h> 192 #include <netdb.h> 193 #include <string.h> 194 #include <errno.h> 195 #include <stdlib.h> 196 #include <stdio.h> /* sprintf() */ 197 198 /* Utility library. */ 199 200 #include <mymalloc.h> 201 #include <valid_hostname.h> 202 #include <sock_addr.h> 203 #include <stringops.h> 204 #include <msg.h> 205 #include <inet_proto.h> 206 #include <myaddrinfo.h> 207 208 /* Application-specific. */ 209 210 /* 211 * Use an old trick to save some space: allocate space for two objects in 212 * one. In Postfix we often use this trick for structures that have an array 213 * of things at the end. 214 */ 215 struct ipv4addrinfo { 216 struct addrinfo info; 217 struct sockaddr_in sin; 218 }; 219 220 /* 221 * When we're not interested in service ports, we must pick a socket type 222 * otherwise getaddrinfo() will give us duplicate results: one set for TCP, 223 * and another set for UDP. For consistency, we'll use the same default 224 * socket type for the results from emulation mode. 225 */ 226 #define MAI_SOCKTYPE SOCK_STREAM /* getaddrinfo() query */ 227 228 #ifdef EMULATE_IPV4_ADDRINFO 229 230 /* clone_ipv4addrinfo - clone ipv4addrinfo structure */ 231 232 static struct ipv4addrinfo *clone_ipv4addrinfo(struct ipv4addrinfo * tp) 233 { 234 struct ipv4addrinfo *ip; 235 236 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip)); 237 *ip = *tp; 238 ip->info.ai_addr = (struct sockaddr *) & (ip->sin); 239 return (ip); 240 } 241 242 /* init_ipv4addrinfo - initialize an ipv4addrinfo structure */ 243 244 static void init_ipv4addrinfo(struct ipv4addrinfo * ip, int socktype) 245 { 246 247 /* 248 * Portability: null pointers aren't necessarily all-zero bits, so we 249 * make explicit assignments to all the pointers that we're aware of. 250 */ 251 memset((char *) ip, 0, sizeof(*ip)); 252 ip->info.ai_family = PF_INET; 253 ip->info.ai_socktype = socktype; 254 ip->info.ai_protocol = 0; /* XXX */ 255 ip->info.ai_addrlen = sizeof(ip->sin); 256 ip->info.ai_canonname = 0; 257 ip->info.ai_addr = (struct sockaddr *) & (ip->sin); 258 ip->info.ai_next = 0; 259 ip->sin.sin_family = AF_INET; 260 #ifdef HAS_SA_LEN 261 ip->sin.sin_len = sizeof(ip->sin); 262 #endif 263 } 264 265 /* find_service - translate numeric or symbolic service name */ 266 267 static int find_service(const char *service, int socktype) 268 { 269 struct servent *sp; 270 const char *proto; 271 unsigned port; 272 273 if (alldig(service)) { 274 port = atoi(service); 275 return (port < 65536 ? htons(port) : -1); 276 } 277 if (socktype == SOCK_STREAM) { 278 proto = "tcp"; 279 } else if (socktype == SOCK_DGRAM) { 280 proto = "udp"; 281 } else { 282 return (-1); 283 } 284 if ((sp = getservbyname(service, proto)) != 0) { 285 return (sp->s_port); 286 } else { 287 return (-1); 288 } 289 } 290 291 #endif 292 293 /* hostname_to_sockaddr_pf - hostname to binary address form */ 294 295 int hostname_to_sockaddr_pf(const char *hostname, int pf, 296 const char *service, int socktype, 297 struct addrinfo ** res) 298 { 299 #ifdef EMULATE_IPV4_ADDRINFO 300 301 /* 302 * Emulated getaddrinfo(3) version. 303 */ 304 static struct ipv4addrinfo template; 305 struct ipv4addrinfo *ip; 306 struct ipv4addrinfo *prev; 307 struct in_addr addr; 308 struct hostent *hp; 309 char **name_list; 310 int port; 311 312 /* 313 * Validate the service. 314 */ 315 if (service) { 316 if ((port = find_service(service, socktype)) < 0) 317 return (EAI_SERVICE); 318 } else { 319 port = 0; 320 socktype = MAI_SOCKTYPE; 321 } 322 323 /* 324 * No host means INADDR_ANY. 325 */ 326 if (hostname == 0) { 327 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip)); 328 init_ipv4addrinfo(ip, socktype); 329 ip->sin.sin_addr.s_addr = INADDR_ANY; 330 ip->sin.sin_port = port; 331 *res = &(ip->info); 332 return (0); 333 } 334 335 /* 336 * Numeric host. 337 */ 338 if (inet_pton(AF_INET, hostname, (void *) &addr) == 1) { 339 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip)); 340 init_ipv4addrinfo(ip, socktype); 341 ip->sin.sin_addr = addr; 342 ip->sin.sin_port = port; 343 *res = &(ip->info); 344 return (0); 345 } 346 347 /* 348 * Look up the IPv4 address list. 349 */ 350 if ((hp = gethostbyname(hostname)) == 0) 351 return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NODATA); 352 if (hp->h_addrtype != AF_INET 353 || hp->h_length != sizeof(template.sin.sin_addr)) 354 return (EAI_NODATA); 355 356 /* 357 * Initialize the result template. 358 */ 359 if (template.info.ai_addrlen == 0) 360 init_ipv4addrinfo(&template, socktype); 361 362 /* 363 * Copy the address information into an addrinfo structure. 364 */ 365 prev = &template; 366 for (name_list = hp->h_addr_list; name_list[0]; name_list++) { 367 ip = clone_ipv4addrinfo(prev); 368 ip->sin.sin_addr = IN_ADDR(name_list[0]); 369 ip->sin.sin_port = port; 370 if (prev == &template) 371 *res = &(ip->info); 372 else 373 prev->info.ai_next = &(ip->info); 374 prev = ip; 375 } 376 return (0); 377 #else 378 379 /* 380 * Native getaddrinfo(3) version. 381 * 382 * XXX Wild-card listener issues. 383 * 384 * With most IPv4 plus IPv6 systems, an IPv6 wild-card listener also listens 385 * on the IPv4 wild-card address. Connections from IPv4 clients appear as 386 * IPv4-in-IPv6 addresses; when Postfix support for IPv4 is turned on, 387 * Postfix automatically maps these embedded addresses to their original 388 * IPv4 form. So everything seems to be fine. 389 * 390 * However, some applications prefer to use separate listener sockets for 391 * IPv4 and IPv6. The Postfix IPv6 patch provided such an example. And 392 * this is where things become tricky. On many systems the IPv6 and IPv4 393 * wild-card listeners cannot coexist. When one is already active, the 394 * other fails with EADDRINUSE. Solaris 9, however, will automagically 395 * "do the right thing" and allow both listeners to coexist. 396 * 397 * Recent systems have the IPV6_V6ONLY feature (RFC 3493), which tells the 398 * system that we really mean IPv6 when we say IPv6. This allows us to 399 * set up separate wild-card listener sockets for IPv4 and IPv6. So 400 * everything seems to be fine again. 401 * 402 * The following workaround disables the wild-card IPv4 listener when 403 * IPV6_V6ONLY is unavailable. This is necessary for some Linux versions, 404 * but is not needed for Solaris 9 (which allows IPv4 and IPv6 wild-card 405 * listeners to coexist). Solaris 10 beta already has IPV6_V6ONLY. 406 * 407 * XXX This workaround obviously breaks if we want to support protocols in 408 * addition to IPv6 and IPv4, but it is needed only until IPv6 409 * implementations catch up with RFC 3493. A nicer fix is to filter the 410 * getaddrinfo() result, and to return a vector of addrinfo pointers to 411 * only those types of elements that the caller has expressed interested 412 * in. 413 * 414 * XXX Vanilla AIX 5.1 getaddrinfo() does not support a null hostname with 415 * AI_PASSIVE. And since we don't know how getaddrinfo() manages its 416 * memory we can't bypass it for this special case, or freeaddrinfo() 417 * might blow up. Instead we turn off IPV6_V6ONLY in inet_listen(), and 418 * supply a protocol-dependent hard-coded string value to getaddrinfo() 419 * below, so that it will convert into the appropriate wild-card address. 420 * 421 * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null 422 * service argument is specified. 423 */ 424 struct addrinfo hints; 425 int err; 426 427 memset((char *) &hints, 0, sizeof(hints)); 428 hints.ai_family = (pf != PF_UNSPEC) ? pf : inet_proto_info()->ai_family; 429 hints.ai_socktype = service ? socktype : MAI_SOCKTYPE; 430 if (!hostname) { 431 hints.ai_flags = AI_PASSIVE; 432 #if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST) 433 switch (hints.ai_family) { 434 case PF_UNSPEC: 435 hints.ai_family = PF_INET6; 436 #ifdef BROKEN_AI_PASSIVE_NULL_HOST 437 case PF_INET6: 438 hostname = "::"; 439 break; 440 case PF_INET: 441 hostname = "0.0.0.0"; 442 break; 443 #endif 444 } 445 #endif 446 } 447 err = getaddrinfo(hostname, service, &hints, res); 448 #if defined(BROKEN_AI_NULL_SERVICE) 449 if (service == 0 && err == 0) { 450 struct addrinfo *r; 451 unsigned short *portp; 452 453 for (r = *res; r != 0; r = r->ai_next) 454 if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0) 455 *portp = 0; 456 } 457 #endif 458 return (err); 459 #endif 460 } 461 462 /* hostaddr_to_sockaddr - printable address to binary address form */ 463 464 int hostaddr_to_sockaddr(const char *hostaddr, const char *service, 465 int socktype, struct addrinfo ** res) 466 { 467 #ifdef EMULATE_IPV4_ADDRINFO 468 469 /* 470 * Emulated getaddrinfo(3) version. 471 */ 472 struct ipv4addrinfo *ip; 473 struct in_addr addr; 474 int port; 475 476 /* 477 * Validate the service. 478 */ 479 if (service) { 480 if ((port = find_service(service, socktype)) < 0) 481 return (EAI_SERVICE); 482 } else { 483 port = 0; 484 socktype = MAI_SOCKTYPE; 485 } 486 487 /* 488 * No host means INADDR_ANY. 489 */ 490 if (hostaddr == 0) { 491 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip)); 492 init_ipv4addrinfo(ip, socktype); 493 ip->sin.sin_addr.s_addr = INADDR_ANY; 494 ip->sin.sin_port = port; 495 *res = &(ip->info); 496 return (0); 497 } 498 499 /* 500 * Deal with bad address forms. 501 */ 502 switch (inet_pton(AF_INET, hostaddr, (void *) &addr)) { 503 case 1: /* Success */ 504 break; 505 default: /* Unparsable */ 506 return (EAI_NONAME); 507 case -1: /* See errno */ 508 return (EAI_SYSTEM); 509 } 510 511 /* 512 * Initialize the result structure. 513 */ 514 ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip)); 515 init_ipv4addrinfo(ip, socktype); 516 517 /* 518 * And copy the result. 519 */ 520 ip->sin.sin_addr = addr; 521 ip->sin.sin_port = port; 522 *res = &(ip->info); 523 524 return (0); 525 #else 526 527 /* 528 * Native getaddrinfo(3) version. See comments in hostname_to_sockaddr(). 529 * 530 * XXX Vanilla AIX 5.1 getaddrinfo() returns multiple results when 531 * converting a printable ipv4 or ipv6 address to socket address with 532 * ai_family=PF_UNSPEC, ai_flags=AI_NUMERICHOST, ai_socktype=SOCK_STREAM, 533 * ai_protocol=0 or IPPROTO_TCP, and service=0. The workaround is to 534 * ignore all but the first result. 535 * 536 * XXX AIX 5.[1-3] getaddrinfo() may return a non-null port when a null 537 * service argument is specified. 538 */ 539 struct addrinfo hints; 540 int err; 541 542 memset(&hints, 0, sizeof(hints)); 543 hints.ai_family = inet_proto_info()->ai_family; 544 hints.ai_socktype = service ? socktype : MAI_SOCKTYPE; 545 hints.ai_flags = AI_NUMERICHOST; 546 if (!hostaddr) { 547 hints.ai_flags |= AI_PASSIVE; 548 #if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST) 549 switch (hints.ai_family) { 550 case PF_UNSPEC: 551 hints.ai_family = PF_INET6; 552 #ifdef BROKEN_AI_PASSIVE_NULL_HOST 553 case PF_INET6: 554 hostaddr = "::"; 555 break; 556 case PF_INET: 557 hostaddr = "0.0.0.0"; 558 break; 559 #endif 560 } 561 #endif 562 } 563 err = getaddrinfo(hostaddr, service, &hints, res); 564 #if defined(BROKEN_AI_NULL_SERVICE) 565 if (service == 0 && err == 0) { 566 struct addrinfo *r; 567 unsigned short *portp; 568 569 for (r = *res; r != 0; r = r->ai_next) 570 if (*(portp = SOCK_ADDR_PORTP(r->ai_addr)) != 0) 571 *portp = 0; 572 } 573 #endif 574 return (err); 575 #endif 576 } 577 578 /* sockaddr_to_hostaddr - binary address to printable address form */ 579 580 int sockaddr_to_hostaddr(const struct sockaddr * sa, SOCKADDR_SIZE salen, 581 MAI_HOSTADDR_STR *hostaddr, 582 MAI_SERVPORT_STR *portnum, 583 int unused_socktype) 584 { 585 #ifdef EMULATE_IPV4_ADDRINFO 586 char portbuf[sizeof("65535")]; 587 ssize_t len; 588 589 /* 590 * Emulated getnameinfo(3) version. The buffer length includes the space 591 * for the null terminator. 592 */ 593 if (sa->sa_family != AF_INET) { 594 errno = EAFNOSUPPORT; 595 return (EAI_SYSTEM); 596 } 597 if (hostaddr != 0) { 598 if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)), 599 hostaddr->buf, sizeof(hostaddr->buf)) == 0) 600 return (EAI_SYSTEM); 601 } 602 if (portnum != 0) { 603 sprintf(portbuf, "%d", ntohs(SOCK_ADDR_IN_PORT(sa)) & 0xffff); 604 if ((len = strlen(portbuf)) >= sizeof(portnum->buf)) { 605 errno = ENOSPC; 606 return (EAI_SYSTEM); 607 } 608 memcpy(portnum->buf, portbuf, len + 1); 609 } 610 return (0); 611 #else 612 613 /* 614 * Native getnameinfo(3) version. 615 */ 616 return (getnameinfo(sa, salen, 617 hostaddr ? hostaddr->buf : (char *) 0, 618 hostaddr ? sizeof(hostaddr->buf) : 0, 619 portnum ? portnum->buf : (char *) 0, 620 portnum ? sizeof(portnum->buf) : 0, 621 NI_NUMERICHOST | NI_NUMERICSERV)); 622 #endif 623 } 624 625 /* sockaddr_to_hostname - binary address to printable hostname */ 626 627 int sockaddr_to_hostname(const struct sockaddr * sa, SOCKADDR_SIZE salen, 628 MAI_HOSTNAME_STR *hostname, 629 MAI_SERVNAME_STR *service, 630 int socktype) 631 { 632 #ifdef EMULATE_IPV4_ADDRINFO 633 634 /* 635 * Emulated getnameinfo(3) version. 636 */ 637 struct hostent *hp; 638 struct servent *sp; 639 size_t len; 640 641 /* 642 * Sanity check. 643 */ 644 if (sa->sa_family != AF_INET) 645 return (EAI_NODATA); 646 647 /* 648 * Look up the host name. 649 */ 650 if (hostname != 0) { 651 if ((hp = gethostbyaddr((char *) &(SOCK_ADDR_IN_ADDR(sa)), 652 sizeof(SOCK_ADDR_IN_ADDR(sa)), 653 AF_INET)) == 0) 654 return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NONAME); 655 656 /* 657 * Save the result. The buffer length includes the space for the null 658 * terminator. Hostname sanity checks are at the end of this 659 * function. 660 */ 661 if ((len = strlen(hp->h_name)) >= sizeof(hostname->buf)) { 662 errno = ENOSPC; 663 return (EAI_SYSTEM); 664 } 665 memcpy(hostname->buf, hp->h_name, len + 1); 666 } 667 668 /* 669 * Look up the service. 670 */ 671 if (service != 0) { 672 if ((sp = getservbyport(ntohs(SOCK_ADDR_IN_PORT(sa)), 673 socktype == SOCK_DGRAM ? "udp" : "tcp")) == 0) 674 return (EAI_NONAME); 675 676 /* 677 * Save the result. The buffer length includes the space for the null 678 * terminator. 679 */ 680 if ((len = strlen(sp->s_name)) >= sizeof(service->buf)) { 681 errno = ENOSPC; 682 return (EAI_SYSTEM); 683 } 684 memcpy(service->buf, sp->s_name, len + 1); 685 } 686 #else 687 688 /* 689 * Native getnameinfo(3) version. 690 */ 691 int err; 692 693 err = getnameinfo(sa, salen, 694 hostname ? hostname->buf : (char *) 0, 695 hostname ? sizeof(hostname->buf) : 0, 696 service ? service->buf : (char *) 0, 697 service ? sizeof(service->buf) : 0, 698 socktype == SOCK_DGRAM ? 699 NI_NAMEREQD | NI_DGRAM : NI_NAMEREQD); 700 if (err != 0) 701 return (err); 702 #endif 703 704 /* 705 * Hostname sanity checks. 706 */ 707 if (hostname != 0) { 708 if (valid_hostaddr(hostname->buf, DONT_GRIPE)) { 709 msg_warn("numeric hostname: %s", hostname->buf); 710 return (EAI_NONAME); 711 } 712 if (!valid_hostname(hostname->buf, DO_GRIPE)) 713 return (EAI_NONAME); 714 } 715 return (0); 716 } 717 718 /* myaddrinfo_control - fine control */ 719 720 void myaddrinfo_control(int name,...) 721 { 722 const char *myname = "myaddrinfo_control"; 723 va_list ap; 724 725 for (va_start(ap, name); name != 0; name = va_arg(ap, int)) { 726 switch (name) { 727 default: 728 msg_panic("%s: bad name %d", myname, name); 729 } 730 } 731 va_end(ap); 732 } 733 734 #ifdef EMULATE_IPV4_ADDRINFO 735 736 /* freeaddrinfo - release storage */ 737 738 void freeaddrinfo(struct addrinfo * ai) 739 { 740 struct addrinfo *ap; 741 struct addrinfo *next; 742 743 /* 744 * Artefact of implementation: tolerate a null pointer argument. 745 */ 746 for (ap = ai; ap != 0; ap = next) { 747 next = ap->ai_next; 748 if (ap->ai_canonname) 749 myfree(ap->ai_canonname); 750 /* ap->ai_addr is allocated within this memory block */ 751 myfree((char *) ap); 752 } 753 } 754 755 static char *ai_errlist[] = { 756 "Success", 757 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 758 "Temporary failure in name resolution", /* EAI_AGAIN */ 759 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 760 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 761 "ai_family not supported", /* EAI_FAMILY */ 762 "Memory allocation failure", /* EAI_MEMORY */ 763 "No address associated with hostname", /* EAI_NODATA */ 764 "hostname nor servname provided, or not known", /* EAI_NONAME */ 765 "service name not supported for ai_socktype", /* EAI_SERVICE */ 766 "ai_socktype not supported", /* EAI_SOCKTYPE */ 767 "System error returned in errno", /* EAI_SYSTEM */ 768 "Invalid value for hints", /* EAI_BADHINTS */ 769 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 770 "Unknown error", /* EAI_MAX */ 771 }; 772 773 /* gai_strerror - error number to string */ 774 775 char *gai_strerror(int ecode) 776 { 777 778 /* 779 * Note: EAI_SYSTEM errors are not automatically handed over to 780 * strerror(). The application decides. 781 */ 782 if (ecode < 0 || ecode > EAI_MAX) 783 ecode = EAI_MAX; 784 return (ai_errlist[ecode]); 785 } 786 787 #endif 788 789 #ifdef TEST 790 791 /* 792 * A test program that takes some info from the command line and runs it 793 * forward and backward through the above conversion routines. 794 */ 795 #include <msg.h> 796 #include <vstream.h> 797 #include <msg_vstream.h> 798 799 int main(int argc, char **argv) 800 { 801 struct addrinfo *info; 802 struct addrinfo *ip; 803 MAI_HOSTNAME_STR host; 804 MAI_HOSTADDR_STR addr; 805 int err; 806 807 msg_vstream_init(argv[0], VSTREAM_ERR); 808 809 if (argc != 4) 810 msg_fatal("usage: %s protocols hostname hostaddress", argv[0]); 811 812 inet_proto_init(argv[0], argv[1]); 813 814 msg_info("=== hostname %s ===", argv[2]); 815 816 if ((err = hostname_to_sockaddr(argv[2], (char *) 0, 0, &info)) != 0) { 817 msg_info("hostname_to_sockaddr(%s): %s", 818 argv[2], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); 819 } else { 820 for (ip = info; ip != 0; ip = ip->ai_next) { 821 if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr, 822 (MAI_SERVPORT_STR *) 0, 0)) != 0) { 823 msg_info("sockaddr_to_hostaddr: %s", 824 err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); 825 continue; 826 } 827 msg_info("%s -> family=%d sock=%d proto=%d %s", argv[2], 828 ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf); 829 if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host, 830 (MAI_SERVNAME_STR *) 0, 0)) != 0) { 831 msg_info("sockaddr_to_hostname: %s", 832 err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); 833 continue; 834 } 835 msg_info("%s -> %s", addr.buf, host.buf); 836 } 837 freeaddrinfo(info); 838 } 839 840 msg_info("=== host address %s ===", argv[3]); 841 842 if ((err = hostaddr_to_sockaddr(argv[3], (char *) 0, 0, &ip)) != 0) { 843 msg_info("hostaddr_to_sockaddr(%s): %s", 844 argv[3], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); 845 } else { 846 if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr, 847 (MAI_SERVPORT_STR *) 0, 0)) != 0) { 848 msg_info("sockaddr_to_hostaddr: %s", 849 err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); 850 } else { 851 msg_info("%s -> family=%d sock=%d proto=%d %s", argv[3], 852 ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf); 853 if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host, 854 (MAI_SERVNAME_STR *) 0, 0)) != 0) { 855 msg_info("sockaddr_to_hostname: %s", 856 err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); 857 } else 858 msg_info("%s -> %s", addr.buf, host.buf); 859 freeaddrinfo(ip); 860 } 861 } 862 exit(0); 863 } 864 865 #endif 866