void addRRSigs(DNSSECKeeper& dk, DNSBackend& db, const std::set<string, CIStringCompare>& authMap, vector<DNSResourceRecord>& rrs);
string calculateMD5HMAC(const std::string& key_, const std::string& text);
-string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigoffset, const string& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly);
+string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigoffset, const string& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset=0);
void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const string& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly);
#endif
AXFRRetriever::AXFRRetriever(const ComboAddress& remote, const string& domain, const string& tsigkeyname, const string& tsigalgorithm,
const string& tsigsecret)
-: d_tsigkeyname(tsigkeyname), d_tsigsecret(tsigsecret), d_nonSignedMessages(0)
+: d_tsigkeyname(tsigkeyname), d_tsigsecret(tsigsecret), d_nonSignedMessages(0), d_tsigPos(0)
{
ComboAddress local;
if(remote.sin4.sin_family == AF_INET)
{
if(d_soacount > 1)
return false;
+
// d_sock is connected and is about to spit out a packet
int len=getLength();
-
if(len<0)
throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
timeoutReadn(len);
-
MOADNSParser mdp(d_buf.get(), len);
-
+
+ int err = parseResult(mdp, "", 0, 0, &res);
+ if(err)
+ throw ResolverException("AXFR chunk with a non-zero rcode "+lexical_cast<string>(err));
+
+ BOOST_FOREACH(const MOADNSParser::answers_t::value_type& answer, mdp.d_answers)
+ if (answer.first.d_type == QType::SOA)
+ d_soacount++;
+
if(!d_tsigkeyname.empty()) { // TSIG verify message
+ // If we have multiple messages, we need to concatenate them together. We also need to make sure we know the location of
+ // the TSIG record so we can remove it in makeTSIGMessageFromTSIGPacket
+ d_signData.append(d_buf.get(), len);
+ if (mdp.getTSIGPos() == 0)
+ d_tsigPos += len;
+ else
+ d_tsigPos += mdp.getTSIGPos();
+
string theirMac;
bool checkTSIG = false;
- d_nonSignedMessages++;
+
BOOST_FOREACH(const MOADNSParser::answers_t::value_type& answer, mdp.d_answers) {
- if (answer.first.d_type == QType::SOA) { // A SOA is either the first or the last record. We need to check TSIG if that's the case.
+ if (answer.first.d_type == QType::SOA) // A SOA is either the first or the last record. We need to check TSIG if that's the case.
checkTSIG = true;
- }
+
if(answer.first.d_type == QType::TSIG) {
shared_ptr<TSIGRecordContent> trc = boost::dynamic_pointer_cast<TSIGRecordContent>(answer.first.d_content);
theirMac = trc->d_mac;
}
}
-
- if(d_nonSignedMessages > 99) { // We're allowed to get 100 digest without a TSIG.
- L<<Logger::Info<<"Received 100th envelope for AXFR transfer."<<endl;
- checkTSIG = true;
+ if( ! checkTSIG && d_nonSignedMessages > 99) { // We're allowed to get 100 digest without a TSIG.
+ throw ResolverException("No TSIG message received in last 100 messages of AXFR transfer.");
}
-
- if(theirMac.empty() && checkTSIG)
- throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tsigkeyname+"'");
-
if (checkTSIG) {
+ if (theirMac.empty())
+ throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tsigkeyname+"'");
+
string message;
if (!d_prevMac.empty()) {
- message = makeTSIGMessageFromTSIGPacket(string(d_buf.get(), len), mdp.getTSIGPos(), d_tsigkeyname, d_trc, d_prevMac, true);
+ message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_prevMac, true, d_signData.size()-len);
} else {
- message = makeTSIGMessageFromTSIGPacket(string(d_buf.get(), len), mdp.getTSIGPos(), d_tsigkeyname, d_trc, d_trc.d_mac, false); // insert our question MAC
+ message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_trc.d_mac, false);
}
-
string ourMac=calculateMD5HMAC(d_tsigsecret, message);
+
// ourMac[0]++; // sabotage == for testing :-)
if(ourMac != theirMac) {
throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname+"'");
}
- d_prevMac = theirMac; // store the mac for the next chunk, see RFC2845 4.4
- d_nonSignedMessages = 0; // reset message count, as we now allow another 100 to not be signed.
- }
- }
-
- int err = parseResult(mdp, "", 0, 0, &res);
- if(err)
- throw ResolverException("AXFR chunk with a non-zero rcode "+lexical_cast<string>(err));
-
-
- vector<uint32_t> removeItems;
- for(Resolver::res_t::const_iterator i= res.begin(); i!=res.end(); ++i) {
- if(i->qtype.getCode()==QType::SOA) {
- d_soacount++;
- if (d_soacount>1)
- removeItems.push_back(i-res.begin());
- }
- }
-
- if (!removeItems.empty()) {
- BOOST_FOREACH(uint32_t i, removeItems) {
- res.erase(res.begin()+i);
+ // Reset and store some values for the next chunks.
+ d_prevMac = theirMac;
+ d_nonSignedMessages = 0;
+ d_signData.clear();
+ d_tsigPos = 0;
}
+ else
+ d_nonSignedMessages++;
}
-
+
return true;
}