0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-05-18 10:53:48 +02:00

ircd::net::dns: Add support for netdb; interface to getservbyname(3).

This commit is contained in:
Jason Volk 2020-03-06 11:41:09 -08:00
parent 4b41efcdc8
commit 0e25a2e055
3 changed files with 91 additions and 1 deletions

View file

@ -921,6 +921,7 @@ dnl unix platform
RB_CHK_SYSHEADER(unistd.h, [UNISTD_H])
RB_CHK_SYSHEADER(signal.h, [SIGNAL_H])
RB_CHK_SYSHEADER(ifaddrs.h, [IFADDRS_H])
RB_CHK_SYSHEADER(netdb.h, [NETDB_H])
RB_CHK_SYSHEADER(fcntl.h, [FCNTL_H])
RB_CHK_SYSHEADER(elf.h, [ELF_H])
RB_CHK_SYSHEADER(link.h, [LINK_H])

View file

@ -37,9 +37,13 @@ namespace ircd::net::dns
bool expired(const json::object &rr, const time_t &rr_ts, const time_t &min_ttl);
bool expired(const json::object &rr, const time_t &rr_ts);
json::object random_choice(const json::array &);
string_view make_SRV_key(const mutable_buffer &out, const hostport &, const opts &);
string_view unmake_SRV_key(const string_view &);
uint16_t service_port(std::nothrow_t, const string_view &name, const string_view &prot = {});
uint16_t service_port(const string_view &name, const string_view &prot = {});
// Callback-based interface
void resolve(const hostport &, const opts &, callback);
void resolve(const hostport &, const opts &, callback_one); // convenience
@ -86,6 +90,10 @@ struct ircd::net::dns::opts
/// the returned record is a reference to the cached error.
bool nxdomain_exceptions {true};
/// When false, queries to translate service strings to port numbers using
/// netdb (i.e. /etc/services) will be disabled if they were to occur.
bool service_port {true};
opts() = default;
};

View file

@ -8,6 +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 <RB_INC_NETDB_H
#include <ircd/net/dns_cache.h>
namespace ircd::net::dns
@ -112,16 +113,22 @@ ircd::net::dns::resolve(const hostport &hp,
}
void
ircd::net::dns::resolve(const hostport &hp,
ircd::net::dns::resolve(const hostport &hp_,
const opts &opts,
callback cb)
{
hostport hp(hp_);
if(unlikely(!opts.qtype))
throw error
{
"Query type is required; not specified; cannot be deduced here."
};
// Make any necessary attempt to translate a service name into a portnum.
if(likely(opts.service_port))
if(!port(hp) && service(hp))
port(hp) = service_port(std::nothrow, service(hp), opts.proto);
// Try to satisfy from the cache first. This requires a ctx.
if(likely(ctx::current && opts.cache_check))
if(cache::get(hp, opts, cb))
@ -532,3 +539,77 @@ ircd::net::dns::new_record(mutable_buffer &buf,
consume(buf, sizeof(type));
return new (pos) type(answer);
}
uint16_t
ircd::net::dns::service_port(const string_view &name,
const string_view &prot)
{
const auto ret
{
service_port(std::nothrow, name, prot)
};
if(unlikely(!ret))
throw error
{
"Port for service %s:%s not found",
name,
prot?: "*"_sv,
};
return ret;
}
#ifdef HAVE_NETDB_H
uint16_t
ircd::net::dns::service_port(std::nothrow_t,
const string_view &name,
const string_view &prot)
try
{
thread_local struct ::servent res, *ent {nullptr};
thread_local char _name[32], _prot[32], buf[2048];
strlcpy(_name, name);
strlcpy(_prot, prot);
syscall
(
::getservbyname_r,
_name,
prot? _prot : nullptr,
&res,
buf,
sizeof(buf),
&ent
);
assert(!ent || ent->s_port != 0);
assert(!ent || name == ent->s_name);
assert(!ent || !prot || prot == ent->s_proto);
return ent?
htons(ent->s_port):
0U;
}
catch(const std::exception &e)
{
log::critical
{
log, "Failure when translating service %s:%s to port number :%s",
name,
prot?: "*"_sv,
e.what(),
};
throw;
}
#else
uint16_t
ircd::net::dns::service_port(std::nothrow_t,
const string_view &name,
const string_view &prot)
{
//TODO: XXX
always_assert(false);
return 0;
}
#endif