0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 02:02:38 +01:00

ircd::net: Reorg DNS related; move resolver into header.

This commit is contained in:
Jason Volk 2018-01-28 09:37:13 -08:00
parent b462f2bbd8
commit 513082b656
9 changed files with 315 additions and 304 deletions

View file

@ -371,7 +371,7 @@ try
auto future
{
net::resolve(hostport)
net::dns(hostport)
};
std::cout << future.get() << std::endl;
@ -392,7 +392,7 @@ try
auto future
{
net::resolve(remote)
net::dns(remote)
};
std::cout << future.get() << std::endl;

View file

@ -65,8 +65,6 @@ struct ircd::strand
#include <ircd/ctx/continuation.h>
#include <ircd/net/asio.h>
#include <ircd/net/socket.h>
#include <ircd/net/acceptor.h>
inline ircd::strand::operator
asio::io_service &()

View file

@ -46,6 +46,10 @@ namespace ircd::net
ip::tcp::endpoint make_endpoint(const ipport &);
}
#include <ircd/net/socket.h>
#include <ircd/net/acceptor.h>
#include <ircd/net/resolver.h>
namespace ircd
{
using net::string;

43
include/ircd/net/dns.h Normal file
View file

@ -0,0 +1,43 @@
// 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.
#pragma once
#define HAVE_IRCD_NET_DNS_H
namespace ircd::net
{
struct dns extern dns;
}
/// DNS resolution suite.
///
/// This is a singleton class; public usage is to make calls on the singleton
/// object like `ircd::net::dns()` etc.
///
struct ircd::net::dns
{
struct resolver;
struct resolver static *resolver;
public:
using callback_one = std::function<void (std::exception_ptr, const ipport &)>;
using callback_many = std::function<void (std::exception_ptr, std::vector<ipport>)>;
using callback_reverse = std::function<void (std::exception_ptr, std::string)>;
// Callback-based interface
void operator()(const hostport &, callback_one);
void operator()(const hostport &, callback_many);
void operator()(const ipport &, callback_reverse);
// Future-based interface
ctx::future<ipport> operator()(const hostport &);
ctx::future<std::string> operator()(const ipport &);
};

View file

@ -49,7 +49,7 @@ namespace ircd::net
#include "hostport.h"
#include "ipport.h"
#include "remote.h"
#include "resolve.h"
#include "dns.h"
#include "listener.h"
#include "sock_opts.h"
#include "open.h"

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2017 Charybdis Development Team
* Copyright (C) 2017 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_NET_RESOLVE_H
namespace ircd::net
{
struct resolve extern resolve;
}
/// DNS resolution suite.
///
/// This is a singleton class; public usage is to make calls on the singleton
/// object like `ircd::net::resolve()` etc.
///
struct ircd::net::resolve
{
using callback_one = std::function<void (std::exception_ptr, const ipport &)>;
using callback_many = std::function<void (std::exception_ptr, std::vector<ipport>)>;
using callback_reverse = std::function<void (std::exception_ptr, std::string)>;
// Callback-based interface
void operator()(const hostport &, callback_one);
void operator()(const hostport &, callback_many);
void operator()(const ipport &, callback_reverse);
// Future-based interface
ctx::future<ipport> operator()(const hostport &);
ctx::future<std::string> operator()(const ipport &);
};

View file

@ -0,0 +1,44 @@
// 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.
#pragma once
#define HAVE_IRCD_NET_RESOLVER_H
// This file is not included with the IRCd standard include stack because
// it requires symbols we can't forward declare without boost headers. It
// is part of the <ircd/asio.h> stack which can be included in your
// definition file if you need low level access to this resolver API.
/// Internal resolver service
struct ircd::net::dns::resolver
{
using resolve_callback = std::function<void (std::exception_ptr, ip::tcp::resolver::results_type)>;
ip::tcp::resolver gai; // Old getaddrinfo() being removed
ip::udp::socket ns; // A pollable activity object
std::vector<ip::udp::endpoint> server; // The list of active servers
size_t server_next{0}; // Round-robin state to hit servers
bool reply_set {false};
ip::udp::endpoint reply_from;
uint8_t reply[64_KiB];
void handle(const error_code &ec, const size_t &) noexcept;
void set_handle();
void send_query(const ip::udp::endpoint &, const const_buffer &);
void send_query(const const_buffer &);
void operator()(const hostport &, ip::tcp::resolver::flags, resolve_callback);
void operator()(const ipport &, resolve_callback);
resolver();
~resolver() noexcept;
};

View file

@ -21,6 +21,29 @@
#include <ircd/asio.h>
///////////////////////////////////////////////////////////////////////////////
//
// init
//
/// Network subsystem initialization
ircd::net::init::init()
{
assert(ircd::ios);
assert(!net::dns::resolver);
net::dns::resolver = new struct dns::resolver();
sslv23_client.set_verify_mode(asio::ssl::verify_peer);
sslv23_client.set_default_verify_paths();
}
/// Network subsystem shutdown
ircd::net::init::~init()
{
delete net::dns::resolver;
net::dns::resolver = nullptr;
}
///////////////////////////////////////////////////////////////////////////////
//
// net/net.h
@ -503,7 +526,7 @@ ircd::net::open(socket &socket,
}};
if(!opts.ipport)
resolve(opts.hostport, std::move(connector));
dns(opts.hostport, std::move(connector));
else
connector({}, opts.ipport);
}
@ -2111,52 +2134,134 @@ ircd::net::socket::scope_timeout::release()
///////////////////////////////////////////////////////////////////////////////
//
// net/resolve.h
// net/dns.h
//
namespace ircd::net
{
struct resolver extern *resolver;
// Internal resolve base (requires boost syms)
using resolve_callback = std::function<void (std::exception_ptr, ip::tcp::resolver::results_type)>;
void _resolve(const hostport &, ip::tcp::resolver::flags, resolve_callback);
void _resolve(const ipport &, resolve_callback);
}
/// Internal resolver service
struct ircd::net::resolver
{
ip::tcp::resolver gai; // Old getaddrinfo() being removed
ip::udp::socket ns; // A pollable activity object
std::vector<ip::udp::endpoint> server; // The list of active servers
size_t server_next{0}; // Round-robin state to hit servers
bool reply_set {false};
ip::udp::endpoint reply_from;
uint8_t reply[64_KiB];
void handle(const error_code &ec, const size_t &) noexcept;
void set_handle();
void send_query(const ip::udp::endpoint &, const const_buffer &);
void send_query(const const_buffer &);
resolver();
~resolver() noexcept;
};
/// Singleton instance of the public interface ircd::net::resolve
decltype(ircd::net::resolve)
ircd::net::resolve
decltype(ircd::net::dns)
ircd::net::dns
{};
/// Singleton instance of the internal boost resolver wrapper.
decltype(ircd::net::resolver)
ircd::net::resolver
decltype(ircd::net::dns::resolver)
ircd::net::dns::resolver
{};
ircd::net::resolver::resolver()
/// Resolve a numerical address to a hostname string. This is a PTR record
/// query or 'reverse DNS' lookup.
ircd::ctx::future<std::string>
ircd::net::dns::operator()(const ipport &ipport)
{
ctx::promise<std::string> p;
ctx::future<std::string> ret{p};
operator()(ipport, [p(std::move(p))]
(std::exception_ptr eptr, std::string ptr)
mutable
{
if(eptr)
p.set_exception(std::move(eptr));
else
p.set_value(ptr);
});
return ret;
}
/// Resolve a hostname (with service name/portnum) to a numerical address. This
/// is an A or AAAA query (with automatic SRV query) returning a single result.
ircd::ctx::future<ircd::net::ipport>
ircd::net::dns::operator()(const hostport &hostport)
{
ctx::promise<ipport> p;
ctx::future<ipport> ret{p};
operator()(hostport, [p(std::move(p))]
(std::exception_ptr eptr, const ipport &ip)
mutable
{
if(eptr)
p.set_exception(std::move(eptr));
else
p.set_value(ip);
});
return ret;
}
/// Lower-level PTR query (i.e "reverse DNS") with asynchronous callback
/// interface.
void
ircd::net::dns::operator()(const ipport &ipport,
callback_reverse callback)
{
assert(bool(ircd::net::dns::resolver));
(*resolver)(ipport, [callback(std::move(callback))]
(std::exception_ptr eptr, ip::tcp::resolver::results_type results)
{
if(eptr)
return callback(std::move(eptr), {});
if(results.empty())
return callback({}, {});
assert(results.size() <= 1);
const auto &result(*begin(results));
callback({}, result.host_name());
});
}
/// Lower-level A or AAAA query (with automatic SRV query) with asynchronous
/// callback interface. This returns only one result.
void
ircd::net::dns::operator()(const hostport &hostport,
callback_one callback)
{
static const ip::tcp::resolver::flags flags{};
assert(bool(ircd::net::dns::resolver));
(*resolver)(hostport, flags, [callback(std::move(callback))]
(std::exception_ptr eptr, ip::tcp::resolver::results_type results)
{
if(eptr)
return callback(std::move(eptr), {});
if(results.empty())
return callback(std::make_exception_ptr(nxdomain{}), {});
const auto &result(*begin(results));
callback(std::move(eptr), make_ipport(result));
});
}
/// Lower-level A+AAAA query (with automatic SRV query). This returns a vector
/// of all results in the callback.
void
ircd::net::dns::operator()(const hostport &hostport,
callback_many callback)
{
static const ip::tcp::resolver::flags flags{};
assert(bool(ircd::net::dns::resolver));
(*resolver)(hostport, flags, [callback(std::move(callback))]
(std::exception_ptr eptr, ip::tcp::resolver::results_type results)
{
if(eptr)
return callback(std::move(eptr), {});
std::vector<ipport> vector(results.size());
std::transform(begin(results), end(results), begin(vector), []
(const auto &entry)
{
return make_ipport(entry.endpoint());
});
callback(std::move(eptr), std::move(vector));
});
}
///////////////////////////////////////////////////////////////////////////////
//
// net/resolver.h
//
ircd::net::dns::resolver::resolver()
:gai{*ircd::ios}
,ns{*ircd::ios}
{
@ -2165,15 +2270,84 @@ ircd::net::resolver::resolver()
set_handle();
}
ircd::net::resolver::~resolver()
ircd::net::dns::resolver::~resolver()
noexcept
{
gai.cancel();
ns.close();
}
/// Internal A/AAAA record resolver function
void
ircd::net::resolver::send_query(const const_buffer &buf)
ircd::net::dns::resolver::operator()(const hostport &hostport,
ip::tcp::resolver::flags flags,
resolve_callback callback)
{
// Trivial host string
const string_view &host
{
hostport.host
};
// Determine if the port is a string or requires a lex_cast to one.
char portbuf[8];
const string_view &port
{
hostport.portnum? lex_cast(hostport.portnum, portbuf) : hostport.port
};
// Determine if the port is numeric and hint to avoid name lookup if so.
if(hostport.portnum || ctype<std::isdigit>(hostport.port) == -1)
flags |= ip::tcp::resolver::numeric_service;
// This base handler will provide exception guarantees for the entire stack.
// It may invoke callback twice in the case when callback throws unhandled,
// but the latter invocation will always have an the eptr set.
gai.async_resolve(host, port, flags, [callback(std::move(callback))]
(const error_code &ec, ip::tcp::resolver::results_type results)
noexcept
{
if(ec)
{
callback(std::make_exception_ptr(boost::system::system_error{ec}), std::move(results));
}
else try
{
callback({}, std::move(results));
}
catch(...)
{
callback(std::make_exception_ptr(std::current_exception()), {});
}
});
}
/// Internal PTR record resolver function
void
ircd::net::dns::resolver::operator()(const ipport &ipport,
resolve_callback callback)
{
gai.async_resolve(make_endpoint(ipport), [callback(std::move(callback))]
(const error_code &ec, ip::tcp::resolver::results_type results)
noexcept
{
if(ec)
{
callback(std::make_exception_ptr(boost::system::system_error{ec}), std::move(results));
}
else try
{
callback({}, std::move(results));
}
catch(...)
{
callback(std::make_exception_ptr(std::current_exception()), {});
}
});
}
void
ircd::net::dns::resolver::send_query(const const_buffer &buf)
{
assert(!server.empty());
@ -2183,15 +2357,15 @@ ircd::net::resolver::send_query(const const_buffer &buf)
}
void
ircd::net::resolver::send_query(const ip::udp::endpoint &ep,
const const_buffer &buf)
ircd::net::dns::resolver::send_query(const ip::udp::endpoint &ep,
const const_buffer &buf)
{
assert(ns.non_blocking());
ns.send_to(asio::const_buffers_1(buf), ep);
}
void
ircd::net::resolver::set_handle()
ircd::net::dns::resolver::set_handle()
{
auto handler
{
@ -2205,8 +2379,8 @@ ircd::net::resolver::set_handle()
}
void
ircd::net::resolver::handle(const error_code &ec,
const size_t &bytes)
ircd::net::dns::resolver::handle(const error_code &ec,
const size_t &bytes)
noexcept try
{
using namespace boost::system::errc;
@ -2250,7 +2424,6 @@ noexcept try
reply + sizeof(header), bytes - sizeof(header)
};
std::cout << "answer: " << header.ancount << std::endl;
if(!header.ancount)
return;
@ -2259,9 +2432,7 @@ noexcept try
const_buffer{body}
};
std::cout << "answer [" << answer.name << "] " << answer.rdlength << " " << answer.qtype << " " << answer.qclass << " " << answer.ttl << std::endl;
net::ipport ipp(ip::address_v4(*(const uint32_t *)data(answer.rdata)).to_uint(), 0);
std::cout << ipp << std::endl;
}
catch(const std::exception &e)
@ -2272,183 +2443,6 @@ catch(const std::exception &e)
};
}
/// Resolve a numerical address to a hostname string. This is a PTR record
/// query or 'reverse DNS' lookup.
ircd::ctx::future<std::string>
ircd::net::resolve::operator()(const ipport &ipport)
{
ctx::promise<std::string> p;
ctx::future<std::string> ret{p};
operator()(ipport, [p(std::move(p))]
(std::exception_ptr eptr, std::string ptr)
mutable
{
if(eptr)
p.set_exception(std::move(eptr));
else
p.set_value(ptr);
});
return ret;
}
/// Resolve a hostname (with service name/portnum) to a numerical address. This
/// is an A or AAAA query (with automatic SRV query) returning a single result.
ircd::ctx::future<ircd::net::ipport>
ircd::net::resolve::operator()(const hostport &hostport)
{
ctx::promise<ipport> p;
ctx::future<ipport> ret{p};
operator()(hostport, [p(std::move(p))]
(std::exception_ptr eptr, const ipport &ip)
mutable
{
if(eptr)
p.set_exception(std::move(eptr));
else
p.set_value(ip);
});
return ret;
}
/// Lower-level PTR query (i.e "reverse DNS") with asynchronous callback
/// interface.
void
ircd::net::resolve::operator()(const ipport &ipport,
callback_reverse callback)
{
_resolve(ipport, [callback(std::move(callback))]
(std::exception_ptr eptr, ip::tcp::resolver::results_type results)
{
if(eptr)
return callback(std::move(eptr), {});
if(results.empty())
return callback({}, {});
assert(results.size() <= 1);
const auto &result(*begin(results));
callback({}, result.host_name());
});
}
/// Lower-level A or AAAA query (with automatic SRV query) with asynchronous
/// callback interface. This returns only one result.
void
ircd::net::resolve::operator()(const hostport &hostport,
callback_one callback)
{
static const ip::tcp::resolver::flags flags{};
_resolve(hostport, flags, [callback(std::move(callback))]
(std::exception_ptr eptr, ip::tcp::resolver::results_type results)
{
if(eptr)
return callback(std::move(eptr), {});
if(results.empty())
return callback(std::make_exception_ptr(nxdomain{}), {});
const auto &result(*begin(results));
callback(std::move(eptr), make_ipport(result));
});
}
/// Lower-level A+AAAA query (with automatic SRV query). This returns a vector
/// of all results in the callback.
void
ircd::net::resolve::operator()(const hostport &hostport,
callback_many callback)
{
static const ip::tcp::resolver::flags flags{};
_resolve(hostport, flags, [callback(std::move(callback))]
(std::exception_ptr eptr, ip::tcp::resolver::results_type results)
{
if(eptr)
return callback(std::move(eptr), {});
std::vector<ipport> vector(results.size());
std::transform(begin(results), end(results), begin(vector), []
(const auto &entry)
{
return make_ipport(entry.endpoint());
});
callback(std::move(eptr), std::move(vector));
});
}
/// Internal A/AAAA record resolver function
void
ircd::net::_resolve(const hostport &hostport,
ip::tcp::resolver::flags flags,
resolve_callback callback)
{
// Trivial host string
const string_view &host
{
hostport.host
};
// Determine if the port is a string or requires a lex_cast to one.
char portbuf[8];
const string_view &port
{
hostport.portnum? lex_cast(hostport.portnum, portbuf) : hostport.port
};
// Determine if the port is numeric and hint to avoid name lookup if so.
if(hostport.portnum || ctype<std::isdigit>(hostport.port) == -1)
flags |= ip::tcp::resolver::numeric_service;
// This base handler will provide exception guarantees for the entire stack.
// It may invoke callback twice in the case when callback throws unhandled,
// but the latter invocation will always have an the eptr set.
assert(bool(ircd::net::resolver));
resolver->gai.async_resolve(host, port, flags, [callback(std::move(callback))]
(const error_code &ec, ip::tcp::resolver::results_type results)
noexcept
{
if(ec)
{
callback(std::make_exception_ptr(boost::system::system_error{ec}), std::move(results));
}
else try
{
callback({}, std::move(results));
}
catch(...)
{
callback(std::make_exception_ptr(std::current_exception()), {});
}
});
}
/// Internal PTR record resolver function
void
ircd::net::_resolve(const ipport &ipport,
resolve_callback callback)
{
assert(bool(ircd::net::resolver));
resolver->gai.async_resolve(make_endpoint(ipport), [callback(std::move(callback))]
(const error_code &ec, ip::tcp::resolver::results_type results)
noexcept
{
if(ec)
{
callback(std::make_exception_ptr(boost::system::system_error{ec}), std::move(results));
}
else try
{
callback({}, std::move(results));
}
catch(...)
{
callback(std::make_exception_ptr(std::current_exception()), {});
}
});
}
///////////////////////////////////////////////////////////////////////////////
//
// net/remote.h
@ -2792,26 +2786,3 @@ const
data(*this), size(*this)
};
}
///////////////////////////////////////////////////////////////////////////////
//
// init
//
/// Network subsystem initialization
ircd::net::init::init()
{
assert(ircd::ios);
assert(!net::resolver);
net::resolver = new struct resolver();
sslv23_client.set_verify_mode(asio::ssl::verify_peer);
sslv23_client.set_default_verify_paths();
}
/// Network subsystem shutdown
ircd::net::init::~init()
{
delete net::resolver;
net::resolver = nullptr;
}

View file

@ -695,7 +695,7 @@ ircd::server::node::resolve(const hostport &hostport)
std::bind(&node::handle_resolve, this, weak_from(*this), ph::_1, ph::_2)
};
net::resolve(hostport, std::move(handler));
net::dns(hostport, std::move(handler));
}
void