1/* $NetBSD: inet_addr_host.c,v 1.3 2022/10/08 16:12:50 christos Exp $ */ 2 3/*++ 4/* NAME 5/* inet_addr_host 3 6/* SUMMARY 7/* determine all host internet interface addresses 8/* SYNOPSIS 9/* #include <inet_addr_host.h> 10/* 11/* int inet_addr_host(addr_list, hostname) 12/* INET_ADDR_LIST *addr_list; 13/* const char *hostname; 14/* DESCRIPTION 15/* inet_addr_host() determines all interface addresses of the 16/* named host. The host may be specified as a symbolic name, 17/* or as a numerical address. An empty host expands as the 18/* wild-card address. Address results are appended to 19/* the specified address list. The result value is the number 20/* of addresses appended to the list. 21/* DIAGNOSTICS 22/* Fatal errors: out of memory. 23/* BUGS 24/* This code uses the name service, so it talks to the network, 25/* and that may not be desirable. 26/* SEE ALSO 27/* inet_addr_list(3) address list management 28/* LICENSE 29/* .ad 30/* .fi 31/* The Secure Mailer license must be distributed with this software. 32/* AUTHOR(S) 33/* Wietse Venema 34/* IBM T.J. Watson Research 35/* P.O. Box 704 36/* Yorktown Heights, NY 10598, USA 37/* 38/* Wietse Venema 39/* Google, Inc. 40/* 111 8th Avenue 41/* New York, NY 10011, USA 42/*--*/ 43 44/* System library. */ 45 46#include <sys_defs.h> 47#include <netinet/in.h> 48#include <arpa/inet.h> 49#include <sys/socket.h> 50#include <netdb.h> 51#include <stdlib.h> 52#include <string.h> 53#include <unistd.h> 54 55/* Utility library. */ 56 57#include <mymalloc.h> 58#include <inet_addr_list.h> 59#include <inet_addr_host.h> 60#include <myaddrinfo.h> 61#include <sock_addr.h> 62#include <inet_proto.h> 63#include <msg.h> 64 65/* inet_addr_host - look up address list for host */ 66 67int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname) 68{ 69 const char *myname = "inet_addr_host"; 70 int sock; 71 struct addrinfo *res0; 72 struct addrinfo *res; 73 int aierr; 74 ssize_t hostnamelen; 75 const char *hname; 76 const char *serv; 77 int initial_count = addr_list->used; 78 const INET_PROTO_INFO *proto_info; 79 80 /* 81 * The use of square brackets around an IPv6 addresses is required, even 82 * though we don't enforce it as it'd make the code unnecessarily 83 * complicated. 84 * 85 * XXX AIX 5.1 getaddrinfo() does not allow "0" as service, regardless of 86 * whether or not a host is specified. 87 */ 88 if (*hostname == 0) { 89 hname = 0; 90 serv = "1"; 91 } else if (*hostname == '[' 92 && hostname[(hostnamelen = strlen(hostname)) - 1] == ']') { 93 hname = mystrndup(hostname + 1, hostnamelen - 2); 94 serv = 0; 95 } else { 96 hname = hostname; 97 serv = 0; 98 } 99 100 proto_info = inet_proto_info(); 101 if ((aierr = hostname_to_sockaddr(hname, serv, SOCK_STREAM, &res0)) == 0) { 102 for (res = res0; res; res = res->ai_next) { 103 104 /* 105 * Safety net. 106 */ 107 if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { 108 msg_info("%s: skipping address family %d for host \"%s\"", 109 myname, res->ai_family, hostname); 110 continue; 111 } 112 113 /* 114 * On Linux systems it is not unusual for user-land to be out of 115 * sync with kernel-land. When this is the case we try to be 116 * helpful and filter out address families that the library 117 * claims to understand but that are not supported by the kernel. 118 */ 119 if ((sock = socket(res->ai_family, SOCK_STREAM, 0)) < 0) { 120 msg_warn("%s: skipping address family %d: %m", 121 myname, res->ai_family); 122 continue; 123 } 124 if (close(sock)) 125 msg_warn("%s: close socket: %m", myname); 126 127 inet_addr_list_append(addr_list, res->ai_addr); 128 } 129 freeaddrinfo(res0); 130 } 131 if (hname && hname != hostname) 132 myfree((void *) hname); 133 134 return (addr_list->used - initial_count); 135} 136 137#ifdef TEST 138 139#include <msg.h> 140#include <vstream.h> 141#include <msg_vstream.h> 142#include <sock_addr.h> 143 144int main(int argc, char **argv) 145{ 146 INET_ADDR_LIST list; 147 struct sockaddr_storage *sa; 148 MAI_HOSTADDR_STR hostaddr; 149 INET_PROTO_INFO *proto_info; 150 151 msg_vstream_init(argv[0], VSTREAM_ERR); 152 153 if (argc < 3) 154 msg_fatal("usage: %s protocols hostname...", argv[0]); 155 156 proto_info = inet_proto_init(argv[0], argv[1]); 157 argv += 1; 158 159 while (--argc && *++argv) { 160 inet_addr_list_init(&list); 161 if (inet_addr_host(&list, *argv) == 0) 162 msg_fatal("not found: %s", *argv); 163 164 for (sa = list.addrs; sa < list.addrs + list.used; sa++) { 165 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa), 166 &hostaddr, (MAI_SERVPORT_STR *) 0, 0); 167 vstream_printf("%s\t%s\n", *argv, hostaddr.buf); 168 } 169 vstream_fflush(VSTREAM_OUT); 170 inet_addr_list_free(&list); 171 } 172 return (0); 173} 174 175#endif 176