mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 08:12:37 +01:00
ircd::net::dns Include query in callback arguments to prevent any stale captures.
This commit is contained in:
parent
39ad36e3ed
commit
fb53069c6f
6 changed files with 76 additions and 68 deletions
|
@ -35,10 +35,10 @@ struct ircd::net::dns
|
|||
struct resolver static *resolver;
|
||||
struct opts static const opts_default;
|
||||
|
||||
using callback = std::function<void (std::exception_ptr, vector_view<const rfc1035::record *>)>;
|
||||
using callback_A_one = std::function<void (std::exception_ptr, const rfc1035::record::A &)>;
|
||||
using callback_SRV_one = std::function<void (std::exception_ptr, const rfc1035::record::SRV &)>;
|
||||
using callback_ipport_one = std::function<void (std::exception_ptr, const ipport &)>;
|
||||
using callback = std::function<void (std::exception_ptr, const hostport &, vector_view<const rfc1035::record *>)>;
|
||||
using callback_A_one = std::function<void (std::exception_ptr, const hostport &, const rfc1035::record::A &)>;
|
||||
using callback_SRV_one = std::function<void (std::exception_ptr, const hostport &, const rfc1035::record::SRV &)>;
|
||||
using callback_ipport_one = std::function<void (std::exception_ptr, const hostport &, const ipport &)>;
|
||||
|
||||
// (internal) generate strings for rfc1035 questions or dns::cache keys.
|
||||
static string_view make_SRV_key(const mutable_buffer &out, const hostport &, const opts &);
|
||||
|
|
|
@ -52,7 +52,7 @@ struct ircd::net::dns::resolver
|
|||
void send_query(const const_buffer &, tag &);
|
||||
void submit(const const_buffer &, tag &);
|
||||
|
||||
tag &set_tag(tag &&);
|
||||
template<class... A> tag &set_tag(A&&...);
|
||||
const_buffer make_query(const mutable_buffer &buf, const tag &) const;
|
||||
void operator()(const hostport &, const opts &, callback);
|
||||
|
||||
|
@ -72,20 +72,23 @@ struct ircd::net::dns::resolver
|
|||
struct ircd::net::dns::resolver::tag
|
||||
{
|
||||
uint16_t id {0};
|
||||
hostport hp; // note: invalid after query sent
|
||||
hostport hp;
|
||||
dns::opts opts; // note: invalid after query sent
|
||||
callback cb;
|
||||
steady_point last;
|
||||
uint8_t tries {0};
|
||||
char hostbuf[256];
|
||||
|
||||
tag(const hostport &, const dns::opts &, callback);
|
||||
tag(const hostport &, const dns::opts &, callback &&);
|
||||
};
|
||||
|
||||
inline
|
||||
ircd::net::dns::resolver::tag::tag(const hostport &hp,
|
||||
const dns::opts &opts,
|
||||
callback cb)
|
||||
callback &&cb)
|
||||
:hp{hp}
|
||||
,opts{opts}
|
||||
,cb{std::move(cb)}
|
||||
{}
|
||||
{
|
||||
this->hp.host = { hostbuf, copy(hostbuf, hp.host) };
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ struct ircd::server::peer
|
|||
template<class F> size_t accumulate_tags(F&&) const;
|
||||
|
||||
void handle_finished();
|
||||
void handle_resolve(std::exception_ptr, const ipport &);
|
||||
void handle_resolve(std::exception_ptr, const hostport &, const ipport &);
|
||||
void resolve(const hostport &);
|
||||
|
||||
void disperse_uncommitted(link &);
|
||||
|
|
114
ircd/net.cc
114
ircd/net.cc
|
@ -547,7 +547,7 @@ ircd::net::open(socket &socket,
|
|||
}};
|
||||
|
||||
auto connector{[&socket, opts, complete(std::move(complete))]
|
||||
(std::exception_ptr eptr, const ipport &ipport)
|
||||
(std::exception_ptr eptr, const hostport &hp, const ipport &ipport)
|
||||
{
|
||||
if(eptr)
|
||||
return complete(std::move(eptr));
|
||||
|
@ -559,7 +559,7 @@ ircd::net::open(socket &socket,
|
|||
if(!opts.ipport)
|
||||
dns(opts.hostport, std::move(connector));
|
||||
else
|
||||
connector({}, opts.ipport);
|
||||
connector({}, opts.hostport, opts.ipport);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2361,21 +2361,21 @@ ircd::net::dns::cache::min_ttl
|
|||
|
||||
decltype(ircd::net::dns::prefetch_ipport)
|
||||
ircd::net::dns::prefetch_ipport{[]
|
||||
(std::exception_ptr, const auto &record)
|
||||
(std::exception_ptr, const auto &hostport, const auto &record)
|
||||
{
|
||||
// Do nothing; cache already updated if necessary
|
||||
}};
|
||||
|
||||
decltype(ircd::net::dns::prefetch_SRV)
|
||||
ircd::net::dns::prefetch_SRV{[]
|
||||
(std::exception_ptr, const auto &record)
|
||||
(std::exception_ptr, const auto &hostport, const auto &record)
|
||||
{
|
||||
// Do nothing; cache already updated if necessary
|
||||
}};
|
||||
|
||||
decltype(ircd::net::dns::prefetch_A)
|
||||
ircd::net::dns::prefetch_A{[]
|
||||
(std::exception_ptr, const auto &record)
|
||||
(std::exception_ptr, const auto &hostport, const auto &record)
|
||||
{
|
||||
// Do nothing; cache already updated if necessary
|
||||
}};
|
||||
|
@ -2390,51 +2390,48 @@ ircd::net::dns::operator()(const hostport &hp,
|
|||
{
|
||||
//TODO: ip6
|
||||
auto calluser{[callback(std::move(callback))]
|
||||
(std::exception_ptr eptr, const uint32_t &ip, const uint16_t &port)
|
||||
(std::exception_ptr eptr, const hostport &hp, const uint32_t &ip)
|
||||
{
|
||||
if(eptr)
|
||||
return callback(std::move(eptr), {});
|
||||
return callback(std::move(eptr), hp, {});
|
||||
|
||||
if(!ip)
|
||||
return callback(std::make_exception_ptr(net::not_found{"Host has no A record"}), {});
|
||||
return callback(std::make_exception_ptr(net::not_found{"Host has no A record"}), hp, {});
|
||||
|
||||
const ipport ipport{ip, port};
|
||||
callback(std::move(eptr), ipport);
|
||||
const ipport ipport{ip, port(hp)};
|
||||
callback(std::move(eptr), hp, ipport);
|
||||
}};
|
||||
|
||||
if(!hp.service)
|
||||
return operator()(hp, opts, [hp, calluser(std::move(calluser))]
|
||||
(std::exception_ptr eptr, const rfc1035::record::A &record)
|
||||
return operator()(hp, opts, [calluser(std::move(calluser))]
|
||||
(std::exception_ptr eptr, const hostport &hp, const rfc1035::record::A &record)
|
||||
{
|
||||
calluser(std::move(eptr), record.ip4, port(hp));
|
||||
calluser(std::move(eptr), hp, record.ip4);
|
||||
});
|
||||
|
||||
auto srv_opts{opts};
|
||||
srv_opts.nxdomain_exceptions = false;
|
||||
operator()(hp, srv_opts, [this, hp(hp), opts(opts), calluser(std::move(calluser))]
|
||||
(std::exception_ptr eptr, const rfc1035::record::SRV &record)
|
||||
operator()(hp, srv_opts, [this, opts(opts), calluser(std::move(calluser))]
|
||||
(std::exception_ptr eptr, hostport hp, const rfc1035::record::SRV &record)
|
||||
mutable
|
||||
{
|
||||
if(eptr)
|
||||
return calluser(std::move(eptr), 0, 0);
|
||||
return calluser(std::move(eptr), hp, 0);
|
||||
|
||||
if(record.port != 0)
|
||||
hp.port = record.port;
|
||||
|
||||
// The host reference in hp has become invalid by the time of this cb.
|
||||
assert(!record.tgt.empty());
|
||||
hp.host = record.tgt;
|
||||
hp.host = record.tgt?: unmake_SRV_key(hp.host);
|
||||
|
||||
// Have to kill the service name to not run another SRV query now, and
|
||||
// these are also invalid references too.
|
||||
// Have to kill the service name to not run another SRV query now.
|
||||
hp.service = {};
|
||||
opts.srv = {};
|
||||
opts.proto = {};
|
||||
|
||||
this->operator()(hp, opts, [hp, calluser(std::move(calluser))]
|
||||
(std::exception_ptr eptr, const rfc1035::record::A &record)
|
||||
this->operator()(hp, opts, [calluser(std::move(calluser))]
|
||||
(std::exception_ptr eptr, const hostport &hp, const rfc1035::record::A &record)
|
||||
{
|
||||
calluser(std::move(eptr), record.ip4, port(hp));
|
||||
calluser(std::move(eptr), hp, record.ip4);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2442,16 +2439,16 @@ ircd::net::dns::operator()(const hostport &hp,
|
|||
/// Convenience callback with a single SRV record which was selected from
|
||||
/// the vector with stochastic respect for weighting and priority.
|
||||
void
|
||||
ircd::net::dns::operator()(const hostport &hostport,
|
||||
ircd::net::dns::operator()(const hostport &hp,
|
||||
const opts &opts,
|
||||
callback_SRV_one callback)
|
||||
{
|
||||
assert(bool(ircd::net::dns::resolver));
|
||||
operator()(hostport, opts, [callback(std::move(callback))]
|
||||
(std::exception_ptr eptr, const vector_view<const rfc1035::record *> rrs)
|
||||
operator()(hp, opts, [callback(std::move(callback))]
|
||||
(std::exception_ptr eptr, const hostport &hp, const vector_view<const rfc1035::record *> rrs)
|
||||
{
|
||||
if(eptr)
|
||||
return callback(std::move(eptr), {});
|
||||
return callback(std::move(eptr), hp, {});
|
||||
|
||||
//TODO: prng on weight / prio plz
|
||||
for(size_t i(0); i < rrs.size(); ++i)
|
||||
|
@ -2461,26 +2458,26 @@ ircd::net::dns::operator()(const hostport &hostport,
|
|||
continue;
|
||||
|
||||
const auto &record(rr.as<const rfc1035::record::SRV>());
|
||||
return callback(std::move(eptr), record);
|
||||
return callback(std::move(eptr), hp, record);
|
||||
}
|
||||
|
||||
return callback(std::move(eptr), {});
|
||||
return callback(std::move(eptr), hp, {});
|
||||
});
|
||||
}
|
||||
|
||||
/// Convenience callback with a single A record which was selected from
|
||||
/// the vector randomly.
|
||||
void
|
||||
ircd::net::dns::operator()(const hostport &hostport,
|
||||
ircd::net::dns::operator()(const hostport &hp,
|
||||
const opts &opts,
|
||||
callback_A_one callback)
|
||||
{
|
||||
assert(bool(ircd::net::dns::resolver));
|
||||
operator()(hostport, opts, [callback(std::move(callback))]
|
||||
(std::exception_ptr eptr, const vector_view<const rfc1035::record *> rrs)
|
||||
operator()(hp, opts, [callback(std::move(callback))]
|
||||
(std::exception_ptr eptr, const hostport &hp, const vector_view<const rfc1035::record *> rrs)
|
||||
{
|
||||
if(eptr)
|
||||
return callback(std::move(eptr), {});
|
||||
return callback(std::move(eptr), hp, {});
|
||||
|
||||
//TODO: prng plz
|
||||
for(size_t i(0); i < rrs.size(); ++i)
|
||||
|
@ -2490,10 +2487,10 @@ ircd::net::dns::operator()(const hostport &hostport,
|
|||
continue;
|
||||
|
||||
const auto &record(rr.as<const rfc1035::record::A>());
|
||||
return callback(std::move(eptr), record);
|
||||
return callback(std::move(eptr), hp, record);
|
||||
}
|
||||
|
||||
return callback(std::move(eptr), {});
|
||||
return callback(std::move(eptr), hp, {});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2602,7 +2599,6 @@ ircd::net::dns::cache::put_error(const rfc1035::question &question,
|
|||
rfc1035::record::SRV record;
|
||||
record.ttl = ircd::time() + seconds(cache::clear_nxdomain).count(); //TODO: code
|
||||
it = map.emplace_hint(it, host, record);
|
||||
it->second.tgt = unmake_SRV_key(it->first);
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
|
@ -2795,7 +2791,7 @@ ircd::net::dns::cache::get(const hostport &hp,
|
|||
assert(!eptr || count == 1); // if error, should only be one entry.
|
||||
|
||||
if(count)
|
||||
cb(std::move(eptr), vector_view<const rfc1035::record *>(record.data(), count));
|
||||
cb(std::move(eptr), hp, vector_view<const rfc1035::record *>(record.data(), count));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -2955,7 +2951,8 @@ ircd::net::dns::resolver::check_timeout(const uint16_t &id,
|
|||
log.error("DNS timeout id:%u", id);
|
||||
|
||||
// Callback gets a fresh stack off this timeout worker ctx's stack.
|
||||
if(tag.cb) ircd::post([cb(std::move(tag.cb))]
|
||||
std::string host{tag.hp.host};
|
||||
if(tag.cb) ircd::post([cb(std::move(tag.cb)), host(std::move(host)), port(tag.hp.port)]
|
||||
{
|
||||
using boost::system::system_error;
|
||||
const error_code ec
|
||||
|
@ -2963,7 +2960,8 @@ ircd::net::dns::resolver::check_timeout(const uint16_t &id,
|
|||
boost::system::errc::timed_out, boost::system::system_category()
|
||||
};
|
||||
|
||||
cb(std::make_exception_ptr(system_error{ec}), {});
|
||||
const hostport hp{host, port};
|
||||
cb(std::make_exception_ptr(system_error{ec}), hp, {});
|
||||
});
|
||||
|
||||
return false;
|
||||
|
@ -2971,16 +2969,13 @@ ircd::net::dns::resolver::check_timeout(const uint16_t &id,
|
|||
|
||||
/// Internal resolver entry interface.
|
||||
void
|
||||
ircd::net::dns::resolver::operator()(const hostport &hostport,
|
||||
ircd::net::dns::resolver::operator()(const hostport &hp,
|
||||
const opts &opts,
|
||||
callback callback)
|
||||
{
|
||||
auto &tag
|
||||
{
|
||||
set_tag(resolver::tag
|
||||
{
|
||||
hostport, opts, std::move(callback)
|
||||
})
|
||||
set_tag(hp, opts, std::move(callback))
|
||||
};
|
||||
|
||||
// Escape trunk
|
||||
|
@ -3004,7 +2999,7 @@ const
|
|||
thread_local char srvbuf[512];
|
||||
const string_view srvhost
|
||||
{
|
||||
make_SRV_key(srvbuf, tag.hp, tag.opts)
|
||||
make_SRV_key(srvbuf, host(tag.hp), tag.opts)
|
||||
};
|
||||
|
||||
const rfc1035::question question{srvhost, "SRV"};
|
||||
|
@ -3015,17 +3010,22 @@ const
|
|||
return rfc1035::make_query(buf, tag.id, question);
|
||||
}
|
||||
|
||||
template<class... A>
|
||||
ircd::net::dns::resolver::tag &
|
||||
ircd::net::dns::resolver::set_tag(tag &&tag)
|
||||
ircd::net::dns::resolver::set_tag(A&&... args)
|
||||
{
|
||||
while(tags.size() < 65535)
|
||||
{
|
||||
tag.id = ircd::rand::integer(1, 65535);
|
||||
auto it{tags.lower_bound(tag.id)};
|
||||
if(it != end(tags) && it->first == tag.id)
|
||||
auto id(ircd::rand::integer(1, 65535));
|
||||
auto it{tags.lower_bound(id)};
|
||||
if(it != end(tags) && it->first == id)
|
||||
continue;
|
||||
|
||||
it = tags.emplace_hint(it, tag.id, std::move(tag));
|
||||
it = tags.emplace_hint(it,
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(id),
|
||||
std::forward_as_tuple(std::forward<A>(args)...));
|
||||
it->second.id = id;
|
||||
dock.notify_one();
|
||||
return it->second;
|
||||
}
|
||||
|
@ -3288,8 +3288,12 @@ try
|
|||
}
|
||||
}
|
||||
|
||||
// Cache no answers here.
|
||||
if(!header.ancount && tag.opts.cache_result)
|
||||
cache.put_error(qd.at(0), header.rcode);
|
||||
|
||||
if(tag.cb)
|
||||
tag.cb({}, vector_view<const rfc1035::record *>(record, i));
|
||||
tag.cb({}, tag.hp, vector_view<const rfc1035::record *>(record, i));
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
|
@ -3302,8 +3306,8 @@ catch(const std::exception &e)
|
|||
|
||||
if(tag.cb)
|
||||
{
|
||||
assert(tag.opts.nxdomain_exceptions);
|
||||
tag.cb(std::current_exception(), {});
|
||||
assert(header.rcode != 3 || tag.opts.nxdomain_exceptions);
|
||||
tag.cb(std::current_exception(), tag.hp, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3334,7 +3338,7 @@ ircd::net::dns::resolver::handle_error(const header &header,
|
|||
if(!tag.opts.nxdomain_exceptions && tag.cb)
|
||||
{
|
||||
assert(record);
|
||||
tag.cb({}, vector_view<const rfc1035::record *>(&record, 1));
|
||||
tag.cb({}, tag.hp, vector_view<const rfc1035::record *>(&record, 1));
|
||||
tag.cb = {};
|
||||
}
|
||||
|
||||
|
|
|
@ -851,7 +851,7 @@ ircd::server::peer::resolve(const hostport &hostport)
|
|||
|
||||
auto handler
|
||||
{
|
||||
std::bind(&peer::handle_resolve, this, ph::_1, ph::_2)
|
||||
std::bind(&peer::handle_resolve, this, ph::_1, ph::_2, ph::_3)
|
||||
};
|
||||
|
||||
op_resolve = true;
|
||||
|
@ -860,6 +860,7 @@ ircd::server::peer::resolve(const hostport &hostport)
|
|||
|
||||
void
|
||||
ircd::server::peer::handle_resolve(std::exception_ptr eptr,
|
||||
const hostport &hp,
|
||||
const ipport &ipport)
|
||||
try
|
||||
{
|
||||
|
@ -877,7 +878,7 @@ try
|
|||
open_opts.ipport = this->remote;
|
||||
host(open_opts.hostport) = this->hostname;
|
||||
port(open_opts.hostport) = port(ipport);
|
||||
open_opts.common_name = this->hostname;
|
||||
open_opts.common_name = {};
|
||||
|
||||
if(unlikely(finished()))
|
||||
return handle_finished();
|
||||
|
|
|
@ -1693,7 +1693,7 @@ console_cmd__net__host(opt &out, const string_view &line)
|
|||
net::ipport ipport;
|
||||
std::exception_ptr eptr;
|
||||
net::dns(hostport, [&done, &dock, &eptr, &ipport]
|
||||
(std::exception_ptr eptr_, const net::ipport &ipport_)
|
||||
(std::exception_ptr eptr_, const net::hostport &, const net::ipport &ipport_)
|
||||
{
|
||||
eptr = std::move(eptr_);
|
||||
ipport = ipport_;
|
||||
|
|
Loading…
Reference in a new issue