1 /* $NetBSD: inet_addr_host.c,v 1.1.1.1 2009/06/23 10:09:00 tron 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 39 /* System library. */ 40 41 #include <sys_defs.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 #include <sys/socket.h> 45 #include <netdb.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 /* Utility library. */ 51 52 #include <mymalloc.h> 53 #include <inet_addr_list.h> 54 #include <inet_addr_host.h> 55 #include <myaddrinfo.h> 56 #include <sock_addr.h> 57 #include <inet_proto.h> 58 #include <msg.h> 59 60 /* inet_addr_host - look up address list for host */ 61 62 int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname) 63 { 64 const char *myname = "inet_addr_host"; 65 int sock; 66 struct addrinfo *res0; 67 struct addrinfo *res; 68 int aierr; 69 ssize_t hostnamelen; 70 const char *hname; 71 const char *serv; 72 int initial_count = addr_list->used; 73 INET_PROTO_INFO *proto_info; 74 75 /* 76 * The use of square brackets around an IPv6 addresses is required, even 77 * though we don't enforce it as it'd make the code unnecessarily 78 * complicated. 79 * 80 * XXX AIX 5.1 getaddrinfo() does not allow "0" as service, regardless of 81 * whether or not a host is specified. 82 */ 83 if (*hostname == 0) { 84 hname = 0; 85 serv = "1"; 86 } else if (*hostname == '[' 87 && hostname[(hostnamelen = strlen(hostname)) - 1] == ']') { 88 hname = mystrndup(hostname + 1, hostnamelen - 2); 89 serv = 0; 90 } else { 91 hname = hostname; 92 serv = 0; 93 } 94 95 proto_info = inet_proto_info(); 96 if ((aierr = hostname_to_sockaddr(hname, serv, SOCK_STREAM, &res0)) == 0) { 97 for (res = res0; res; res = res->ai_next) { 98 99 /* 100 * Safety net. 101 */ 102 if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { 103 msg_info("%s: skipping address family %d for host \"%s\"", 104 myname, res->ai_family, hostname); 105 continue; 106 } 107 108 /* 109 * On Linux systems it is not unusual for user-land to be out of 110 * sync with kernel-land. When this is the case we try to be 111 * helpful and filter out address families that the library 112 * claims to understand but that are not supported by the kernel. 113 */ 114 if ((sock = socket(res->ai_family, SOCK_STREAM, 0)) < 0) { 115 msg_warn("%s: skipping address family %d: %m", 116 myname, res->ai_family); 117 continue; 118 } 119 if (close(sock)) 120 msg_warn("%s: close socket: %m", myname); 121 122 inet_addr_list_append(addr_list, res->ai_addr); 123 } 124 freeaddrinfo(res0); 125 } 126 if (hname && hname != hostname) 127 myfree((char *) hname); 128 129 return (addr_list->used - initial_count); 130 } 131 132 #ifdef TEST 133 134 #include <msg.h> 135 #include <vstream.h> 136 #include <msg_vstream.h> 137 #include <sock_addr.h> 138 139 int main(int argc, char **argv) 140 { 141 INET_ADDR_LIST list; 142 struct sockaddr_storage *sa; 143 MAI_HOSTADDR_STR hostaddr; 144 INET_PROTO_INFO *proto_info; 145 146 msg_vstream_init(argv[0], VSTREAM_ERR); 147 148 if (argc < 3) 149 msg_fatal("usage: %s protocols hostname...", argv[0]); 150 151 proto_info = inet_proto_init(argv[0], argv[1]); 152 argv += 1; 153 154 while (--argc && *++argv) { 155 inet_addr_list_init(&list); 156 if (inet_addr_host(&list, *argv) == 0) 157 msg_fatal("not found: %s", *argv); 158 159 for (sa = list.addrs; sa < list.addrs + list.used; sa++) { 160 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa), 161 &hostaddr, (MAI_SERVPORT_STR *) 0, 0); 162 vstream_printf("%s\t%s\n", *argv, hostaddr.buf); 163 } 164 vstream_fflush(VSTREAM_OUT); 165 inet_addr_list_free(&list); 166 } 167 return (0); 168 } 169 170 #endif 171