Skip to content

Commit

Permalink
DNSRecord: Ensure that the content can be read or replaced, not edited
Browse files Browse the repository at this point in the history
  • Loading branch information
rgacogne committed Mar 17, 2023
1 parent 467ad1f commit d06dcda
Show file tree
Hide file tree
Showing 77 changed files with 675 additions and 620 deletions.
4 changes: 2 additions & 2 deletions modules/lmdbbackend/lmdbbackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ bool LMDBBackend::get(DNSZoneRecord& zr)
zr.domain_id = compoundOrdername::getDomainID(key);
zr.dr.d_type = compoundOrdername::getQType(key).getCode();
zr.dr.d_ttl = lrr.ttl;
zr.dr.d_content = deserializeContentZR(zr.dr.d_type, zr.dr.d_name, lrr.content);
zr.dr.setContent(deserializeContentZR(zr.dr.d_type, zr.dr.d_name, lrr.content));
zr.auth = lrr.auth;
}

Expand Down Expand Up @@ -903,7 +903,7 @@ bool LMDBBackend::get(DNSResourceRecord& rr)
rr.qname = zr.dr.d_name;
rr.ttl = zr.dr.d_ttl;
rr.qtype = zr.dr.d_type;
rr.content = zr.dr.d_content->getZoneRepresentation(true);
rr.content = zr.dr.getContent()->getZoneRepresentation(true);
rr.domain_id = zr.domain_id;
rr.auth = zr.auth;
rr.disabled = zr.disabled;
Expand Down
8 changes: 4 additions & 4 deletions pdns/auth-catalogzone.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ DNSZoneRecord CatalogInfo::getCatalogVersionRecord(const DNSName& zone)
dzr.dr.d_name = DNSName("version") + zone;
dzr.dr.d_ttl = 0;
dzr.dr.d_type = QType::TXT;
dzr.dr.d_content = std::make_shared<TXTRecordContent>("2");
dzr.dr.setContent(std::make_shared<TXTRecordContent>("2"));
return dzr;
}

Expand All @@ -135,22 +135,22 @@ void CatalogInfo::toDNSZoneRecords(const DNSName& zone, vector<DNSZoneRecord>& d
dzr.dr.d_name = prefix;
dzr.dr.d_ttl = 0;
dzr.dr.d_type = QType::PTR;
dzr.dr.d_content = std::make_shared<PTRRecordContent>(d_zone.toString());
dzr.dr.setContent(std::make_shared<PTRRecordContent>(d_zone.toString()));
dzrs.emplace_back(dzr);

if (!d_coo.empty()) {
dzr.dr.d_name = DNSName("coo") + prefix;
dzr.dr.d_ttl = 0;
dzr.dr.d_type = QType::PTR;
dzr.dr.d_content = std::make_shared<PTRRecordContent>(d_coo);
dzr.dr.setContent(std::make_shared<PTRRecordContent>(d_coo));
dzrs.emplace_back(dzr);
}

for (const auto& group : d_group) {
dzr.dr.d_name = DNSName("group") + prefix;
dzr.dr.d_ttl = 0;
dzr.dr.d_type = QType::TXT;
dzr.dr.d_content = std::make_shared<TXTRecordContent>("\"" + group + "\"");
dzr.dr.setContent(std::make_shared<TXTRecordContent>("\"" + group + "\""));
dzrs.emplace_back(dzr);
}
}
2 changes: 1 addition & 1 deletion pdns/communicator.hh
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public:
DNSZoneRecord rr;
while(b->get(rr))
if(rr.dr.d_type == QType::A || rr.dr.d_type==QType::AAAA)
addresses.push_back(rr.dr.d_content->getZoneRepresentation()); // SOL if you have a CNAME for an NS
addresses.push_back(rr.dr.getContent()->getZoneRepresentation()); // SOL if you have a CNAME for an NS
}
return addresses;
}
Expand Down
5 changes: 2 additions & 3 deletions pdns/dbdnsseckeeper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -638,12 +638,11 @@ void DNSSECKeeper::getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, ui
const auto rr = *rrs.rbegin();

DNSZoneRecord dzr;
std::shared_ptr<RRSIGRecordContent> rrsig;

db.lookup(QType(QType::RRSIG), !rr.wildcardname.empty() ? rr.wildcardname : rr.dr.d_name, rr.domain_id);
while(db.get(dzr)) {
rrsig = getRR<RRSIGRecordContent>(dzr.dr);
if(rrsig->d_type == rr.dr.d_type) {
auto rrsig = getRR<RRSIGRecordContent>(dzr.dr);
if (rrsig->d_type == rr.dr.d_type) {
if(!rr.wildcardname.empty()) {
dzr.dr.d_name = rr.dr.d_name;
}
Expand Down
4 changes: 2 additions & 2 deletions pdns/dnsbulktest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,14 @@ struct SendReceive
dr.rcode = mdp.d_header.rcode;
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
if(i->first.d_place == 1 && i->first.d_type == mdp.d_qtype)
dr.ips.push_back(ComboAddress(i->first.d_content->getZoneRepresentation()));
dr.ips.push_back(ComboAddress(i->first.getContent()->getZoneRepresentation()));
if(i->first.d_place == 2 && i->first.d_type == QType::SOA) {
dr.seenauthsoa = true;
}
if(!g_quiet)
{
cout<<i->first.d_place-1<<"\t"<<i->first.d_name<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.getContent()->getZoneRepresentation()<<"\n";
}
}

Expand Down
2 changes: 1 addition & 1 deletion pdns/dnsdistdist/test-dnsdist-dnsparser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(test_Response)
BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::CNAME));
BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
auto content = std::dynamic_pointer_cast<UnknownRecordContent>(mdp.d_answers.at(0).first.d_content);
auto content = getRR<UnknownRecordContent>(mdp.d_answers.at(0).first);
BOOST_REQUIRE(content != nullptr);
BOOST_CHECK_EQUAL(content->getRawContent().size(), notTheTarget.getStorage().size());

Expand Down
8 changes: 4 additions & 4 deletions pdns/dnspacket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ void DNSPacket::addRecord(DNSZoneRecord&& rr)
// in case we are not compressing for AXFR, no such checking is performed!

if(d_compress) {
std::string ser = const_cast<DNSZoneRecord&>(rr).dr.d_content->serialize(rr.dr.d_name);
std::string ser = rr.dr.getContent()->serialize(rr.dr.d_name);
auto hash = boost::hash< std::pair<DNSName, std::string> >()({rr.dr.d_name, ser});
if(d_dedup.count(hash)) { // might be a dup
for(auto & i : d_rrs) {
Expand Down Expand Up @@ -354,7 +354,7 @@ void DNSPacket::wrapup(bool throwsOnTruncation)
maxScopeMask = max(maxScopeMask, pos->scopeMask);

pw.startRecord(pos->dr.d_name, pos->dr.d_type, pos->dr.d_ttl, pos->dr.d_class, pos->dr.d_place);
pos->dr.d_content->toPacket(pw);
pos->dr.getContent()->toPacket(pw);
if(pw.size() + optsize > (d_tcp ? 65535 : getMaxReplyLen())) {
if (throwsOnTruncation) {
throw PDNSException("attempt to write an oversized chunk");
Expand Down Expand Up @@ -516,7 +516,7 @@ bool DNSPacket::getTSIGDetails(TSIGRecordContent* trc, DNSName* keyname, uint16_
for(const auto & answer : mdp.d_answers) {
if(answer.first.d_type == QType::TSIG && answer.first.d_class == QType::ANY) {
// cast can fail, f.e. if d_content is an UnknownRecordContent.
shared_ptr<TSIGRecordContent> content = std::dynamic_pointer_cast<TSIGRecordContent>(answer.first.d_content);
auto content = getRR<TSIGRecordContent>(answer.first);
if (!content) {
g_log<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl;
return false;
Expand Down Expand Up @@ -549,7 +549,7 @@ bool DNSPacket::getTKEYRecord(TKEYRecordContent *tr, DNSName *keyname) const

if(answer.first.d_type == QType::TKEY) {
// cast can fail, f.e. if d_content is an UnknownRecordContent.
shared_ptr<TKEYRecordContent> content = std::dynamic_pointer_cast<TKEYRecordContent>(answer.first.d_content);
auto content = getRR<TKEYRecordContent>(answer.first);
if (!content) {
g_log<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl;
return false;
Expand Down
8 changes: 4 additions & 4 deletions pdns/dnsparser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ string UnknownRecordContent::getZoneRepresentation(bool /* noDot */) const
return str.str();
}

void UnknownRecordContent::toPacket(DNSPacketWriter& pw)
void UnknownRecordContent::toPacket(DNSPacketWriter& pw) const
{
pw.xfrBlob(string(d_record.begin(),d_record.end()));
}
Expand Down Expand Up @@ -211,7 +211,7 @@ DNSResourceRecord DNSResourceRecord::fromWire(const DNSRecord& d) {
rr.qname = d.d_name;
rr.qtype = QType(d.d_type);
rr.ttl = d.d_ttl;
rr.content = d.d_content->getZoneRepresentation(true);
rr.content = d.getContent()->getZoneRepresentation(true);
rr.auth = false;
rr.qclass = d.d_class;
return rr;
Expand Down Expand Up @@ -279,11 +279,11 @@ void MOADNSParser::init(bool query, const std::string_view& packet)
!(d_qtype == QType::IXFR && dr.d_place == DNSResourceRecord::AUTHORITY && dr.d_type == QType::SOA) && // IXFR queries have a SOA in their AUTHORITY section
(dr.d_place == DNSResourceRecord::ANSWER || dr.d_place == DNSResourceRecord::AUTHORITY || (dr.d_type != QType::OPT && dr.d_type != QType::TSIG && dr.d_type != QType::SIG && dr.d_type != QType::TKEY) || ((dr.d_type == QType::TSIG || dr.d_type == QType::SIG || dr.d_type == QType::TKEY) && dr.d_class != QClass::ANY))) {
// cerr<<"discarding RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
dr.d_content=std::make_shared<UnknownRecordContent>(dr, pr);
dr.setContent(std::make_shared<UnknownRecordContent>(dr, pr));
}
else {
// cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
dr.d_content=DNSRecordContent::mastermake(dr, pr, d_header.opcode);
dr.setContent(DNSRecordContent::mastermake(dr, pr, d_header.opcode));
}

/* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned:
Expand Down
29 changes: 23 additions & 6 deletions pdns/dnsparser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ public:

virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
virtual ~DNSRecordContent() {}
virtual void toPacket(DNSPacketWriter& pw)=0;
virtual void toPacket(DNSPacketWriter& pw) const = 0;
// returns the wire format of the content, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set)
virtual string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard because we use the same method (xfrPacket) for both kinds of conversion (fromPacket, toPacket)
string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) const
{
vector<uint8_t> packet;
DNSPacketWriter pw(packet, g_rootdnsname, 1);
Expand Down Expand Up @@ -312,7 +312,9 @@ struct DNSRecord
d_place(place) {}

DNSName d_name;
std::shared_ptr<DNSRecordContent> d_content;
private:
std::shared_ptr<const DNSRecordContent> d_content;
public:
uint16_t d_type{};
uint16_t d_class{};
uint32_t d_ttl{};
Expand All @@ -331,6 +333,21 @@ struct DNSRecord
return s.str();
}

void setContent(const std::shared_ptr<const DNSRecordContent>& content)
{
d_content = content;
}

void setContent(std::shared_ptr<const DNSRecordContent>&& content)
{
d_content = std::move(content);
}

[[nodiscard]] const std::shared_ptr<const DNSRecordContent>& getContent() const
{
return d_content;
}

bool operator<(const DNSRecord& rhs) const
{
if(std::tie(d_name, d_type, d_class, d_ttl) < std::tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
Expand Down Expand Up @@ -416,7 +433,7 @@ public:
UnknownRecordContent(const string& zone);

string getZoneRepresentation(bool noDot) const override;
void toPacket(DNSPacketWriter& pw) override;
void toPacket(DNSPacketWriter& pw) const override;
uint16_t getType() const override
{
return d_dr.d_type;
Expand Down Expand Up @@ -486,9 +503,9 @@ bool getEDNSUDPPayloadSizeAndZ(const char* packet, size_t length, uint16_t* payl
bool visitDNSPacket(const std::string_view& packet, const std::function<bool(uint8_t, uint16_t, uint16_t, uint32_t, uint16_t, const char*)>& visitor);

template<typename T>
std::shared_ptr<T> getRR(const DNSRecord& dr)
std::shared_ptr<const T> getRR(const DNSRecord& dr)
{
return std::dynamic_pointer_cast<T>(dr.d_content);
return std::dynamic_pointer_cast<const T>(dr.getContent());
}

/** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs
Expand Down
4 changes: 2 additions & 2 deletions pdns/dnsproxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ void DNSProxy::mainloop()
MOADNSParser mdp(false, p.getString());
// cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
if (mdp.d_header.rcode == RCode::NoError) {
for(const auto & answer : mdp.d_answers) {
for (auto& answer : mdp.d_answers) {
// cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
if(answer.first.d_place == DNSResourceRecord::ANSWER || (answer.first.d_place == DNSResourceRecord::AUTHORITY && answer.first.d_type == QType::SOA)) {

Expand All @@ -262,7 +262,7 @@ void DNSProxy::mainloop()
dzr.dr.d_type = answer.first.d_type;
dzr.dr.d_ttl=answer.first.d_ttl;
dzr.dr.d_place= answer.first.d_place;
dzr.dr.d_content=answer.first.d_content;
dzr.dr.setContent(answer.first.getContent());
i->second.complete->addRecord(std::move(dzr));
}
}
Expand Down
18 changes: 6 additions & 12 deletions pdns/dnsrecords.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,13 @@ string LUARecordContent::getCode() const
}
#endif

void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options)
void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) const
{
string::size_type pos=0;
uint16_t code, len;
while(d_data.size() >= 4 + pos) {
code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1];
len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3];
code = 256 * (unsigned char)d_data.at(pos) + (unsigned char)d_data.at(pos+1);
len = 256 * (unsigned char)d_data.at(pos+2) + (unsigned char)d_data.at(pos+3);
pos+=4;

if(pos + len > d_data.size())
Expand Down Expand Up @@ -471,7 +471,7 @@ std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone)
}
return ret;
}
void EUI48RecordContent::toPacket(DNSPacketWriter& pw)
void EUI48RecordContent::toPacket(DNSPacketWriter& pw) const
{
string blob(d_eui48, d_eui48+6);
pw.xfrBlob(blob);
Expand Down Expand Up @@ -516,7 +516,7 @@ std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone)
}
return ret;
}
void EUI64RecordContent::toPacket(DNSPacketWriter& pw)
void EUI64RecordContent::toPacket(DNSPacketWriter& pw) const
{
string blob(d_eui64, d_eui64+8);
pw.xfrBlob(blob);
Expand Down Expand Up @@ -687,7 +687,7 @@ std::shared_ptr<DNSRecordContent> APLRecordContent::make(const string& zone) {


// DNSRecord to Packet conversion
void APLRecordContent::toPacket(DNSPacketWriter& pw) {
void APLRecordContent::toPacket(DNSPacketWriter& pw) const {
for (auto & ard : aplrdata) {
pw.xfr16BitInt(ard.d_family);
pw.xfr8BitInt(ard.d_prefix);
Expand Down Expand Up @@ -859,12 +859,6 @@ static uint16_t makeTag(const std::string& data)
}

uint16_t DNSKEYRecordContent::getTag() const
{
DNSKEYRecordContent tmp(*this);
return makeTag(tmp.serialize(DNSName())); // this can't be const for some reason
}

uint16_t DNSKEYRecordContent::getTag()
{
return makeTag(this->serialize(DNSName()));
}
Expand Down
Loading

0 comments on commit d06dcda

Please sign in to comment.