mirror of
https://github.com/matrix-construct/construct
synced 2024-05-29 00:03:45 +02:00
ircd: Split all non-matrix definitions back to lib; rename module to net_dns_cache.
This commit is contained in:
parent
9e3c9be5a8
commit
2b2374db6c
|
@ -18,6 +18,7 @@
|
|||
///
|
||||
namespace ircd::net::dns
|
||||
{
|
||||
struct init;
|
||||
struct opts;
|
||||
using records = vector_view<const rfc1035::record *>;
|
||||
using callback = std::function<void (const hostport &, const json::array &)>;
|
||||
|
@ -106,3 +107,9 @@ namespace ircd::net::dns::cache
|
|||
bool put(const hostport &, const opts &, const records &);
|
||||
bool put(const hostport &, const opts &, const uint &code, const string_view &msg = {});
|
||||
}
|
||||
|
||||
/// (internal)
|
||||
struct ircd::net::dns::init
|
||||
{
|
||||
init(), ~init() noexcept;
|
||||
};
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
//
|
||||
// This file is not included in any include group. It is used when
|
||||
// implementing the dns::cache by modules and extensions.
|
||||
//
|
||||
|
||||
namespace ircd::net::dns::cache
|
||||
{
|
||||
struct waiter;
|
||||
|
||||
bool operator==(const waiter &, const waiter &);
|
||||
bool operator!=(const waiter &, const waiter &);
|
||||
|
||||
void fini();
|
||||
void init();
|
||||
bool operator==(const waiter &, const waiter &) noexcept;
|
||||
bool operator!=(const waiter &, const waiter &) noexcept;
|
||||
|
||||
extern std::list<waiter> waiting;
|
||||
extern ctx::mutex mutex;
|
|
@ -25,8 +25,6 @@ namespace ircd::net::dns
|
|||
constexpr const size_t MAX_COUNT {64};
|
||||
|
||||
uint16_t resolver_call(const hostport &, const opts &);
|
||||
void resolver_init(answers_callback);
|
||||
void resolver_fini();
|
||||
}
|
||||
|
||||
struct ircd::net::dns::resolver
|
||||
|
|
|
@ -147,6 +147,8 @@ libircd_la_SOURCES += db_port.cc
|
|||
libircd_la_SOURCES += db_env.cc
|
||||
libircd_la_SOURCES += db.cc
|
||||
libircd_la_SOURCES += net.cc
|
||||
libircd_la_SOURCES += net_dns.cc
|
||||
libircd_la_SOURCES += net_dns_cache.cc
|
||||
libircd_la_SOURCES += net_dns_resolver.cc
|
||||
libircd_la_SOURCES += server.cc
|
||||
libircd_la_SOURCES += client.cc
|
||||
|
@ -194,6 +196,8 @@ magic.lo: AM_CPPFLAGS := @MAGIC_CPPFLAGS@ ${AM_CPPFLAGS}
|
|||
endif
|
||||
mods.lo: AM_CPPFLAGS := ${ASIO_UNIT_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
net.lo: AM_CPPFLAGS := ${ASIO_UNIT_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
net_dns.lo: AM_CPPFLAGS := ${ASIO_UNIT_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
net_cache.lo: AM_CPPFLAGS := ${ASIO_UNIT_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
net_dns_resolver.lo: AM_CPPFLAGS := ${ASIO_UNIT_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
openssl.lo: AM_CPPFLAGS := @SSL_CPPFLAGS@ @CRYPTO_CPPFLAGS@ ${AM_CPPFLAGS}
|
||||
parse.lo: AM_CPPFLAGS := ${SPIRIT_UNIT_CPPFLAGS} ${AM_CPPFLAGS}
|
||||
|
|
380
ircd/net.cc
380
ircd/net.cc
|
@ -13,6 +13,7 @@
|
|||
namespace ircd::net
|
||||
{
|
||||
ctx::dock dock;
|
||||
std::optional<dns::init> _dns_;
|
||||
|
||||
static void init_ipv6();
|
||||
static void wait_close_sockets();
|
||||
|
@ -69,19 +70,17 @@ ircd::net::init_ipv6()
|
|||
/// Network subsystem initialization
|
||||
ircd::net::init::init()
|
||||
{
|
||||
//TODO: XXX this has to be instantiated in libircd before other loaded
|
||||
//TODO: modules like s_dns.so; otherwise dynamic linker issues.
|
||||
const asio::ip::udp::socket _dummy_udp_ {ios::get()};
|
||||
|
||||
init_ipv6();
|
||||
sslv23_client.set_verify_mode(asio::ssl::verify_peer);
|
||||
sslv23_client.set_default_verify_paths();
|
||||
_dns_.emplace();
|
||||
}
|
||||
|
||||
/// Network subsystem shutdown
|
||||
ircd::net::init::~init()
|
||||
noexcept
|
||||
{
|
||||
_dns_.reset();
|
||||
wait_close_sockets();
|
||||
}
|
||||
|
||||
|
@ -4190,379 +4189,6 @@ const
|
|||
return *ssl.native_handle();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// net/dns.h
|
||||
//
|
||||
|
||||
decltype(ircd::net::dns::log)
|
||||
ircd::net::dns::log
|
||||
{
|
||||
"net.dns"
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::min_ttl)
|
||||
ircd::net::dns::cache::min_ttl
|
||||
{
|
||||
{ "name", "ircd.net.dns.cache.min_ttl" },
|
||||
{ "default", 28800L },
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::error_ttl)
|
||||
ircd::net::dns::cache::error_ttl
|
||||
{
|
||||
{ "name", "ircd.net.dns.cache.error_ttl" },
|
||||
{ "default", 1200L },
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::nxdomain_ttl)
|
||||
ircd::net::dns::cache::nxdomain_ttl
|
||||
{
|
||||
{ "name", "ircd.net.dns.cache.nxdomain_ttl" },
|
||||
{ "default", 86400L },
|
||||
};
|
||||
|
||||
/// Linkage for default opts
|
||||
decltype(ircd::net::dns::opts_default)
|
||||
ircd::net::dns::opts_default;
|
||||
|
||||
void
|
||||
ircd::net::dns::resolve(const hostport &hp,
|
||||
const opts &op,
|
||||
callback_ipport cb)
|
||||
{
|
||||
using prototype = void (const hostport &, const opts &, callback_ipport);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::resolve"
|
||||
};
|
||||
|
||||
call(hp, op, std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::dns::resolve(const hostport &hp,
|
||||
const opts &op,
|
||||
callback_one cb)
|
||||
{
|
||||
using prototype = void (const hostport &, const opts &, callback_one);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::resolve"
|
||||
};
|
||||
|
||||
call(hp, op, std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::dns::resolve(const hostport &hp,
|
||||
const opts &op,
|
||||
callback cb)
|
||||
{
|
||||
using prototype = void (const hostport &, const opts &, callback);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::resolve"
|
||||
};
|
||||
|
||||
call(hp, op, std::move(cb));
|
||||
}
|
||||
|
||||
/// Really assumptional and hacky right now. We're just assuming the SRV
|
||||
/// key is the first two elements of a dot-delimited string which start
|
||||
/// with underscores. If that isn't good enough in the future this will rot
|
||||
/// and become a regression hazard.
|
||||
ircd::string_view
|
||||
ircd::net::dns::unmake_SRV_key(const string_view &key)
|
||||
{
|
||||
if(token_count(key, '.') < 3)
|
||||
return key;
|
||||
|
||||
if(!startswith(token(key, '.', 0), '_'))
|
||||
return key;
|
||||
|
||||
if(!startswith(token(key, '.', 1), '_'))
|
||||
return key;
|
||||
|
||||
return tokens_after(key, '.', 1);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::dns::make_SRV_key(const mutable_buffer &out,
|
||||
const hostport &hp,
|
||||
const opts &opts)
|
||||
{
|
||||
thread_local char tlbuf[2][rfc1035::NAME_BUFSIZE];
|
||||
|
||||
if(!opts.srv)
|
||||
return fmt::sprintf
|
||||
{
|
||||
out, "_%s._%s.%s",
|
||||
tolower(tlbuf[0], service(hp)),
|
||||
opts.proto,
|
||||
tolower(tlbuf[1], host(hp)),
|
||||
};
|
||||
else
|
||||
return fmt::sprintf
|
||||
{
|
||||
out, "%s%s",
|
||||
opts.srv,
|
||||
tolower(tlbuf[1], host(hp))
|
||||
};
|
||||
}
|
||||
|
||||
ircd::json::object
|
||||
ircd::net::dns::random_choice(const json::array &rrs)
|
||||
{
|
||||
const size_t &count
|
||||
{
|
||||
rrs.size()
|
||||
};
|
||||
|
||||
if(!count)
|
||||
return json::object{};
|
||||
|
||||
const auto choice
|
||||
{
|
||||
rand::integer(0, count - 1)
|
||||
};
|
||||
|
||||
assert(choice < count);
|
||||
const json::object &rr
|
||||
{
|
||||
rrs[choice]
|
||||
};
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::expired(const json::object &rr,
|
||||
const time_t &rr_ts)
|
||||
{
|
||||
const seconds &min_seconds
|
||||
{
|
||||
cache::min_ttl
|
||||
};
|
||||
|
||||
const seconds &err_seconds
|
||||
{
|
||||
cache::error_ttl
|
||||
};
|
||||
|
||||
const time_t &min
|
||||
{
|
||||
is_error(rr)?
|
||||
err_seconds.count():
|
||||
min_seconds.count()
|
||||
};
|
||||
|
||||
return expired(rr, rr_ts, min);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::expired(const json::object &rr,
|
||||
const time_t &rr_ts,
|
||||
const time_t &min_ttl)
|
||||
{
|
||||
const auto &ttl
|
||||
{
|
||||
get_ttl(rr)
|
||||
};
|
||||
|
||||
return rr_ts + std::max(ttl, min_ttl) < ircd::time();
|
||||
}
|
||||
|
||||
time_t
|
||||
ircd::net::dns::get_ttl(const json::object &rr)
|
||||
{
|
||||
return rr.get<time_t>("ttl", 0L);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_empty(const json::array &rrs)
|
||||
{
|
||||
return std::all_of(begin(rrs), end(rrs), []
|
||||
(const json::object &rr)
|
||||
{
|
||||
return is_empty(rr);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_empty(const json::object &rr)
|
||||
{
|
||||
return empty(rr) || (rr.has("ttl") && size(rr) == 1);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_error(const json::array &rrs)
|
||||
{
|
||||
return !std::none_of(begin(rrs), end(rrs), []
|
||||
(const json::object &rr)
|
||||
{
|
||||
return is_error(rr);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_error(const json::object &rr)
|
||||
{
|
||||
return rr.has("error");
|
||||
}
|
||||
|
||||
//
|
||||
// cache
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::put(const hostport &h,
|
||||
const opts &o,
|
||||
const uint &r,
|
||||
const string_view &m)
|
||||
try
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const uint &, const string_view &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::cache::put"
|
||||
};
|
||||
|
||||
return call(h, o, r, m);
|
||||
}
|
||||
catch(const mods::unavailable &e)
|
||||
{
|
||||
thread_local char buf[rfc1035::NAME_BUFSIZE];
|
||||
log::dwarning
|
||||
{
|
||||
log, "Failed to put error for '%s' in DNS cache :%s",
|
||||
string(buf, h),
|
||||
e.what()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::put(const hostport &h,
|
||||
const opts &o,
|
||||
const records &r)
|
||||
try
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const records &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::cache::put"
|
||||
};
|
||||
|
||||
return call(h, o, r);
|
||||
}
|
||||
catch(const mods::unavailable &e)
|
||||
{
|
||||
thread_local char buf[rfc1035::NAME_BUFSIZE];
|
||||
log::dwarning
|
||||
{
|
||||
log, "Failed to put '%s' in DNS cache :%s",
|
||||
string(buf, h),
|
||||
e.what()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This function has an opportunity to respond from the DNS cache. If it
|
||||
/// returns true, that indicates it responded by calling back the user and
|
||||
/// nothing further should be done for them. If it returns false, that
|
||||
/// indicates it did not respond and to proceed normally. The response can
|
||||
/// be of a cached successful result, or a cached error. Both will return
|
||||
/// true.
|
||||
bool
|
||||
ircd::net::dns::cache::get(const hostport &h,
|
||||
const opts &o,
|
||||
const callback &c)
|
||||
try
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const callback &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::cache::get"
|
||||
};
|
||||
|
||||
return call(h, o, c);
|
||||
}
|
||||
catch(const mods::unavailable &e)
|
||||
{
|
||||
thread_local char buf[rfc1035::NAME_BUFSIZE];
|
||||
log::dwarning
|
||||
{
|
||||
log, "Failed to get '%s' from DNS cache :%s",
|
||||
string(buf, h),
|
||||
e.what()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::for_each(const hostport &h,
|
||||
const opts &o,
|
||||
const closure &c)
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const closure &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::cache::for_each"
|
||||
};
|
||||
|
||||
return call(h, o, c);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::for_each(const string_view &type,
|
||||
const closure &c)
|
||||
{
|
||||
using prototype = bool (const string_view &, const closure &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns", "ircd::net::dns::cache::for_each"
|
||||
};
|
||||
|
||||
return call(type, c);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::dns::cache::make_type(const mutable_buffer &out,
|
||||
const uint16_t &type)
|
||||
try
|
||||
{
|
||||
return make_type(out, rfc1035::rqtype.at(type));
|
||||
}
|
||||
catch(const std::out_of_range &)
|
||||
{
|
||||
throw error
|
||||
{
|
||||
"Record type[%u] is not recognized", type
|
||||
};
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::dns::cache::make_type(const mutable_buffer &out,
|
||||
const string_view &type)
|
||||
{
|
||||
return fmt::sprintf
|
||||
{
|
||||
out, "ircd.dns.rrs.%s", type
|
||||
};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// net/ipport.h
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#include "net_dns.h"
|
||||
#include <ircd/net/dns_cache.h>
|
||||
|
||||
namespace ircd::net::dns
|
||||
{
|
||||
|
@ -18,35 +18,42 @@ namespace ircd::net::dns
|
|||
static void handle_resolve_A_ipport(const hostport &, const json::object &rr, opts, uint16_t, callback_ipport);
|
||||
static void handle_resolve_SRV_ipport(const hostport &, const json::object &rr, opts, callback_ipport);
|
||||
static void handle_resolve_one(const hostport &, const json::array &rr, callback_one);
|
||||
|
||||
static void fini();
|
||||
static void init();
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
decltype(ircd::net::dns::log)
|
||||
ircd::net::dns::log
|
||||
{
|
||||
"Domain Name System Client, Cache & Components",
|
||||
ircd::net::dns::init,
|
||||
ircd::net::dns::fini,
|
||||
"net.dns"
|
||||
};
|
||||
|
||||
void
|
||||
ircd::net::dns::init()
|
||||
decltype(ircd::net::dns::opts_default)
|
||||
ircd::net::dns::opts_default;
|
||||
|
||||
//
|
||||
// init
|
||||
//
|
||||
|
||||
ircd::net::dns::init::init()
|
||||
{
|
||||
cache::init();
|
||||
resolver_init(handle_resolved);
|
||||
assert(!resolver_instance);
|
||||
resolver_instance = new resolver
|
||||
{
|
||||
handle_resolved
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::dns::fini()
|
||||
ircd::net::dns::init::~init()
|
||||
noexcept
|
||||
{
|
||||
cache::fini();
|
||||
resolver_fini();
|
||||
delete resolver_instance;
|
||||
resolver_instance = nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// net/dns.h
|
||||
//
|
||||
|
||||
void
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::net::dns::resolve(const hostport &hp,
|
||||
const opts &opts_,
|
||||
callback_ipport callback)
|
||||
|
@ -86,7 +93,6 @@ ircd::net::dns::resolve(const hostport &hp,
|
|||
}
|
||||
|
||||
void
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::net::dns::resolve(const hostport &hp,
|
||||
const opts &opts,
|
||||
callback_one callback)
|
||||
|
@ -106,7 +112,6 @@ ircd::net::dns::resolve(const hostport &hp,
|
|||
}
|
||||
|
||||
void
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::net::dns::resolve(const hostport &hp,
|
||||
const opts &opts,
|
||||
callback cb)
|
||||
|
@ -142,6 +147,153 @@ ircd::net::dns::resolve(const hostport &hp,
|
|||
resolver_call(hp, opts);
|
||||
}
|
||||
|
||||
/// Really assumptional and hacky right now. We're just assuming the SRV
|
||||
/// key is the first two elements of a dot-delimited string which start
|
||||
/// with underscores. If that isn't good enough in the future this will rot
|
||||
/// and become a regression hazard.
|
||||
ircd::string_view
|
||||
ircd::net::dns::unmake_SRV_key(const string_view &key)
|
||||
{
|
||||
if(token_count(key, '.') < 3)
|
||||
return key;
|
||||
|
||||
if(!startswith(token(key, '.', 0), '_'))
|
||||
return key;
|
||||
|
||||
if(!startswith(token(key, '.', 1), '_'))
|
||||
return key;
|
||||
|
||||
return tokens_after(key, '.', 1);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::dns::make_SRV_key(const mutable_buffer &out,
|
||||
const hostport &hp,
|
||||
const opts &opts)
|
||||
{
|
||||
thread_local char tlbuf[2][rfc1035::NAME_BUFSIZE];
|
||||
|
||||
if(!opts.srv)
|
||||
return fmt::sprintf
|
||||
{
|
||||
out, "_%s._%s.%s",
|
||||
tolower(tlbuf[0], service(hp)),
|
||||
opts.proto,
|
||||
tolower(tlbuf[1], host(hp)),
|
||||
};
|
||||
else
|
||||
return fmt::sprintf
|
||||
{
|
||||
out, "%s%s",
|
||||
opts.srv,
|
||||
tolower(tlbuf[1], host(hp))
|
||||
};
|
||||
}
|
||||
|
||||
ircd::json::object
|
||||
ircd::net::dns::random_choice(const json::array &rrs)
|
||||
{
|
||||
const size_t &count
|
||||
{
|
||||
rrs.size()
|
||||
};
|
||||
|
||||
if(!count)
|
||||
return json::object{};
|
||||
|
||||
const auto choice
|
||||
{
|
||||
rand::integer(0, count - 1)
|
||||
};
|
||||
|
||||
assert(choice < count);
|
||||
const json::object &rr
|
||||
{
|
||||
rrs[choice]
|
||||
};
|
||||
|
||||
return rr;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::expired(const json::object &rr,
|
||||
const time_t &rr_ts)
|
||||
{
|
||||
const seconds &min_seconds
|
||||
{
|
||||
cache::min_ttl
|
||||
};
|
||||
|
||||
const seconds &err_seconds
|
||||
{
|
||||
cache::error_ttl
|
||||
};
|
||||
|
||||
const time_t &min
|
||||
{
|
||||
is_error(rr)?
|
||||
err_seconds.count():
|
||||
min_seconds.count()
|
||||
};
|
||||
|
||||
return expired(rr, rr_ts, min);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::expired(const json::object &rr,
|
||||
const time_t &rr_ts,
|
||||
const time_t &min_ttl)
|
||||
{
|
||||
const auto &ttl
|
||||
{
|
||||
get_ttl(rr)
|
||||
};
|
||||
|
||||
return rr_ts + std::max(ttl, min_ttl) < ircd::time();
|
||||
}
|
||||
|
||||
time_t
|
||||
ircd::net::dns::get_ttl(const json::object &rr)
|
||||
{
|
||||
return rr.get<time_t>("ttl", 0L);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_empty(const json::array &rrs)
|
||||
{
|
||||
return std::all_of(begin(rrs), end(rrs), []
|
||||
(const json::object &rr)
|
||||
{
|
||||
return is_empty(rr);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_empty(const json::object &rr)
|
||||
{
|
||||
return empty(rr) || (rr.has("ttl") && size(rr) == 1);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_error(const json::array &rrs)
|
||||
{
|
||||
return !std::none_of(begin(rrs), end(rrs), []
|
||||
(const json::object &rr)
|
||||
{
|
||||
return is_error(rr);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::is_error(const json::object &rr)
|
||||
{
|
||||
return rr.has("error");
|
||||
}
|
||||
|
||||
//
|
||||
// internal
|
||||
//
|
||||
|
||||
void
|
||||
ircd::net::dns::handle_resolve_one(const hostport &hp,
|
||||
const json::array &rrs,
|
238
ircd/net_dns_cache.cc
Normal file
238
ircd/net_dns_cache.cc
Normal file
|
@ -0,0 +1,238 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#include <ircd/net/dns_cache.h>
|
||||
|
||||
decltype(ircd::net::dns::cache::min_ttl)
|
||||
ircd::net::dns::cache::min_ttl
|
||||
{
|
||||
{ "name", "ircd.net.dns.cache.min_ttl" },
|
||||
{ "default", 28800L },
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::error_ttl)
|
||||
ircd::net::dns::cache::error_ttl
|
||||
{
|
||||
{ "name", "ircd.net.dns.cache.error_ttl" },
|
||||
{ "default", 1200L },
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::nxdomain_ttl)
|
||||
ircd::net::dns::cache::nxdomain_ttl
|
||||
{
|
||||
{ "name", "ircd.net.dns.cache.nxdomain_ttl" },
|
||||
{ "default", 86400L },
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::waiting)
|
||||
ircd::net::dns::cache::waiting;
|
||||
|
||||
decltype(ircd::net::dns::cache::mutex)
|
||||
ircd::net::dns::cache::mutex;
|
||||
|
||||
decltype(ircd::net::dns::cache::dock)
|
||||
ircd::net::dns::cache::dock;
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::put(const hostport &h,
|
||||
const opts &o,
|
||||
const uint &r,
|
||||
const string_view &m)
|
||||
try
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const uint &, const string_view &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns_cache", "ircd::net::dns::cache::put"
|
||||
};
|
||||
|
||||
return call(h, o, r, m);
|
||||
}
|
||||
catch(const mods::unavailable &e)
|
||||
{
|
||||
thread_local char buf[rfc1035::NAME_BUFSIZE];
|
||||
log::dwarning
|
||||
{
|
||||
log, "Failed to put error for '%s' in DNS cache :%s",
|
||||
string(buf, h),
|
||||
e.what()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::put(const hostport &h,
|
||||
const opts &o,
|
||||
const records &r)
|
||||
try
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const records &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns_cache", "ircd::net::dns::cache::put"
|
||||
};
|
||||
|
||||
return call(h, o, r);
|
||||
}
|
||||
catch(const mods::unavailable &e)
|
||||
{
|
||||
thread_local char buf[rfc1035::NAME_BUFSIZE];
|
||||
log::dwarning
|
||||
{
|
||||
log, "Failed to put '%s' in DNS cache :%s",
|
||||
string(buf, h),
|
||||
e.what()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This function has an opportunity to respond from the DNS cache. If it
|
||||
/// returns true, that indicates it responded by calling back the user and
|
||||
/// nothing further should be done for them. If it returns false, that
|
||||
/// indicates it did not respond and to proceed normally. The response can
|
||||
/// be of a cached successful result, or a cached error. Both will return
|
||||
/// true.
|
||||
bool
|
||||
ircd::net::dns::cache::get(const hostport &h,
|
||||
const opts &o,
|
||||
const callback &c)
|
||||
try
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const callback &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns_cache", "ircd::net::dns::cache::get"
|
||||
};
|
||||
|
||||
return call(h, o, c);
|
||||
}
|
||||
catch(const mods::unavailable &e)
|
||||
{
|
||||
thread_local char buf[rfc1035::NAME_BUFSIZE];
|
||||
log::dwarning
|
||||
{
|
||||
log, "Failed to get '%s' from DNS cache :%s",
|
||||
string(buf, h),
|
||||
e.what()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::for_each(const hostport &h,
|
||||
const opts &o,
|
||||
const closure &c)
|
||||
{
|
||||
using prototype = bool (const hostport &, const opts &, const closure &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns_cache", "ircd::net::dns::cache::for_each"
|
||||
};
|
||||
|
||||
return call(h, o, c);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::for_each(const string_view &type,
|
||||
const closure &c)
|
||||
{
|
||||
using prototype = bool (const string_view &, const closure &);
|
||||
|
||||
static mods::import<prototype> call
|
||||
{
|
||||
"net_dns_cache", "ircd::net::dns::cache::for_each"
|
||||
};
|
||||
|
||||
return call(type, c);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::dns::cache::make_type(const mutable_buffer &out,
|
||||
const uint16_t &type)
|
||||
try
|
||||
{
|
||||
return make_type(out, rfc1035::rqtype.at(type));
|
||||
}
|
||||
catch(const std::out_of_range &)
|
||||
{
|
||||
throw error
|
||||
{
|
||||
"Record type[%u] is not recognized", type
|
||||
};
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::dns::cache::make_type(const mutable_buffer &out,
|
||||
const string_view &type)
|
||||
{
|
||||
return fmt::sprintf
|
||||
{
|
||||
out, "ircd.dns.rrs.%s", type
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// cache::waiter
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::operator==(const waiter &a, const waiter &b)
|
||||
noexcept
|
||||
{
|
||||
return
|
||||
a.opts.qtype == b.opts.qtype &&
|
||||
a.key && b.key &&
|
||||
a.key == b.key;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::operator!=(const waiter &a, const waiter &b)
|
||||
noexcept
|
||||
{
|
||||
return !operator==(a, b);
|
||||
}
|
||||
|
||||
//
|
||||
// cache::waiter::waiter
|
||||
//
|
||||
|
||||
ircd::net::dns::cache::waiter::waiter(const hostport &hp,
|
||||
const dns::opts &opts,
|
||||
dns::callback &&callback)
|
||||
:callback
|
||||
{
|
||||
std::move(callback)
|
||||
}
|
||||
,opts
|
||||
{
|
||||
opts
|
||||
}
|
||||
,port
|
||||
{
|
||||
net::port(hp)
|
||||
}
|
||||
,key
|
||||
{
|
||||
opts.qtype == 33?
|
||||
make_SRV_key(keybuf, hp, opts):
|
||||
strlcpy(keybuf, host(hp))
|
||||
}
|
||||
{
|
||||
this->opts.srv = {};
|
||||
this->opts.proto = {};
|
||||
assert(this->opts.qtype);
|
||||
}
|
|
@ -56,23 +56,6 @@ ircd::net::dns::resolver::servers
|
|||
// interface
|
||||
//
|
||||
|
||||
void
|
||||
ircd::net::dns::resolver_init(answers_callback callback)
|
||||
{
|
||||
assert(!ircd::net::dns::resolver_instance);
|
||||
ircd::net::dns::resolver_instance = new resolver
|
||||
{
|
||||
std::move(callback)
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::dns::resolver_fini()
|
||||
{
|
||||
delete ircd::net::dns::resolver_instance;
|
||||
ircd::net::dns::resolver_instance = nullptr;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ircd::net::dns::resolver_call(const hostport &hp,
|
||||
const opts &opts)
|
||||
|
@ -84,7 +67,11 @@ ircd::net::dns::resolver_call(const hostport &hp,
|
|||
host(hp)
|
||||
};
|
||||
|
||||
auto &resolver{*dns::resolver_instance};
|
||||
auto &resolver
|
||||
{
|
||||
*dns::resolver_instance
|
||||
};
|
||||
|
||||
if(unlikely(!resolver.ns.is_open()))
|
||||
throw error
|
||||
{
|
||||
|
|
|
@ -237,7 +237,7 @@ ircd::m::homeserver::homeserver(const struct opts *const &opts)
|
|||
signon(*this);
|
||||
|
||||
if(primary == this)
|
||||
mods::imports.emplace("net_dns"s, "net_dns"s);
|
||||
mods::imports.emplace("net_dns_cache"s, "net_dns_cache"s);
|
||||
|
||||
if(primary == this)
|
||||
m::init::backfill::init();
|
||||
|
|
|
@ -221,7 +221,7 @@ noexcept try
|
|||
|
||||
_fetch.reset(nullptr);
|
||||
|
||||
mods::imports.erase("net_dns"s);
|
||||
mods::imports.erase("net_dns_cache"s);
|
||||
|
||||
//TODO: remove this for non-interfering shutdown
|
||||
//server::interrupt_all();
|
||||
|
|
|
@ -39,20 +39,16 @@ AM_LDFLAGS = \
|
|||
|
||||
moduledir = @moduledir@
|
||||
|
||||
net_dns_cache_la_SOURCES = net_dns_cache.cc
|
||||
stats_la_SOURCES = stats.cc
|
||||
net_dns_la_SOURCES = net_dns.cc net_dns_cache.cc
|
||||
net_dns_la_CPPFLAGS = -include $(top_srcdir)/include/ircd/asio.h
|
||||
net_dns_la_CPPFLAGS += $(AM_CPPFLAGS) @BOOST_CPPFLAGS@
|
||||
net_dns_la_LDFLAGS = $(AM_LDFLAGS) @BOOST_LDFLAGS@
|
||||
net_dns_la_LDFLAGS += -Wl,--no-gnu-unique
|
||||
console_la_SOURCES = console.cc
|
||||
web_root_la_SOURCES = web_root.cc
|
||||
web_hook_la_SOURCES = web_hook.cc
|
||||
well_known_la_SOURCES = well_known.cc
|
||||
|
||||
module_LTLIBRARIES = \
|
||||
net_dns_cache.la \
|
||||
stats.la \
|
||||
net_dns.la \
|
||||
console.la \
|
||||
web_root.la \
|
||||
web_hook.la \
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#include "net_dns.h"
|
||||
#include <ircd/net/dns_cache.h>
|
||||
|
||||
namespace ircd::net::dns::cache
|
||||
{
|
||||
|
@ -21,8 +21,18 @@ namespace ircd::net::dns::cache
|
|||
|
||||
extern const m::room::id::buf dns_room_id;
|
||||
extern m::hookfn<m::vm::eval &> hook;
|
||||
|
||||
static void init(), fini();
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"DNS cache using Matrix rooms.",
|
||||
ircd::net::dns::cache::init,
|
||||
ircd::net::dns::cache::fini,
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::dns_room_id)
|
||||
ircd::net::dns::cache::dns_room_id
|
||||
{
|
||||
|
@ -32,25 +42,21 @@ ircd::net::dns::cache::dns_room_id
|
|||
decltype(ircd::net::dns::cache::hook)
|
||||
ircd::net::dns::cache::hook
|
||||
{
|
||||
ircd::net::dns::cache::handle,
|
||||
{
|
||||
{ "_site", "vm.effect" },
|
||||
{ "room_id", string_view{dns_room_id} },
|
||||
}
|
||||
ircd::net::dns::cache::handle,
|
||||
{
|
||||
{ "_site", "vm.effect" },
|
||||
{ "room_id", string_view{dns_room_id} },
|
||||
}
|
||||
};
|
||||
|
||||
decltype(ircd::net::dns::cache::waiting)
|
||||
ircd::net::dns::cache::waiting;
|
||||
|
||||
decltype(ircd::net::dns::cache::mutex)
|
||||
ircd::net::dns::cache::mutex;
|
||||
|
||||
decltype(ircd::net::dns::cache::dock)
|
||||
ircd::net::dns::cache::dock;
|
||||
|
||||
void
|
||||
ircd::net::dns::cache::init()
|
||||
{
|
||||
log::debug
|
||||
{
|
||||
"DNS cache room %s currently set.",
|
||||
string_view{dns_room_id}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -623,55 +629,6 @@ catch(const std::exception &e)
|
|||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// cache::waiter
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::operator==(const waiter &a, const waiter &b)
|
||||
{
|
||||
return a.opts.qtype == b.opts.qtype &&
|
||||
a.key && b.key &&
|
||||
a.key == b.key;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::dns::cache::operator!=(const waiter &a, const waiter &b)
|
||||
{
|
||||
return !operator==(a, b);
|
||||
}
|
||||
|
||||
//
|
||||
// cache::waiter::waiter
|
||||
//
|
||||
|
||||
ircd::net::dns::cache::waiter::waiter(const hostport &hp,
|
||||
const dns::opts &opts,
|
||||
dns::callback &&callback)
|
||||
:callback
|
||||
{
|
||||
std::move(callback)
|
||||
}
|
||||
,opts
|
||||
{
|
||||
opts
|
||||
}
|
||||
,port
|
||||
{
|
||||
net::port(hp)
|
||||
}
|
||||
,key
|
||||
{
|
||||
opts.qtype == 33?
|
||||
make_SRV_key(keybuf, hp, opts):
|
||||
strlcpy(keybuf, host(hp))
|
||||
}
|
||||
{
|
||||
this->opts.srv = {};
|
||||
this->opts.proto = {};
|
||||
assert(this->opts.qtype);
|
||||
}
|
||||
|
||||
//
|
||||
// cache room creation
|
||||
//
|
||||
|
@ -691,6 +648,7 @@ ircd::net::dns::cache::create_room_hook
|
|||
{ "room_id", "!ircd" },
|
||||
{ "type", "m.room.create" },
|
||||
},
|
||||
|
||||
[](const m::event &, m::vm::eval &)
|
||||
{
|
||||
create_room();
|
||||
|
|
Loading…
Reference in a new issue