You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2022/09/23 01:01:56 UTC
[trafficserver] branch master updated: Support reverse lookups from the host file. (#9043)
This is an automated email from the ASF dual-hosted git repository.
maskit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 4c0600dc4 Support reverse lookups from the host file. (#9043)
4c0600dc4 is described below
commit 4c0600dc4f7e7222dead9e84a6b3af897930c44b
Author: Chris McFarlen <ch...@mcfarlen.us>
AuthorDate: Thu Sep 22 20:01:50 2022 -0500
Support reverse lookups from the host file. (#9043)
* Support reverse lookups from the host file.
Refactor host file code to make it more testable and unify lookups
Add unit test for HostFile
* More refactoring
* link libinkevent
* also link tscpputil
* use reverse map in intermediate parse data to use the file order for a stable view of the reverse map
Co-authored-by: Chris McFarlen <cm...@apple.com>
---
iocore/hostdb/HostDB.cc | 186 ++++----------------------------------
iocore/hostdb/HostDBInfo.cc | 84 +++++++++++++++++
iocore/hostdb/HostFile.cc | 150 ++++++++++++++++++++++++++++++
iocore/hostdb/HostFile.h | 51 +++++++++++
iocore/hostdb/Makefile.am | 23 ++++-
iocore/hostdb/P_HostDBProcessor.h | 25 +++--
iocore/hostdb/test_HostFile.cc | 164 +++++++++++++++++++++++++++++++++
7 files changed, 504 insertions(+), 179 deletions(-)
diff --git a/iocore/hostdb/HostDB.cc b/iocore/hostdb/HostDB.cc
index 7481d85a5..79c55bff2 100644
--- a/iocore/hostdb/HostDB.cc
+++ b/iocore/hostdb/HostDB.cc
@@ -29,6 +29,7 @@
#include "tscore/ts_file.h"
#include "tscore/ink_apidefs.h"
#include "tscore/bwf_std_format.h"
+#include "HostFile.h"
#include <utility>
#include <vector>
@@ -74,27 +75,6 @@ ClassAllocator<HostDBContinuation> hostDBContAllocator("hostDBContAllocator");
namespace
{
-/** Assign raw storage to an @c IpAddr
- *
- * @param ip Destination.
- * @param af IP family.
- * @param ptr Raw data for an address of family @a af.
- */
-void
-ip_addr_set(IpAddr &ip, ///< Target storage.
- uint8_t af, ///< Address format.
- void const *ptr ///< Raw address data
-)
-{
- if (AF_INET6 == af) {
- ip = *static_cast<in6_addr const *>(ptr);
- } else if (AF_INET == af) {
- ip = *static_cast<in_addr_t const *>(ptr);
- } else {
- ip.invalidate();
- }
-}
-
unsigned int
HOSTDB_CLIENT_IP_HASH(sockaddr const *lhs, IpAddr const &rhs)
{
@@ -222,41 +202,7 @@ HostDB_Config_Init()
HostDBCache hostDB;
-void ParseHostFile(ts::file::path const &path, ts_seconds interval);
-
-auto
-HostDBInfo::assign(sa_family_t af, void const *addr) -> self_type &
-{
- type = HostDBType::ADDR;
- ip_addr_set(data.ip, af, addr);
- return *this;
-}
-
-auto
-HostDBInfo::assign(IpAddr const &addr) -> self_type &
-{
- type = HostDBType::ADDR;
- data.ip = addr;
- return *this;
-}
-
-auto
-HostDBInfo::assign(SRV const *srv, char const *name) -> self_type &
-{
- type = HostDBType::SRV;
- data.srv.srv_weight = srv->weight;
- data.srv.srv_priority = srv->priority;
- data.srv.srv_port = srv->port;
- data.srv.key = srv->key;
- data.srv.srv_offset = reinterpret_cast<char const *>(this) - name;
- return *this;
-}
-
-char const *
-HostDBInfo::srvname() const
-{
- return data.srv.srv_offset ? reinterpret_cast<char const *>(this) + data.srv.srv_offset : nullptr;
-}
+void UpdateHostsFile(ts::file::path const &path, ts_seconds interval);
static inline bool
is_addr_valid(uint8_t af, ///< Address family (format of data)
@@ -363,8 +309,6 @@ HostDBHash::refresh()
ctx.finalize(hash);
}
-HostDBHash::HostDBHash() {}
-
HostDBHash::~HostDBHash()
{
if (pSD) {
@@ -386,7 +330,7 @@ HostDBCache::is_pending_dns_for_hash(const CryptoHash &hash)
return false;
}
-std::shared_ptr<HostFileMap>
+std::shared_ptr<HostFile>
HostDBCache::acquire_host_file()
{
std::shared_lock lock(host_file_mutex);
@@ -1467,21 +1411,16 @@ HostDBContinuation::do_dns()
hostdb_cont_free(this);
return;
}
+ }
- // If looking for an IPv4 or IPv6 address, check the host file.
- if (hash.db_mark == HOSTDB_MARK_IPV6 || hash.db_mark == HOSTDB_MARK_IPV4) {
- if (auto static_hosts = hostDB.acquire_host_file(); static_hosts) {
- if (auto spot = static_hosts->find(hash.host_name); spot != static_hosts->end()) {
- HostDBRecord::Handle r = (hash.db_mark == HOSTDB_MARK_IPV4) ? spot->second.record_4 : spot->second.record_6;
- // Set the TTL based on how often we stat() the host file
- if (r && action.continuation) {
- r = lookup_done(hash.host_name, hostdb_hostfile_check_interval, nullptr, r);
- reply_to_cont(action.continuation, r.get());
- hostdb_cont_free(this);
- return;
- }
- }
- }
+ // Check if this can be fulfilled by the host file
+ if (auto static_hosts = hostDB.acquire_host_file(); static_hosts) {
+ if (auto r = static_hosts->lookup(hash); r && action.continuation) {
+ // Set the TTL based on how often we stat() the host file
+ r = lookup_done(hash.host_name, static_hosts->ttl, nullptr, r);
+ reply_to_cont(action.continuation, r.get());
+ hostdb_cont_free(this);
+ return;
}
}
@@ -1566,7 +1505,7 @@ HostDBContinuation::backgroundEvent(int /* event ATS_UNUSED */, Event * /* e ATS
}
if (update_p) {
Debug("hostdb", "%s", ts::bwprint(dbg, R"(Updating from host file "{}")", hostdb_hostfile_path).c_str());
- ParseHostFile(hostdb_hostfile_path, hostdb_hostfile_check_interval);
+ UpdateHostsFile(hostdb_hostfile_path, hostdb_hostfile_check_interval);
}
}
@@ -1994,13 +1933,6 @@ ink_hostdb_init(ts::ModuleVersion v)
ts_host_res_global_init();
}
-/// Pair of IP address and host name from a host file.
-struct HostFilePair {
- using self = HostFilePair;
- IpAddr ip;
- const char *name;
-};
-
struct HostDBFileContinuation : public Continuation {
using self = HostDBFileContinuation;
using Keys = std::vector<CryptoHash>;
@@ -2035,106 +1967,24 @@ HostDBFileContinuation::destroy()
// globals.
std::atomic<bool> HostDBFileUpdateActive{false};
-/* Container for temporarily holding data from the host file. For each FQDN there is a vector of IPv4
- * and IPv6 addresses. These are used to generate the HostDBRecord instances that are stored persistently.
- */
-using HostAddrMap = std::unordered_map<std::string_view, std::tuple<std::vector<IpAddr>, std::vector<IpAddr>>>;
-
-namespace
-{
-constexpr unsigned IPV4_IDX = 0;
-constexpr unsigned IPV6_IDX = 1;
-} // namespace
-
-static void
-ParseHostLine(TextView line, HostAddrMap &map)
-{
- // Elements should be the address then a list of host names.
- TextView addr_text = line.take_prefix_if(&isspace);
- IpAddr addr;
-
- // Don't use RecHttpLoadIp because the address *must* be literal.
- if (TS_SUCCESS != addr.load(addr_text)) {
- return;
- }
-
- while (!line.ltrim_if(&isspace).empty()) {
- TextView name = line.take_prefix_if(&isspace);
- if (addr.isIp6()) {
- std::get<IPV6_IDX>(map[name]).push_back(addr);
- } else if (addr.isIp4()) {
- std::get<IPV4_IDX>(map[name]).push_back(addr);
- }
- }
-}
-
void
-ParseHostFile(ts::file::path const &path, ts_seconds hostdb_hostfile_check_interval_parse)
+UpdateHostsFile(ts::file::path const &path, ts_seconds interval)
{
- std::shared_ptr<HostFileMap> map;
-
// Test and set for update in progress.
bool flag = false;
if (!HostDBFileUpdateActive.compare_exchange_strong(flag, true)) {
Debug("hostdb", "Skipped load of host file because update already in progress");
return;
}
- Debug_bw("hostdb", R"(Loading host file "{}")", path);
-
- if (!path.empty()) {
- std::error_code ec;
- std::string content = ts::file::load(path, ec);
- if (!ec) {
- HostAddrMap addr_map;
- TextView text{content};
- while (text) {
- auto line = text.take_prefix_at('\n').ltrim_if(&isspace);
- if (line.empty() || '#' == *line) {
- continue;
- }
- ParseHostLine(line, addr_map);
- }
- // @a map should be loaded with all of the data, create the records.
- map = std::make_shared<HostFileMap>();
- // Common loading function for creating a record from the address vector.
- auto loader = [](TextView key, std::vector<IpAddr> const &v) -> HostDBRecord::Handle {
- HostDBRecord::Handle record{HostDBRecord::alloc(key, v.size())};
- record->af_family = v.front().family(); // @a v is presumed family homogenous
- auto rr_info = record->rr_info();
- auto spot = v.begin();
- for (auto &item : rr_info) {
- item.assign(*spot++);
- }
- return record;
- };
- // Walk the temporary map and create the corresponding records for the persistent map.
- for (auto const &[key, value] : addr_map) {
- // Bit of subtlety to be able to search records with a view and not a string - the key
- // must point at stable memory for the name, which is available in the record itself.
- // Therefore the lookup for adding the record must be done using a view based in the record.
- // It doesn't matter if it's the IPv4 or IPv6 record that's used, both are stable and equal
- // to each other.
- // IPv4
- if (auto const &v = std::get<IPV4_IDX>(value); v.size() > 0) {
- auto r = loader(key, v);
- (*map)[r->name_view()].record_4 = r;
- }
- // IPv6
- if (auto const &v = std::get<IPV6_IDX>(value); v.size() > 0) {
- auto r = loader(key, v);
- (*map)[r->name_view()].record_6 = r;
- }
- }
- hostdb_hostfile_update_timestamp = hostdb_current_timestamp;
- }
- }
+ std::shared_ptr<HostFile> hf = ParseHostFile(path, interval);
// Swap the pointer
- if (map) {
+ if (hf) {
std::unique_lock lock(hostDB.host_file_mutex);
- hostDB.host_file = map;
+ hostDB.host_file = hf;
}
+ hostdb_hostfile_update_timestamp = hostdb_current_timestamp;
// Mark this one as completed, so we can allow another update to happen
HostDBFileUpdateActive = false;
}
diff --git a/iocore/hostdb/HostDBInfo.cc b/iocore/hostdb/HostDBInfo.cc
new file mode 100644
index 000000000..4a4388ff6
--- /dev/null
+++ b/iocore/hostdb/HostDBInfo.cc
@@ -0,0 +1,84 @@
+/** @file
+
+ HostDBInfo implementation
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include <sys/socket.h>
+
+#include "I_HostDBProcessor.h"
+
+namespace
+{
+/** Assign raw storage to an @c IpAddr
+ *
+ * @param ip Destination.
+ * @param af IP family.
+ * @param ptr Raw data for an address of family @a af.
+ */
+void
+ip_addr_set(IpAddr &ip, ///< Target storage.
+ uint8_t af, ///< Address format.
+ void const *ptr ///< Raw address data
+)
+{
+ if (AF_INET6 == af) {
+ ip = *static_cast<in6_addr const *>(ptr);
+ } else if (AF_INET == af) {
+ ip = *static_cast<in_addr_t const *>(ptr);
+ } else {
+ ip.invalidate();
+ }
+}
+} // namespace
+
+auto
+HostDBInfo::assign(sa_family_t af, void const *addr) -> self_type &
+{
+ type = HostDBType::ADDR;
+ ip_addr_set(data.ip, af, addr);
+ return *this;
+}
+
+auto
+HostDBInfo::assign(IpAddr const &addr) -> self_type &
+{
+ type = HostDBType::ADDR;
+ data.ip = addr;
+ return *this;
+}
+
+auto
+HostDBInfo::assign(SRV const *srv, char const *name) -> self_type &
+{
+ type = HostDBType::SRV;
+ data.srv.srv_weight = srv->weight;
+ data.srv.srv_priority = srv->priority;
+ data.srv.srv_port = srv->port;
+ data.srv.key = srv->key;
+ data.srv.srv_offset = reinterpret_cast<char const *>(this) - name;
+ return *this;
+}
+
+char const *
+HostDBInfo::srvname() const
+{
+ return data.srv.srv_offset ? reinterpret_cast<char const *>(this) + data.srv.srv_offset : nullptr;
+}
diff --git a/iocore/hostdb/HostFile.cc b/iocore/hostdb/HostFile.cc
new file mode 100644
index 000000000..42af0c26f
--- /dev/null
+++ b/iocore/hostdb/HostFile.cc
@@ -0,0 +1,150 @@
+/** @file
+
+ HostFile class for processing a hosts file
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "HostFile.h"
+#include "P_HostDBProcessor.h"
+
+/* Container for temporarily holding data from the host file. For each FQDN there is a vector of IPv4
+ * and IPv6 addresses. These are used to generate the HostDBRecord instances that are stored persistently.
+ */
+using HostAddrMap = std::unordered_map<std::string_view, std::tuple<std::vector<IpAddr>, std::vector<IpAddr>>>;
+using AddrHostMap = std::unordered_map<IpAddr, std::string_view, IpAddr::Hasher>;
+
+namespace
+{
+constexpr unsigned IPV4_IDX = 0;
+constexpr unsigned IPV6_IDX = 1;
+} // namespace
+
+static void
+ParseHostLine(ts::TextView line, HostAddrMap &map, AddrHostMap &rmap)
+{
+ // Elements should be the address then a list of host names.
+ ts::TextView addr_text = line.take_prefix_if(&isspace);
+ IpAddr addr;
+
+ // Don't use RecHttpLoadIp because the address *must* be literal.
+ if (TS_SUCCESS != addr.load(addr_text)) {
+ return;
+ }
+
+ while (!line.ltrim_if(&isspace).empty()) {
+ ts::TextView name = line.take_prefix_if(&isspace);
+ if (addr.isIp6()) {
+ std::get<IPV6_IDX>(map[name]).push_back(addr);
+ } else if (addr.isIp4()) {
+ std::get<IPV4_IDX>(map[name]).push_back(addr);
+ }
+ // use insert here so only the first mapping in the file is used to provide a stable view between reloads
+ rmap.insert(std::pair(addr, name));
+ }
+}
+
+HostDBRecord::Handle
+HostFile::lookup(const HostDBHash &hash)
+{
+ HostDBRecord::Handle result;
+
+ // If looking for an IPv4 or IPv6 address, check the host file.
+ if (hash.db_mark == HOSTDB_MARK_IPV6 || hash.db_mark == HOSTDB_MARK_IPV4) {
+ if (auto spot = forward.find(hash.host_name); spot != forward.end()) {
+ result = (hash.db_mark == HOSTDB_MARK_IPV4) ? spot->second.record_4 : spot->second.record_6;
+ }
+ } else if (hash.db_mark != HOSTDB_MARK_SRV) {
+ if (auto spot = reverse.find(hash.ip); spot != reverse.end()) {
+ result = spot->second;
+ }
+ }
+
+ return result;
+}
+
+std::shared_ptr<HostFile>
+ParseHostFile(ts::file::path const &path, ts_seconds interval)
+{
+ std::shared_ptr<HostFile> hf;
+
+ Debug_bw("hostdb", R"(Loading host file "{}")", path);
+
+ if (!path.empty()) {
+ std::error_code ec;
+ std::string content = ts::file::load(path, ec);
+ if (!ec) {
+ HostAddrMap addr_map;
+ AddrHostMap host_map;
+ ts::TextView text{content};
+ while (text) {
+ auto line = text.take_prefix_at('\n').ltrim_if(&isspace);
+ if (line.empty() || '#' == *line) {
+ continue;
+ }
+ ParseHostLine(line, addr_map, host_map);
+ }
+ // @a map should be loaded with all of the data, create the records.
+ hf = std::make_shared<HostFile>(interval);
+ // Common loading function for creating a record from the address vector.
+ auto loader = [](ts::TextView key, std::vector<IpAddr> const &v) -> HostDBRecord::Handle {
+ HostDBRecord::Handle record{HostDBRecord::alloc(key, v.size())};
+ record->af_family = v.front().family(); // @a v is presumed family homogenous
+ auto rr_info = record->rr_info();
+ auto spot = v.begin();
+ for (auto &item : rr_info) {
+ item.assign(*spot++);
+ }
+ return record;
+ };
+ // Walk the temporary map and create the corresponding records for the persistent map.
+ for (auto const &[key, value] : addr_map) {
+ // Bit of subtlety to be able to search records with a view and not a string - the key
+ // must point at stable memory for the name, which is available in the record itself.
+ // Therefore the lookup for adding the record must be done using a view based in the record.
+ // It doesn't matter if it's the IPv4 or IPv6 record that's used, both are stable and equal
+ // to each other.
+ // IPv4
+ if (auto const &v = std::get<IPV4_IDX>(value); v.size() > 0) {
+ auto r = loader(key, v);
+ hf->forward[r->name_view()].record_4 = r;
+ }
+ // IPv6
+ if (auto const &v = std::get<IPV6_IDX>(value); v.size() > 0) {
+ auto r = loader(key, v);
+ hf->forward[r->name_view()].record_6 = r;
+ }
+ }
+
+ // Walk the temporary reverse map and create the reverse index.
+ for (auto const &[ip, host] : host_map) {
+ auto lup = hf->forward.find(host);
+ if (lup != hf->forward.end()) {
+ if (ip.isIp4()) {
+ hf->reverse[ip] = lup->second.record_4;
+ } else {
+ hf->reverse[ip] = lup->second.record_6;
+ }
+ }
+ }
+ }
+ }
+
+ return hf;
+}
diff --git a/iocore/hostdb/HostFile.h b/iocore/hostdb/HostFile.h
new file mode 100644
index 000000000..48a614f08
--- /dev/null
+++ b/iocore/hostdb/HostFile.h
@@ -0,0 +1,51 @@
+/** @file
+
+ HostFile class for processing a hosts file
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#pragma once
+
+#include "I_HostDBProcessor.h"
+#include "tscpp/util/TextView.h"
+#include "tscore/ts_file.h"
+
+#include <memory>
+#include <unordered_map>
+
+struct HostFileRecord {
+ HostDBRecord::Handle record_4;
+ HostDBRecord::Handle record_6;
+};
+
+struct HostFile {
+ using HostFileForwardMap = std::unordered_map<ts::TextView, HostFileRecord, std::hash<std::string_view>>;
+ using HostFileReverseMap = std::unordered_map<IpAddr, HostDBRecord::Handle, IpAddr::Hasher>;
+
+ HostFile(ts_seconds ttl) : ttl(ttl) {}
+
+ HostDBRecord::Handle lookup(const HostDBHash &hash);
+
+ ts_seconds ttl;
+ HostFileForwardMap forward;
+ HostFileReverseMap reverse;
+};
+
+std::shared_ptr<HostFile> ParseHostFile(ts::file::path const &path, ts_seconds interval);
diff --git a/iocore/hostdb/Makefile.am b/iocore/hostdb/Makefile.am
index e0391d759..681c0988d 100644
--- a/iocore/hostdb/Makefile.am
+++ b/iocore/hostdb/Makefile.am
@@ -40,10 +40,13 @@ libinkhostdb_a_SOURCES = \
P_HostDBProcessor.h \
P_RefCountCache.h \
P_RefCountCacheSerializer.h \
- RefCountCache.cc
+ RefCountCache.cc \
+ HostFile.h \
+ HostFile.cc \
+ HostDBInfo.cc
TESTS = $(check_PROGRAMS)
-check_PROGRAMS = test_RefCountCache
+check_PROGRAMS = test_RefCountCache test_HostFile
test_RefCountCache_SOURCES = \
test_RefCountCache.cc
@@ -82,6 +85,22 @@ test_RefCountCache_LDFLAGS = $(test_LD_FLAGS)
test_RefCountCache_LDADD = $(test_LD_ADD)
+test_HostFile_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(abs_top_srcdir)/tests/include \
+ -I$(abs_top_srcdir)/proxy/http/remap
+
+test_HostFile_LDADD = \
+ $(top_builddir)/src/tscore/libtscore.la \
+ $(top_builddir)/src/tscpp/util/libtscpputil.la \
+ $(top_builddir)/iocore/eventsystem/libinkevent.a
+
+test_HostFile_SOURCES = \
+ test_HostFile.cc \
+ HostFile.h \
+ HostFile.cc \
+ HostDBInfo.cc
+
include $(top_srcdir)/build/tidy.mk
clang-tidy-local: $(DIST_SOURCES)
diff --git a/iocore/hostdb/P_HostDBProcessor.h b/iocore/hostdb/P_HostDBProcessor.h
index a373a08a5..4549496cd 100644
--- a/iocore/hostdb/P_HostDBProcessor.h
+++ b/iocore/hostdb/P_HostDBProcessor.h
@@ -28,9 +28,12 @@
#pragma once
#include <shared_mutex>
+#include <unordered_map>
#include "I_HostDBProcessor.h"
+#include "P_RefCountCache.h"
#include "tscore/TsBuffer.h"
+#include "tscore/ts_file.h"
//
// Data
@@ -152,12 +155,7 @@ extern RecRawStatBlock *hostdb_rsb;
#define HOSTDB_DECREMENT_THREAD_DYN_STAT(_s, _t) RecIncrRawStatSum(hostdb_rsb, _t, (int)_s, -1);
-struct HostFileRecord {
- HostDBRecord::Handle record_4;
- HostDBRecord::Handle record_6;
-};
-
-using HostFileMap = std::unordered_map<ts::TextView, HostFileRecord, std::hash<std::string_view>>;
+struct HostFile;
//
// HostDBCache (Private)
@@ -165,7 +163,7 @@ using HostFileMap = std::unordered_map<ts::TextView, HostFileRecord, std::hash<s
struct HostDBCache {
int start(int flags = 0);
// Map to contain all of the host file overrides, initialize it to empty
- std::shared_ptr<HostFileMap> host_file;
+ std::shared_ptr<HostFile> host_file;
std::shared_mutex host_file_mutex;
// TODO: make ATS call a close() method or something on shutdown (it does nothing of the sort today)
@@ -178,13 +176,16 @@ struct HostDBCache {
HostDBCache();
bool is_pending_dns_for_hash(const CryptoHash &hash);
- std::shared_ptr<HostFileMap> acquire_host_file();
+ std::shared_ptr<HostFile> acquire_host_file();
};
//
// Types
//
+struct DNSServer;
+struct SplitDNS;
+
/** Container for a hash and its dependent data.
This handles both the host name and raw address cases.
*/
@@ -204,7 +205,7 @@ struct HostDBHash {
HostDBMark db_mark = HOSTDB_MARK_GENERIC; ///< Mark / type of record.
/// Default constructor.
- HostDBHash();
+ HostDBHash() = default;
/// Destructor.
~HostDBHash();
/// Recompute and update the hash.
@@ -274,6 +275,12 @@ struct HostDBContinuation : public Continuation {
return hash.db_mark == HOSTDB_MARK_SRV;
}
+ bool
+ is_reverse()
+ {
+ return !is_byname() && !is_srv();
+ }
+
Ptr<HostDBRecord>
lookup_done(const char *query_name, ts_seconds answer_ttl, SRVHosts *s = nullptr, Ptr<HostDBRecord> record = Ptr<HostDBRecord>{})
{
diff --git a/iocore/hostdb/test_HostFile.cc b/iocore/hostdb/test_HostFile.cc
new file mode 100644
index 000000000..4e1d61783
--- /dev/null
+++ b/iocore/hostdb/test_HostFile.cc
@@ -0,0 +1,164 @@
+/** @file
+
+ Test HostFile
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include "HostFile.h"
+#include "P_HostDBProcessor.h"
+
+const std::string_view hosts_data = "127.0.0.1 localhost\n::1 localhost\n1.2.3.4 host1\n4.3.2.1 host2 host3\n"_sv;
+
+void
+spit(const ts::file::path &p, std::string_view data)
+{
+ std::ofstream f(p.c_str(), std::ios::trunc);
+ f.write(data.data(), data.size());
+ f.close();
+}
+
+TEST_CASE("HostFile", "[hostdb]")
+{
+ auto tmp = ts::file::temp_directory_path();
+ ts::LocalBufferWriter<1024> w;
+ w.print("{}/localhost.{}", tmp, ::getpid());
+
+ auto hostfilepath = ts::file::path(w.view());
+
+ spit(hostfilepath, hosts_data);
+
+ auto hf = ParseHostFile(hostfilepath, ts_seconds(3600));
+
+ REQUIRE(hf);
+
+ SECTION("reverse lookup localhost v4")
+ {
+ HostDBHash h;
+ h.ip.load("127.0.0.1");
+ h.db_mark = HOSTDB_MARK_GENERIC;
+
+ auto result = hf->lookup(h);
+
+ REQUIRE(result);
+ REQUIRE(result->name_view() == "localhost");
+ }
+
+ SECTION("reverse lookup localhost v6")
+ {
+ HostDBHash h;
+ h.ip.load("::1");
+ h.db_mark = HOSTDB_MARK_GENERIC;
+
+ auto result = hf->lookup(h);
+
+ REQUIRE(result);
+ REQUIRE(result->name_view() == "localhost");
+ }
+
+ SECTION("reverse lookup host v4")
+ {
+ HostDBHash h;
+ h.ip.load("4.3.2.1");
+ h.db_mark = HOSTDB_MARK_GENERIC;
+
+ auto result = hf->lookup(h);
+
+ REQUIRE(result);
+ REQUIRE(result->name_view() == "host2");
+ }
+
+ SECTION("forward lookup localhost v4")
+ {
+ HostDBHash h;
+ h.host_name = "localhost"_sv;
+ h.db_mark = HOSTDB_MARK_IPV4;
+
+ auto result = hf->lookup(h);
+
+ REQUIRE(result);
+ REQUIRE(result->name_view() == h.host_name);
+ }
+
+ SECTION("forward lookup localhost v6")
+ {
+ HostDBHash h;
+ h.host_name = "localhost"_sv;
+ h.db_mark = HOSTDB_MARK_IPV6;
+
+ auto result = hf->lookup(h);
+
+ REQUIRE(result);
+ REQUIRE(result->name_view() == h.host_name);
+ }
+
+ SECTION("forward lookup host v6")
+ {
+ HostDBHash h;
+ h.host_name = "host1"_sv;
+ h.db_mark = HOSTDB_MARK_IPV4;
+
+ auto result = hf->lookup(h);
+
+ REQUIRE(result);
+ REQUIRE(result->name_view() == h.host_name);
+ }
+}
+
+// NOTE(cmcfarlen): need this destructor defined so we don't have to link in the entire project for this test
+HostDBHash::~HostDBHash() {}
+
+#include "tscore/Scalar.h"
+
+HostDBRecord *
+HostDBRecord::alloc(ts::TextView query_name, unsigned int rr_count, size_t srv_name_size)
+{
+ const ts::Scalar<8> qn_size = ts::round_up(query_name.size() + 1);
+ const ts::Scalar<8> r_size = ts::round_up(sizeof(self_type) + qn_size + rr_count * sizeof(HostDBInfo) + srv_name_size);
+ auto ptr = malloc(r_size);
+ memset(ptr, 0, r_size);
+ auto self = static_cast<self_type *>(ptr);
+ new (self) self_type();
+ self->_iobuffer_index = 0;
+ self->_record_size = r_size;
+
+ Debug("hostdb", "allocating %ld bytes for %.*s with %d RR records at [%p]", r_size.value(), int(query_name.size()),
+ query_name.data(), rr_count, self);
+
+ // where in our block of memory we are
+ int offset = sizeof(self_type);
+ memcpy(self->apply_offset<void>(offset), query_name);
+ offset += qn_size;
+ self->rr_offset = offset;
+ self->rr_count = rr_count;
+ // Construct the info instances to a valid state.
+ for (auto &info : self->rr_info()) {
+ new (&info) std::remove_reference_t<decltype(info)>;
+ }
+
+ return self;
+}
+
+void
+HostDBRecord::free()
+{
+}