Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions docs/dnssec/modes-of-operation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ DNSSEC data using the original keys.
Such a single replicated database requires no further attention beyond
monitoring already required during non-DNSSEC operations.

Please note that the ALIAS record type is
:ref:`not supported <alias_and_dnssec>` in this mode.

Records, Keys, signatures, hashes within PowerDNS in online signing mode
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
9 changes: 5 additions & 4 deletions docs/guides/alias.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ When set to 'ignore-errors', an unresolvable ALIAS target will be omitted from t
ALIAS and DNSSEC
----------------

Starting with the PowerDNS Authoritative Server 4.0.0, DNSSEC 'washing'
of ALIAS records is supported on AXFR (**not** on live-signing). Set
``outgoing-axfr-expand-alias`` to 'yes' and enable DNSSEC for the zone
on the primary. PowerDNS will sign the A/AAAA records during the AXFR.
Starting with the PowerDNS Authoritative Server 4.0.0, DNSSEC 'washing' of
ALIAS records is supported on AXFR. Set ``outgoing-axfr-expand-alias`` to
'yes' and enable DNSSEC for the zone on the primary. PowerDNS will sign the
A/AAAA records during the AXFR. Starting with PowerDNS Authoritative Server
?.?.?, live-signing is also supported.
45 changes: 44 additions & 1 deletion pdns/dnsproxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
#include "ednsoptions.hh"
#include "ednssubnet.hh"
#include "dnsproxy.hh"
#include "dnsseckeeper.hh"
#include "dnssecinfra.hh"
#include "ueberbackend.hh"

#include <boost/uuid/uuid_io.hpp>

Expand Down Expand Up @@ -111,7 +114,7 @@
}

//! look up qname 'target' with reply->qtype, plonk it in the answer section of 'reply' with name 'aname'
bool DNSProxy::completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, const uint8_t scopeMask)
bool DNSProxy::completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, const uint8_t scopeMask, const bool doSign, const std::set<ZoneName>& authSet, DNSSECKeeper& dnssecKeeper, UeberBackend& backend)
{
string ECSOptionStr;

Expand Down Expand Up @@ -157,6 +160,23 @@
ip.dr.d_name = aname;
reply->addRecord(std::move(ip));
}
if (doSign) {
try {
addRRSigs(dnssecKeeper, backend, authSet, reply->getRRS(), reply.get());
}
catch (const std::exception& e) {
SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << aname << " over TCP: " << e.what() << ", returning SERVFAIL" << endl,
d_slog->error(Logr::Error, e.what(), "Error signing ALIAS answer over TCP, returning SERVFAIL", "alias", Logging::Loggable(aname)));
reply->clearRecords();
reply->setRcode(RCode::ServFail);
}
catch (const PDNSException& e) {
SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << aname << " over TCP: " << e.reason << ", returning SERVFAIL" << endl,
d_slog->error(Logr::Error, e.reason, "Error signing ALIAS answer over TCP, returning SERVFAIL", "alias", Logging::Loggable(aname)));
reply->clearRecords();
reply->setRcode(RCode::ServFail);
}
}
}

uint16_t len = htons(reply->getString().length());
Expand Down Expand Up @@ -184,6 +204,8 @@
ce.complete = std::move(reply);
ce.aname = aname;
ce.anameScopeMask = scopeMask;
ce.doSign = doSign;
ce.authSet = authSet;
(*conntrack)[id] = std::move(ce);
}

Expand Down Expand Up @@ -234,6 +256,9 @@
{
setThreadName("pdns/dnsproxy");
try {
UeberBackend db;

Check warning on line 259 in pdns/dnsproxy.cc

View workflow job for this annotation

GitHub Actions / Analyze (cpp, auth)

variable name 'db' is too short, expected at least 3 characters (readability-identifier-length - Level=Warning)
DNSSECKeeper dk(d_slog, &db);

char buffer[1500];
ssize_t len;

Expand Down Expand Up @@ -324,6 +349,24 @@
}

iter->second.complete->setRcode(mdp.d_header.rcode);

if (iter->second.doSign) {
try {
addRRSigs(dk, db, iter->second.authSet, iter->second.complete->getRRS(), iter->second.complete.get());
}
catch (const std::exception& e) {
SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << iter->second.aname << ": " << e.what() << ", returning SERVFAIL" << endl,
d_slog->error(Logr::Error, e.what(), "Error signing ALIAS answer, returning SERVFAIL", "alias", Logging::Loggable(iter->second.aname)));
iter->second.complete->clearRecords();
iter->second.complete->setRcode(RCode::ServFail);
}
catch (const PDNSException& e) {
SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << iter->second.aname << ": " << e.reason << ", returning SERVFAIL" << endl,
d_slog->error(Logr::Error, e.reason, "Error signing ALIAS answer, returning SERVFAIL", "alias", Logging::Loggable(iter->second.aname)));
iter->second.complete->clearRecords();
iter->second.complete->setRcode(RCode::ServFail);
}
}
}
else {
SLOG(g_log << Logger::Error << "Error resolving for " << iter->second.aname << " ALIAS " << iter->second.qname << " over UDP, " << QType(iter->second.qtype).toString() << "-record query returned " << RCode::to_s(mdp.d_header.rcode) << ", returning SERVFAIL" << endl,
Expand Down
12 changes: 11 additions & 1 deletion pdns/dnsproxy.hh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
#pragma once
#include <map>
#include <set>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
Expand All @@ -29,6 +30,7 @@
#include "dnspacket.hh"
#include "lock.hh"
#include "iputils.hh"
#include "dnsname.hh"

#include "namespaces.hh"

Expand All @@ -48,13 +50,19 @@ to make sure outside parties can't spoof us.
To fix: how to remove the stale entries that will surely accumulate
*/

class DNSSECKeeper;
class UeberBackend;

class DNSProxy
{
public:
DNSProxy(Logr::log_t slog, const string& remote, const string& udpPortRange); //!< creates socket
~DNSProxy(); //<! dtor for DNSProxy
void go(); //!< launches the actual thread
bool completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, uint8_t scopeMask);
// dnssecKeeper and backend are only used for the TCP path, where signing
// happens synchronously in the caller's thread; the UDP path signs later in
// mainloop() using its own thread-local backend.
bool completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, uint8_t scopeMask, bool doSign, const std::set<ZoneName>& authSet, DNSSECKeeper& dnssecKeeper, UeberBackend& backend);

void mainloop(); //!< this is the main loop that receives reply packets and sends them out again
private:
Expand All @@ -65,7 +73,9 @@ private:
DNSName qname;
std::unique_ptr<DNSPacket> complete;
DNSName aname;
std::set<ZoneName> authSet;
uint8_t anameScopeMask;
bool doSign{false};
ComboAddress remote;
uint16_t id;
uint16_t qtype;
Expand Down
2 changes: 1 addition & 1 deletion pdns/packethandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,7 @@ bool PacketHandler::opcodeQueryInner2(DNSPacket& pkt, queryState &state, bool re
if(!haveAlias.empty() && (!weDone || pkt.qtype.getCode() == QType::ANY)) {
DLOG(SLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<state.target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl,
d_slog->info(Logr::Warning, "Found nothing that matched, but got alias, referring", "query", Logging::Loggable(state.target), "alias", Logging::Loggable(haveAlias))));
DP->completePacket(state.r, haveAlias, state.target, aliasScopeMask);
DP->completePacket(state.r, haveAlias, state.target, aliasScopeMask, d_dnssec, state.authSet, d_dk, B);
state.r = nullptr;
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion regression-tests.auth-py/authtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ def assertMatchingRRSIGInAnswer(self, msg, coveredRRset, keys=None):

if keys:
try:
dns.dnssec.validate(msgRRSet, msgRRsigRRSet.to_rdataset(), keys)
dns.dnssec.validate(msgRRSet, msgRRsigRRSet, keys)
except dns.dnssec.ValidationFailure as e:
raise AssertionError("Signature validation failed for %s:\n%s" % (msg.question[0].to_text(), e))

Expand Down
1 change: 1 addition & 0 deletions regression-tests.auth-py/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

wheel==0.46.3
dnspython
cryptography>=43
pytest
Twisted>0.15.0
requests>=2.18.4
Expand Down
Loading
Loading