summaryrefslogtreecommitdiffstats
path: root/src/util/inet_addr_host.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/inet_addr_host.c')
-rw-r--r--src/util/inet_addr_host.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/util/inet_addr_host.c b/src/util/inet_addr_host.c
new file mode 100644
index 0000000..ea36385
--- /dev/null
+++ b/src/util/inet_addr_host.c
@@ -0,0 +1,168 @@
+/*++
+/* NAME
+/* inet_addr_host 3
+/* SUMMARY
+/* determine all host internet interface addresses
+/* SYNOPSIS
+/* #include <inet_addr_host.h>
+/*
+/* int inet_addr_host(addr_list, hostname)
+/* INET_ADDR_LIST *addr_list;
+/* const char *hostname;
+/* DESCRIPTION
+/* inet_addr_host() determines all interface addresses of the
+/* named host. The host may be specified as a symbolic name,
+/* or as a numerical address. An empty host expands as the
+/* wild-card address. Address results are appended to
+/* the specified address list. The result value is the number
+/* of addresses appended to the list.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory.
+/* BUGS
+/* This code uses the name service, so it talks to the network,
+/* and that may not be desirable.
+/* SEE ALSO
+/* inet_addr_list(3) address list management
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <inet_addr_list.h>
+#include <inet_addr_host.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <inet_proto.h>
+#include <msg.h>
+
+/* inet_addr_host - look up address list for host */
+
+int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname)
+{
+ const char *myname = "inet_addr_host";
+ int sock;
+ struct addrinfo *res0;
+ struct addrinfo *res;
+ int aierr;
+ ssize_t hostnamelen;
+ const char *hname;
+ const char *serv;
+ int initial_count = addr_list->used;
+ INET_PROTO_INFO *proto_info;
+
+ /*
+ * The use of square brackets around an IPv6 addresses is required, even
+ * though we don't enforce it as it'd make the code unnecessarily
+ * complicated.
+ *
+ * XXX AIX 5.1 getaddrinfo() does not allow "0" as service, regardless of
+ * whether or not a host is specified.
+ */
+ if (*hostname == 0) {
+ hname = 0;
+ serv = "1";
+ } else if (*hostname == '['
+ && hostname[(hostnamelen = strlen(hostname)) - 1] == ']') {
+ hname = mystrndup(hostname + 1, hostnamelen - 2);
+ serv = 0;
+ } else {
+ hname = hostname;
+ serv = 0;
+ }
+
+ proto_info = inet_proto_info();
+ if ((aierr = hostname_to_sockaddr(hname, serv, SOCK_STREAM, &res0)) == 0) {
+ for (res = res0; res; res = res->ai_next) {
+
+ /*
+ * Safety net.
+ */
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("%s: skipping address family %d for host \"%s\"",
+ myname, res->ai_family, hostname);
+ continue;
+ }
+
+ /*
+ * On Linux systems it is not unusual for user-land to be out of
+ * sync with kernel-land. When this is the case we try to be
+ * helpful and filter out address families that the library
+ * claims to understand but that are not supported by the kernel.
+ */
+ if ((sock = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
+ msg_warn("%s: skipping address family %d: %m",
+ myname, res->ai_family);
+ continue;
+ }
+ if (close(sock))
+ msg_warn("%s: close socket: %m", myname);
+
+ inet_addr_list_append(addr_list, res->ai_addr);
+ }
+ freeaddrinfo(res0);
+ }
+ if (hname && hname != hostname)
+ myfree((void *) hname);
+
+ return (addr_list->used - initial_count);
+}
+
+#ifdef TEST
+
+#include <msg.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+#include <sock_addr.h>
+
+int main(int argc, char **argv)
+{
+ INET_ADDR_LIST list;
+ struct sockaddr_storage *sa;
+ MAI_HOSTADDR_STR hostaddr;
+ INET_PROTO_INFO *proto_info;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+
+ if (argc < 3)
+ msg_fatal("usage: %s protocols hostname...", argv[0]);
+
+ proto_info = inet_proto_init(argv[0], argv[1]);
+ argv += 1;
+
+ while (--argc && *++argv) {
+ inet_addr_list_init(&list);
+ if (inet_addr_host(&list, *argv) == 0)
+ msg_fatal("not found: %s", *argv);
+
+ for (sa = list.addrs; sa < list.addrs + list.used; sa++) {
+ SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ vstream_printf("%s\t%s\n", *argv, hostaddr.buf);
+ }
+ vstream_fflush(VSTREAM_OUT);
+ inet_addr_list_free(&list);
+ }
+ return (0);
+}
+
+#endif