if (!pdns::isQueryLocalAddressFamilyEnabled(remote.sin4.sin_family)) {
throw ResolverException("Unable to determine source address for AXFR request to " + remote.toStringWithPort() + " for " + domain.toLogString() + ". Address family is not configured for outgoing queries");
}
- local = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
+ local = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0).d_address;
}
d_sock = -1;
try {
#include "iputils.hh"
#include "dns_random.hh"
-namespace pdns {
+namespace pdns
+{
static const ComboAddress local4("0.0.0.0");
static const ComboAddress local6("::");
- static vector<ComboAddress> g_localQueryAddresses4;
- static vector<ComboAddress> g_localQueryAddresses6;
+ static vector<AddressAndInterface> g_localQueryAddresses4;
+ static vector<AddressAndInterface> g_localQueryAddresses6;
- ComboAddress getQueryLocalAddress(const sa_family_t family, const in_port_t port) {
- ComboAddress ret;
+ AddressAndInterface getQueryLocalAddress(const sa_family_t family, const in_port_t port) {
+ AddressAndInterface ret;
if (family==AF_INET) {
if (g_localQueryAddresses4.empty()) {
- ret = local4;
+ ret.d_address = local4;
} else if (g_localQueryAddresses4.size() == 1) {
ret = g_localQueryAddresses4.at(0);
} else {
ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())];
}
- ret.sin4.sin_port = htons(port);
+ ret.d_address.sin4.sin_port = htons(port);
}
else {
if (g_localQueryAddresses6.empty()) {
- ret = local6;
+ ret.d_address = local6;
} else if (g_localQueryAddresses6.size() == 1) {
ret = g_localQueryAddresses6.at(0);
} else {
ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())];
}
- ret.sin6.sin6_port = htons(port);
+ ret.d_address.sin6.sin6_port = htons(port);
}
return ret;
}
- ComboAddress getNonAnyQueryLocalAddress(const sa_family_t family) {
+ AddressAndInterface getNonAnyQueryLocalAddress(const sa_family_t family) {
if (family == AF_INET) {
for (const auto& addr : pdns::g_localQueryAddresses4) {
- if (!IsAnyAddress(addr)) {
+ if (!IsAnyAddress(addr.d_address)) {
return addr;
}
}
}
if (family == AF_INET6) {
for (const auto& addr : pdns::g_localQueryAddresses6) {
- if (!IsAnyAddress(addr)) {
+ if (!IsAnyAddress(addr.d_address)) {
return addr;
}
}
}
- ComboAddress ret("0.0.0.0");
- ret.reset(); // Ensure all is zero, even the addr family
+ AddressAndInterface ret{ComboAddress{"0.0.0.0"}, std::nullopt};
+ ret.d_address.reset(); // Ensure all is zero, even the addr family
return ret;
}
vector<string> addrs;
stringtok(addrs, qla, ", ;");
for(const string& addr : addrs) {
- ComboAddress tmp(addr);
- if (tmp.isIPv4()) {
- g_localQueryAddresses4.push_back(tmp);
+ AddressAndInterface tmp{ComboAddress{addr}, std::nullopt};
+ if (tmp.d_address.isIPv4()) {
+ g_localQueryAddresses4.emplace_back(std::move(tmp));
continue;
}
- g_localQueryAddresses6.push_back(tmp);
+ g_localQueryAddresses6.emplace_back(std::move(tmp));
}
}
#include "iputils.hh"
namespace pdns {
+
+ struct Interface
+ {
+ std::string d_name;
+ int d_index{-1};
+ };
+ struct AddressAndInterface
+ {
+ ComboAddress d_address;
+ std::optional<Interface> d_interface;
+ bool operator<(const AddressAndInterface& arg) const
+ {
+ return d_address < arg.d_address; // XXX
+ };
+ };
+
/*! pick a random query local address for family
*
* Will always return a ComboAddress.
* @param family Address Family, only AF_INET and AF_INET6 are supported
* @param port Port to set in the returned ComboAddress
*/
- ComboAddress getQueryLocalAddress(const sa_family_t family, const in_port_t port);
+ AddressAndInterface getQueryLocalAddress(sa_family_t family, in_port_t port);
/*! Returns a non-Any address QLA, or an empty QLA when the QLA is any
*
* @param family Address Family
*/
- ComboAddress getNonAnyQueryLocalAddress(const sa_family_t family);
+ AddressAndInterface getNonAnyQueryLocalAddress(sa_family_t family);
/*! Populate the query local address vectors
*
*
* @param family Address Family, only AF_INET and AF_INET6 are supported
*/
- bool isQueryLocalAddressFamilyEnabled(const sa_family_t family);
+ bool isQueryLocalAddressFamilyEnabled(sa_family_t family);
} // namespace pdns
{
};
-static bool tcpconnect(const OptLog& log, const ComboAddress& remote, const std::optional<ComboAddress> localBind, TCPOutConnectionManager::Connection& connection, bool& dnsOverTLS, const std::string& nsName, std::string& subjectName)
+static bool tcpconnect(const OptLog& log, const ComboAddress& remote, const std::optional<pdns::AddressAndInterface> localBind, TCPOutConnectionManager::Connection& connection, bool& dnsOverTLS, const std::string& nsName, std::string& subjectName)
{
dnsOverTLS = SyncRes::s_dot_to_port_853 && remote.getPort() == 853;
sock.setNonBlocking();
setTCPNoDelay(sock.getHandle());
// Bind to the same address the cookie is associated with (RFC 9018 section 3 last paragraph)
- ComboAddress localip = localBind ? *localBind : pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
+ pdns::AddressAndInterface localip = localBind ? *localBind : pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
if (localBind) {
- VLOG(log, "Connecting TCP to " << remote.toStringWithPortExcept(53) << " with specific local address " << localip.toString() << endl);
+ VLOG(log, "Connecting TCP to " << remote.toStringWithPortExcept(53) << " with specific local address " << localip.d_address.toString() << endl);
}
else {
VLOG(log, "Connecting TCP to " << remote.toStringWithPortExcept(53) << " with no specific local address" << endl);
}
try {
- sock.bind(localip);
+ sock.bind(localip.d_address);
}
catch (const NetworkError& e) {
if (localBind) {
}
}
-static void outgoingCookie(const OptLog& log, const ComboAddress& address, const timeval& now, DNSPacketWriter::optvect_t& opts, std::optional<EDNSCookiesOpt>& cookieSentOut, std::optional<ComboAddress>& addressToBindTo)
+static void outgoingCookie(const OptLog& log, const ComboAddress& address, const timeval& now, DNSPacketWriter::optvect_t& opts, std::optional<EDNSCookiesOpt>& cookieSentOut, std::optional<pdns::AddressAndInterface>& addressToBindTo)
{
auto lock = s_cookiestore.lock();
if (auto found = lock->find(address); found != lock->end()) {
VLOG(log, "Sending new client cookie info to " << address.toString() << ": " << entry.d_cookie.toDisplayString() << endl);
}
-static std::pair<bool, LWResult::Result> incomingCookie(const OptLog& log, const ComboAddress& address, const ComboAddress& localip, const timeval& now, const std::optional<EDNSCookiesOpt>& cookieSentOut, const EDNSOpts& edo, bool doTCP, LWResult& lwr, bool& cookieFoundInReply)
+static std::pair<bool, LWResult::Result> incomingCookie(const OptLog& log, const ComboAddress& address, const pdns::AddressAndInterface& localip, const timeval& now, const std::optional<EDNSCookiesOpt>& cookieSentOut, const EDNSOpts& edo, bool doTCP, LWResult& lwr, bool& cookieFoundInReply)
{
auto lock = s_cookiestore.lock();
auto found = lock->find(address);
cookieFoundInReply = true;
VLOG(log, "Received cookie info back from " << address.toString() << ": " << received.toDisplayString() << endl);
if (cookieSentOut && received.getClient() == cookieSentOut->getClient()) {
- VLOG(log, "Client cookie from " << address.toString() << " matched! Storing with localAddress " << localip.toString() << endl);
+ VLOG(log, "Client cookie from " << address.toString() << " matched! Storing with localAddress " << localip.d_address.toString() << endl);
++t_Counters.at(rec::Counter::cookieMatched);
found->d_localaddress = localip;
- found->d_localaddress.setPort(0);
+ found->d_localaddress.d_address.setPort(0);
found->d_cookie = std::move(received);
if (found->getSupport() == CookieEntry::Support::Probing) {
++t_Counters.at(rec::Counter::cookieProbeSupported);
if (ercode == ERCode::BADCOOKIE) {
lwr.d_validpacket = true;
++t_Counters.at(rec::Counter::cookieRetry);
- VLOG(log, "Server " << localip.toString() << " returned BADCOOKIE " << endl);
+ VLOG(log, "Server " << localip.d_address.toString() << " returned BADCOOKIE " << endl);
return {true, LWResult::Result::BadCookie}; // We did update the entry, retry should succeed
}
}
else {
if (!doTCP) {
// Server responded with a wrong client cookie, fall back to TCP, RFC 7873 5.3
- VLOG(log, "Server " << localip.toString() << " responded with wrong client cookie, fall back to TCP" << endl);
+ VLOG(log, "Server " << localip.d_address.toString() << " responded with wrong client cookie, fall back to TCP" << endl);
lwr.d_validpacket = true;
++t_Counters.at(rec::Counter::cookieMismatchedOverUDP);
return {true, LWResult::Result::Spoofed};
}
// mismatched cookie when already doing TCP, ignore that
- VLOG(log, "Server " << localip.toString() << " responded with wrong client cookie over TCP, ignoring that" << endl);
+ VLOG(log, "Server " << localip.d_address.toString() << " responded with wrong client cookie over TCP, ignoring that" << endl);
++t_Counters.at(rec::Counter::cookieMismatchedOverTCP);
}
}
pw.getHeader()->cd = (sendRDQuery && g_dnssecmode != DNSSECMode::Off);
std::optional<EDNSSubnetOpts> subnetOpts = std::nullopt;
- std::optional<ComboAddress> addressToBindTo;
+ std::optional<pdns::AddressAndInterface> addressToBindTo;
std::optional<EDNSCookiesOpt> cookieSentOut;
if (EDNS0Level > 0) {
// Cookie info already has been added to packet, so we must retry from a higher level
auto lock = s_cookiestore.lock();
lock->erase(address);
- VLOG(log, "BindError remote: " << address.toString() << " localAddress: " << (addressToBindTo ? addressToBindTo->toString() : "none") << endl);
+ VLOG(log, "BindError remote: " << address.toString() << " localAddress: " << (addressToBindTo ? addressToBindTo->d_address.toString() : "none") << endl);
return LWResult::Result::BindError;
}
catch (const NetworkError& nwe) {
}
}
if (g_cookies && cookieSentOut && !*chained) {
- auto [done, result] = incomingCookie(log, address, localip, *now, cookieSentOut, edo, doTCP, *lwr, cookieFoundInReply);
+ auto [done, result] = incomingCookie(log, address, {localip, std::nullopt}, *now, cookieSentOut, edo, doTCP, *lwr, cookieFoundInReply);
if (done) {
return result;
}
#include "pdnsexception.hh"
#include "noinitvector.hh"
#include "remote_logger.hh"
+#include "query-local-address.hh"
class FrameStreamLogger;
struct DNSRecord;
class EDNSSubnetOpts;
LWResult::Result asendto(const void* data, size_t len, const ComboAddress& toAddress,
- std::optional<ComboAddress>& localAddress, uint16_t qid,
+ std::optional<pdns::AddressAndInterface>& localAddress, uint16_t qid,
const DNSName& domain, uint16_t qtype, const std::optional<EDNSSubnetOpts>& ecs, int* fileDesc, timeval& now);
LWResult::Result arecvfrom(PacketBuffer& packet, const ComboAddress& fromAddr, size_t& len, uint16_t qid,
const DNSName& domain, uint16_t qtype, int fileDesc, const std::optional<EDNSSubnetOpts>& ecs, const struct timeval& now);
GlobalStateHolder<SuffixMatchNode> g_DoTToAuthNames;
uint64_t g_latencyStatSize;
-LWResult::Result UDPClientSocks::getSocket(const ComboAddress& toaddr, const std::optional<ComboAddress>& localAddress, int* fileDesc)
+LWResult::Result UDPClientSocks::getSocket(const ComboAddress& toaddr, const std::optional<pdns::AddressAndInterface>& localAddress, int* fileDesc)
{
*fileDesc = makeClientSocket(toaddr.sin4.sin_family, localAddress);
if (*fileDesc < 0) { // temporary error - receive exception otherwise
}
// returns -1 for errors which might go away, throws for ones that won't
-int UDPClientSocks::makeClientSocket(int family, const std::optional<ComboAddress>& localAddress)
+int UDPClientSocks::makeClientSocket(int family, const std::optional<pdns::AddressAndInterface>& localAddress)
{
int ret = socket(family, SOCK_DGRAM, 0); // turns out that setting CLO_EXEC and NONBLOCK from here is not a performance win on Linux (oddly enough)
// localAddress is set if a cookie was involved, bind to the same address the cookie is
// associated with (RFC 9018 section 3 last paragraph)
if (localAddress) {
- sin = *localAddress;
+ sin = localAddress->d_address;
sin.setPort(port);
}
else {
- sin = pdns::getQueryLocalAddress(family, port); // does htons for us
+ sin = pdns::getQueryLocalAddress(family, port).d_address; // does htons for us
}
if (::bind(ret, reinterpret_cast<struct sockaddr*>(&sin), sin.getSocklen()) >= 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
break;
{
Socket socket(dest.sin4.sin_family, SOCK_DGRAM);
socket.setNonBlocking();
- ComboAddress local = pdns::getQueryLocalAddress(dest.sin4.sin_family, 0);
+ ComboAddress local = pdns::getQueryLocalAddress(dest.sin4.sin_family, 0).d_address;
socket.bind(local);
socket.connect(dest);
/* these two functions are used by LWRes */
LWResult::Result asendto(const void* data, size_t len,
- const ComboAddress& toAddress, std::optional<ComboAddress>& localAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, const std::optional<EDNSSubnetOpts>& ecs, int* fileDesc, timeval& now)
+ const ComboAddress& toAddress, std::optional<pdns::AddressAndInterface>& localAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, const std::optional<EDNSSubnetOpts>& ecs, int* fileDesc, timeval& now)
{
auto pident = std::make_shared<PacketID>();
timebuf_t tmp;
fprintf(filePtr.get(), "%s\t%s\t%s\t%s\t%s\n",
entry.d_address.toStringWithPortExcept(53).c_str(),
- entry.d_localaddress.isUnspecified() ? "-" : entry.d_localaddress.toString().c_str(),
+ entry.d_localaddress.d_address.isUnspecified() ? "-" : entry.d_localaddress.d_address.toString().c_str(),
entry.d_support == CookieEntry::Support::Unsupported ? "-" : entry.d_cookie.toDisplayString().c_str(),
CookieEntry::toString(entry.d_support).c_str(),
entry.d_lastused == std::numeric_limits<time_t>::max() ? "Forever" : timestamp(entry.d_lastused, tmp));
#include "iputils.hh"
#include "ednscookies.hh"
+#include "query-local-address.hh"
using namespace ::boost::multi_index;
}
ComboAddress d_address;
- mutable ComboAddress d_localaddress; // The address we were bound to, see RFC 9018
+ mutable pdns::AddressAndInterface d_localaddress; // The address we were bound to, see RFC 9018
mutable EDNSCookiesOpt d_cookie; // Contains both client and server cookie
mutable time_t d_lastused{};
mutable Support d_support{Support::Unsupported};
Netmask netmask;
bool done = false;
- auto addr = pdns::getNonAnyQueryLocalAddress(AF_INET);
+ auto addr = pdns::getNonAnyQueryLocalAddress(AF_INET).d_address;
if (addr.sin4.sin_family != 0) {
netmask = Netmask(addr, 32);
done = true;
}
if (!done) {
- addr = pdns::getNonAnyQueryLocalAddress(AF_INET6);
+ addr = pdns::getNonAnyQueryLocalAddress(AF_INET6).d_address;
if (addr.sin4.sin_family != 0) {
netmask = Netmask(addr, 128);
done = true;
class UDPClientSocks
{
public:
- LWResult::Result getSocket(const ComboAddress& toaddr, const std::optional<ComboAddress>& localAddress, int* fileDesc);
+ LWResult::Result getSocket(const ComboAddress& toaddr, const std::optional<pdns::AddressAndInterface>& localAddress, int* fileDesc);
// return a socket to the pool, or simply erase it
void returnSocket(int fileDesc);
private:
unsigned int d_numsocks{0};
// returns -1 for errors which might go away, throws for ones that won't
- static int makeClientSocket(int family, const std::optional<ComboAddress>& localAddress);
+ static int makeClientSocket(int family, const std::optional<pdns::AddressAndInterface>& localAddress);
};
enum class PaddingMode : uint8_t
#include "iputils.hh"
#include "tcpiohandler.hh"
+#include "query-local-address.hh"
namespace pdns::rust::settings::rec
{
}
std::shared_ptr<TCPIOHandler> d_handler;
- std::optional<ComboAddress> d_local;
+ std::optional<pdns::AddressAndInterface> d_local;
timeval d_last_used{0, 0};
size_t d_numqueries{0};
bool d_verboseLogging{false};
};
- using endpoints_t = std::pair<ComboAddress, std::optional<ComboAddress>>;
+ using endpoints_t = std::pair<ComboAddress, std::optional<pdns::AddressAndInterface>>;
void store(const struct timeval& now, const endpoints_t& endpoints, Connection&& connection);
Connection get(const endpoints_t& pair);
ComboAddress local(localAddress);
if (local == ComboAddress()) {
- local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
+ local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0).d_address;
}
AXFRRetriever axfr(logger, primary, zoneName, tsigTriplet, &local, maxReceivedBytes, axfrTimeout);
ComboAddress local(d_params.localAddress);
if (local == ComboAddress()) {
- local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
+ local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0).d_address;
}
try {
const TSIGTriplet tsigTriplet = config.d_tt;
ComboAddress local = config.d_local;
if (local == ComboAddress()) {
- local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
+ local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0).d_address;
}
AXFRRetriever axfr(d_log, primary, d_zone, tsigTriplet, &local, maxReceivedBytes, axfrTimeout);
ComboAddress local(localAddress);
if (local == ComboAddress()) {
- local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
+ local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0).d_address;
}
AXFRRetriever axfr(logger, primary, zoneName, tsigTriplet, &local, maxReceivedBytes, axfrTimeout);
ComboAddress local(params.zoneXFRParams.localAddress);
if (local == ComboAddress()) {
- local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
+ local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0).d_address;
}
try {
locals["default6"] = -1;
try {
if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET)) {
- locals["default4"] = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0), true, ::arg().mustDo("non-local-bind"));
+ locals["default4"] = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0).d_address, true, ::arg().mustDo("non-local-bind"));
}
if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET6)) {
- locals["default6"] = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0), true, ::arg().mustDo("non-local-bind"));
+ locals["default6"] = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0).d_address, true, ::arg().mustDo("non-local-bind"));
}
}
catch(...) {