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