diff options
Diffstat (limited to 'vespalib')
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 |