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