pdns-recursor: add patch for CVE-2022-27227
Signed-off-by: Peter van Dijk <peter.van.dijk@powerdns.com>
This commit is contained in:
parent
f618daa55f
commit
216a37d655
1 changed files with 171 additions and 0 deletions
171
net/pdns-recursor/patches/300-cve-2022-27227.patch
Normal file
171
net/pdns-recursor/patches/300-cve-2022-27227.patch
Normal file
|
@ -0,0 +1,171 @@
|
|||
--- a/ixfr.cc
|
||||
+++ b/ixfr.cc
|
||||
@@ -123,7 +123,7 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
}
|
||||
|
||||
// Returns pairs of "remove & add" vectors. If you get an empty remove, it means you got an AXFR!
|
||||
-vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr,
|
||||
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& primary, const DNSName& zone, const DNSRecord& oursr,
|
||||
const TSIGTriplet& tt, const ComboAddress* laddr, size_t maxReceivedBytes)
|
||||
{
|
||||
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
|
||||
@@ -137,7 +137,7 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
|
||||
pw.commit();
|
||||
TSIGRecordContent trc;
|
||||
- TSIGTCPVerifier tsigVerifier(tt, master, trc);
|
||||
+ TSIGTCPVerifier tsigVerifier(tt, primary, trc);
|
||||
if(!tt.algo.empty()) {
|
||||
TSIGHashEnum the;
|
||||
getTSIGHashEnum(tt.algo, the);
|
||||
@@ -156,11 +156,11 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
string msg((const char*)&len, 2);
|
||||
msg.append((const char*)&packet[0], packet.size());
|
||||
|
||||
- Socket s(master.sin4.sin_family, SOCK_STREAM);
|
||||
+ Socket s(primary.sin4.sin_family, SOCK_STREAM);
|
||||
// cout<<"going to connect"<<endl;
|
||||
if(laddr)
|
||||
s.bind(*laddr);
|
||||
- s.connect(master);
|
||||
+ s.connect(primary);
|
||||
// cout<<"Connected"<<endl;
|
||||
s.writen(msg);
|
||||
|
||||
@@ -171,16 +171,24 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
// SOA WHERE THIS DELTA GOES
|
||||
// RECORDS TO ADD
|
||||
// CURRENT MASTER SOA
|
||||
- std::shared_ptr<SOARecordContent> masterSOA = nullptr;
|
||||
+ std::shared_ptr<SOARecordContent> primarySOA = nullptr;
|
||||
vector<DNSRecord> records;
|
||||
size_t receivedBytes = 0;
|
||||
- int8_t ixfrInProgress = -2;
|
||||
std::string reply;
|
||||
|
||||
+ enum transferStyle { Unknown, AXFR, IXFR } style = Unknown;
|
||||
+ const unsigned int expectedSOAForAXFR = 2;
|
||||
+ const unsigned int expectedSOAForIXFR = 3;
|
||||
+ unsigned int primarySOACount = 0;
|
||||
+
|
||||
for(;;) {
|
||||
- // IXFR end
|
||||
- if (ixfrInProgress >= 0)
|
||||
+ // IXFR or AXFR style end reached? We don't want to process trailing data after the closing SOA
|
||||
+ if (style == AXFR && primarySOACount == expectedSOAForAXFR) {
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (style == IXFR && primarySOACount == expectedSOAForIXFR) {
|
||||
break;
|
||||
+ }
|
||||
|
||||
if(s.read((char*)&len, sizeof(len)) != sizeof(len))
|
||||
break;
|
||||
@@ -191,7 +199,7 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
break;
|
||||
|
||||
if (maxReceivedBytes > 0 && (maxReceivedBytes - receivedBytes) < (size_t) len)
|
||||
- throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toLogString()+"' from master "+master.toStringWithPort());
|
||||
+ throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toLogString()+"' from primary "+primary.toStringWithPort());
|
||||
|
||||
reply.resize(len);
|
||||
readn2(s.getHandle(), &reply.at(0), len);
|
||||
@@ -199,7 +207,7 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
|
||||
MOADNSParser mdp(false, reply);
|
||||
if(mdp.d_header.rcode)
|
||||
- throw std::runtime_error("Got an error trying to IXFR zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
|
||||
+ throw std::runtime_error("Got an error trying to IXFR zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
|
||||
|
||||
// cout<<"Got a response, rcode: "<<mdp.d_header.rcode<<", got "<<mdp.d_answers.size()<<" answers"<<endl;
|
||||
|
||||
@@ -209,32 +217,47 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
|
||||
for(auto& r: mdp.d_answers) {
|
||||
// cout<<r.first.d_name<< " " <<r.first.d_content->getZoneRepresentation()<<endl;
|
||||
- if(!masterSOA) {
|
||||
+ if(!primarySOA) {
|
||||
// we have not seen the first SOA record yet
|
||||
if (r.first.d_type != QType::SOA) {
|
||||
- throw std::runtime_error("The first record of the IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"' is not a SOA ("+QType(r.first.d_type).getName()+")");
|
||||
+ throw std::runtime_error("The first record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"' is not a SOA ("+QType(r.first.d_type).getName()+")");
|
||||
}
|
||||
|
||||
auto sr = getRR<SOARecordContent>(r.first);
|
||||
if (!sr) {
|
||||
- throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"'");
|
||||
+ throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'");
|
||||
}
|
||||
|
||||
if(sr->d_st.serial == std::dynamic_pointer_cast<SOARecordContent>(oursr.d_content)->d_st.serial) {
|
||||
// we are up to date
|
||||
return ret;
|
||||
}
|
||||
- masterSOA = sr;
|
||||
+ primarySOA = sr;
|
||||
+ ++primarySOACount;
|
||||
} else if (r.first.d_type == QType::SOA) {
|
||||
auto sr = getRR<SOARecordContent>(r.first);
|
||||
if (!sr) {
|
||||
- throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort()+"'");
|
||||
+ throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'");
|
||||
}
|
||||
|
||||
- // we hit the last SOA record
|
||||
- // IXFR is considered to be done if we hit the last SOA record twice
|
||||
- if (masterSOA->d_st.serial == sr->d_st.serial) {
|
||||
- ixfrInProgress++;
|
||||
+ // we hit a marker SOA record
|
||||
+ if (primarySOA->d_st.serial == sr->d_st.serial) {
|
||||
+ ++primarySOACount;
|
||||
+ }
|
||||
+ }
|
||||
+ // When we see the 2nd record, we can decide what the style is
|
||||
+ if (records.size() == 1 && style == Unknown) {
|
||||
+ if (r.first.d_type != QType::SOA) {
|
||||
+ // Non-empty AXFR style has a non-SOA record following the first SOA
|
||||
+ style = AXFR;
|
||||
+ }
|
||||
+ else if (primarySOACount == expectedSOAForAXFR) {
|
||||
+ // Empty zone AXFR style: start SOA is immediately followed by end marker SOA
|
||||
+ style = AXFR;
|
||||
+ }
|
||||
+ else {
|
||||
+ // IXFR has a 2nd SOA (with different serial) following the first
|
||||
+ style = IXFR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +268,7 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
if(r.first.d_type == QType::OPT)
|
||||
continue;
|
||||
|
||||
- throw std::runtime_error("Unexpected record (" +QType(r.first.d_type).getName()+") in non-answer section ("+std::to_string(r.first.d_place)+")in IXFR response for zone '"+zone.toLogString()+"' from master '"+master.toStringWithPort());
|
||||
+ throw std::runtime_error("Unexpected record (" +QType(r.first.d_type).getName()+") in non-answer section ("+std::to_string(r.first.d_place)+")in IXFR response for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort());
|
||||
}
|
||||
|
||||
r.first.d_name.makeUsRelative(zone);
|
||||
@@ -253,7 +276,21 @@ vector<pair<vector<DNSRecord>, vector<DN
|
||||
}
|
||||
}
|
||||
|
||||
- // cout<<"Got "<<records.size()<<" records"<<endl;
|
||||
+ switch (style) {
|
||||
+ case IXFR:
|
||||
+ if (primarySOACount != expectedSOAForIXFR) {
|
||||
+ throw std::runtime_error("Incomplete IXFR transfer for '" + zone.toLogString() + "' from primary '" + primary.toStringWithPort());
|
||||
+ }
|
||||
+ break;
|
||||
+ case AXFR:
|
||||
+ if (primarySOACount != expectedSOAForAXFR){
|
||||
+ throw std::runtime_error("Incomplete AXFR style transfer for '" + zone.toLogString() + "' from primary '" + primary.toStringWithPort());
|
||||
+ }
|
||||
+ break;
|
||||
+ case Unknown:
|
||||
+ throw std::runtime_error("Incomplete XFR for '" + zone.toLogString() + "' from primary '" + primary.toStringWithPort());
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
- return processIXFRRecords(master, zone, records, masterSOA);
|
||||
+ return processIXFRRecords(primary, zone, records, primarySOA);
|
||||
}
|
Loading…
Reference in a new issue