aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2018-05-08 15:53:40 +0000
committerHåvard Pettersen <havardpe@oath.com>2018-05-09 13:02:59 +0000
commit4e953d4813d3384eaf4761f4930b36036b0dda21 (patch)
treefd4d012f7ea51138bb4d99d35006bf90acceba31 /vespalib
parent57e7ff91fdb1a319087ced1748a05de159556024 (diff)
added tools to detect and validate hostname
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/CMakeLists.txt2
-rw-r--r--vespalib/src/apps/vespa-detect-hostname/.gitignore1
-rw-r--r--vespalib/src/apps/vespa-detect-hostname/CMakeLists.txt9
-rw-r--r--vespalib/src/apps/vespa-detect-hostname/detect_hostname.cpp50
-rw-r--r--vespalib/src/apps/vespa-validate-hostname/.gitignore1
-rw-r--r--vespalib/src/apps/vespa-validate-hostname/CMakeLists.txt9
-rw-r--r--vespalib/src/apps/vespa-validate-hostname/validate_hostname.cpp70
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_address.cpp58
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_address.h3
9 files changed, 203 insertions, 0 deletions
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt
index 40d0c539c86..33553da9422 100644
--- a/vespalib/CMakeLists.txt
+++ b/vespalib/CMakeLists.txt
@@ -10,6 +10,8 @@ vespa_define_module(
APPS
src/apps/make_fixture_macros
+ src/apps/vespa-detect-hostname
+ src/apps/vespa-validate-hostname
TESTS
src/tests/alignedmemory
diff --git a/vespalib/src/apps/vespa-detect-hostname/.gitignore b/vespalib/src/apps/vespa-detect-hostname/.gitignore
new file mode 100644
index 00000000000..d1570fb3d89
--- /dev/null
+++ b/vespalib/src/apps/vespa-detect-hostname/.gitignore
@@ -0,0 +1 @@
+/vespa-detect-hostname
diff --git a/vespalib/src/apps/vespa-detect-hostname/CMakeLists.txt b/vespalib/src/apps/vespa-detect-hostname/CMakeLists.txt
new file mode 100644
index 00000000000..51d2ba3b0b0
--- /dev/null
+++ b/vespalib/src/apps/vespa-detect-hostname/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_vespa-detect-hostname_app
+ SOURCES
+ detect_hostname.cpp
+ OUTPUT_NAME vespa-detect-hostname
+ INSTALL bin
+ DEPENDS
+ vespalib
+)
diff --git a/vespalib/src/apps/vespa-detect-hostname/detect_hostname.cpp b/vespalib/src/apps/vespa-detect-hostname/detect_hostname.cpp
new file mode 100644
index 00000000000..a1387c6519d
--- /dev/null
+++ b/vespalib/src/apps/vespa-detect-hostname/detect_hostname.cpp
@@ -0,0 +1,50 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vespa/vespalib/net/socket_address.h>
+#include <vespa/vespalib/stllike/string.h>
+#include <set>
+
+using vespalib::SocketAddress;
+
+std::set<vespalib::string> make_ip_set() {
+ std::set<vespalib::string> result;
+ for (const auto &addr: SocketAddress::get_interfaces()) {
+ result.insert(addr.ip_address());
+ }
+ return result;
+}
+
+vespalib::string get_hostname() {
+ std::vector<char> result(4096, '\0');
+ gethostname(&result[0], 4000);
+ return SocketAddress::normalize(&result[0]);
+}
+
+bool check(const vespalib::string &name, const std::set<vespalib::string> &ip_set) {
+ auto addr_list = SocketAddress::resolve(80, name.c_str());
+ if (addr_list.empty()) {
+ return false;
+ }
+ for (const SocketAddress &addr: addr_list) {
+ vespalib::string ip_addr = addr.ip_address();
+ if (ip_set.count(ip_addr) == 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+int main(int, char **) {
+ auto my_ip_set = make_ip_set();
+ std::vector<vespalib::string> list({get_hostname(), "localhost", "127.0.0.1", "::1"});
+ for (const vespalib::string &name: list) {
+ if (check(name, my_ip_set)) {
+ fprintf(stdout, "%s\n", name.c_str());
+ return 0;
+ }
+ }
+ fprintf(stderr, "ERROR: failed to detect hostname\n");
+ return 1;
+}
diff --git a/vespalib/src/apps/vespa-validate-hostname/.gitignore b/vespalib/src/apps/vespa-validate-hostname/.gitignore
new file mode 100644
index 00000000000..9d95e867f73
--- /dev/null
+++ b/vespalib/src/apps/vespa-validate-hostname/.gitignore
@@ -0,0 +1 @@
+/vespa-validate-hostname
diff --git a/vespalib/src/apps/vespa-validate-hostname/CMakeLists.txt b/vespalib/src/apps/vespa-validate-hostname/CMakeLists.txt
new file mode 100644
index 00000000000..7ffa7d763ec
--- /dev/null
+++ b/vespalib/src/apps/vespa-validate-hostname/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_vespa-validate-hostname_app
+ SOURCES
+ validate_hostname.cpp
+ OUTPUT_NAME vespa-validate-hostname
+ INSTALL bin
+ DEPENDS
+ vespalib
+)
diff --git a/vespalib/src/apps/vespa-validate-hostname/validate_hostname.cpp b/vespalib/src/apps/vespa-validate-hostname/validate_hostname.cpp
new file mode 100644
index 00000000000..da4907d4c91
--- /dev/null
+++ b/vespalib/src/apps/vespa-validate-hostname/validate_hostname.cpp
@@ -0,0 +1,70 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vespa/vespalib/net/socket_address.h>
+#include <vespa/vespalib/stllike/string.h>
+#include <set>
+
+using vespalib::SocketAddress;
+
+std::set<vespalib::string> make_ip_set() {
+ std::set<vespalib::string> result;
+ for (const auto &addr: SocketAddress::get_interfaces()) {
+ result.insert(addr.ip_address());
+ }
+ return result;
+}
+
+vespalib::string normalize(const vespalib::string &hostname) {
+ vespalib::string canon_name = SocketAddress::normalize(hostname);
+ if (canon_name != hostname) {
+ fprintf(stderr, "warning: host name (%s) is not canonical (canonical host name: %s)\n",
+ hostname.c_str(), canon_name.c_str());
+ }
+ return canon_name;
+}
+
+void check_reverse(const vespalib::string &hostname, const SocketAddress &addr) {
+ std::set<vespalib::string> seen({hostname});
+ vespalib::string reverse = addr.reverse_lookup();
+ for (size_t i = 0; !reverse.empty() && (i < 10); ++i) {
+ if (seen.count(reverse) == 0) {
+ seen.insert(reverse);
+ fprintf(stderr, "warning: conflicting reverse lookup: %s->%s->%s\n",
+ hostname.c_str(), addr.ip_address().c_str(), reverse.c_str());
+ }
+ reverse = addr.reverse_lookup();
+ }
+}
+
+int usage(const char *self) {
+ fprintf(stderr, "usage: %s <hostname>\n", self);
+ return 1;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ return usage(argv[0]);
+ }
+ bool valid = true;
+ auto my_ip_set = make_ip_set();
+ vespalib::string hostname = normalize(argv[1]);
+ auto addr_list = SocketAddress::resolve(80, hostname.c_str());
+ if (addr_list.empty()) {
+ valid = false;
+ fprintf(stderr, "ERROR: host name (%s) could not be resolved\n",
+ hostname.c_str());
+ }
+ for (const SocketAddress &addr: addr_list) {
+ vespalib::string ip_addr = addr.ip_address();
+ if (my_ip_set.count(ip_addr) == 0) {
+ valid = false;
+ fprintf(stderr, "ERROR: host name (%s) resolves to ip address not owned by this host (%s)\n",
+ hostname.c_str(), ip_addr.c_str());
+ } else {
+ check_reverse(hostname, addr);
+ }
+ }
+ return valid ? 0 : 1;
+}
diff --git a/vespalib/src/vespa/vespalib/net/socket_address.cpp b/vespalib/src/vespa/vespalib/net/socket_address.cpp
index 8f1d903daa6..d71441b0989 100644
--- a/vespalib/src/vespa/vespalib/net/socket_address.cpp
+++ b/vespalib/src/vespa/vespalib/net/socket_address.cpp
@@ -5,6 +5,7 @@
#include <sys/types.h>
#include <sys/un.h>
#include <arpa/inet.h>
+#include <ifaddrs.h>
#include <netdb.h>
#include <cassert>
@@ -14,6 +15,18 @@ namespace {
const in6_addr ipv6_wildcard = IN6ADDR_ANY_INIT;
+socklen_t get_ip_addr_size(const sockaddr *addr) {
+ if (addr != nullptr) {
+ if (addr->sa_family == AF_INET) {
+ return sizeof(sockaddr_in);
+ }
+ if (addr->sa_family == AF_INET6) {
+ return sizeof(sockaddr_in6);
+ }
+ }
+ return 0;
+}
+
} // namespace vespalib::<unnamed>
bool
@@ -55,6 +68,14 @@ SocketAddress::ip_address() const
}
vespalib::string
+SocketAddress::reverse_lookup() const
+{
+ std::vector<char> result(4096, '\0');
+ getnameinfo(addr(), _size, &result[0], 4000, nullptr, 0, NI_NAMEREQD);
+ return &result[0];
+}
+
+vespalib::string
SocketAddress::path() const
{
vespalib::string result;
@@ -250,4 +271,41 @@ SocketAddress::from_name(const vespalib::string &name)
return result;
}
+std::vector<SocketAddress>
+SocketAddress::get_interfaces()
+{
+ std::vector<SocketAddress> result;
+ ifaddrs *list = nullptr;
+ if (getifaddrs(&list) == 0) {
+ for (const ifaddrs *entry = list; entry != nullptr; entry = entry->ifa_next) {
+ socklen_t size = get_ip_addr_size(entry->ifa_addr);
+ if (size > 0) {
+ result.push_back(SocketAddress(entry->ifa_addr, size));
+ }
+ }
+ freeifaddrs(list);
+ }
+ return result;
+}
+
+vespalib::string
+SocketAddress::normalize(const vespalib::string &host_name)
+{
+ vespalib::string result = host_name;
+ addrinfo hints;
+ memset(&hints, 0, sizeof(addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ hints.ai_flags = (AI_CANONNAME);
+ addrinfo *list = nullptr;
+ if (getaddrinfo(host_name.c_str(), nullptr, &hints, &list) == 0) {
+ if ((list != nullptr) && (list->ai_canonname != nullptr)) {
+ result = list->ai_canonname;
+ }
+ freeaddrinfo(list);
+ }
+ return result;
+}
+
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/socket_address.h b/vespalib/src/vespa/vespalib/net/socket_address.h
index cc0958e7c63..5e706742e1f 100644
--- a/vespalib/src/vespa/vespalib/net/socket_address.h
+++ b/vespalib/src/vespa/vespalib/net/socket_address.h
@@ -43,6 +43,7 @@ public:
bool is_abstract() const;
int port() const;
vespalib::string ip_address() const;
+ vespalib::string reverse_lookup() const;
vespalib::string path() const;
vespalib::string name() const;
vespalib::string spec() const;
@@ -73,6 +74,8 @@ public:
}
static SocketAddress from_path(const vespalib::string &path);
static SocketAddress from_name(const vespalib::string &name);
+ static std::vector<SocketAddress> get_interfaces();
+ static vespalib::string normalize(const vespalib::string &host_name);
};
} // namespace vespalib