]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ixfr.cc
Merge pull request #4963 from Habbie/dnsdist-doc-nit
[thirdparty/pdns.git] / pdns / ixfr.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
39ec5d29 22#include "ixfr.hh"
23#include "sstuff.hh"
24#include "dns_random.hh"
25#include "dnsrecords.hh"
189f9579 26#include "dnssecinfra.hh"
60a1c204 27#include "tsigverifier.hh"
7eafc52f 28
3e7dcee6 29// Returns pairs of "remove & add" vectors. If you get an empty remove, it means you got an AXFR!
30vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr,
db8f9152 31 const TSIGTriplet& tt, const ComboAddress* laddr, size_t maxReceivedBytes)
39ec5d29 32{
33 vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
34 vector<uint8_t> packet;
35 DNSPacketWriter pw(packet, zone, QType::IXFR);
36 pw.getHeader()->qr=0;
37 pw.getHeader()->rd=0;
38 pw.getHeader()->id=dns_random(0xffff);
189f9579 39 pw.startRecord(zone, QType::SOA, 0, QClass::IN, DNSResourceRecord::AUTHORITY);
39ec5d29 40 oursr.d_content->toPacket(pw);
189f9579 41
39ec5d29 42 pw.commit();
60a1c204
RG
43 TSIGRecordContent trc;
44 TSIGTCPVerifier tsigVerifier(tt, master, trc);
98c9ec39 45 if(!tt.algo.empty()) {
bd051ad6
PL
46 TSIGHashEnum the;
47 getTSIGHashEnum(tt.algo, the);
bd051ad6
PL
48 try {
49 trc.d_algoName = getTSIGAlgoName(the);
50 } catch(PDNSException& pe) {
51 throw std::runtime_error("TSIG algorithm '"+tt.algo.toString()+"' is unknown.");
52 }
189f9579 53 trc.d_time = time((time_t*)NULL);
54 trc.d_fudge = 300;
55 trc.d_origID=ntohs(pw.getHeader()->id);
56 trc.d_eRcode=0;
98c9ec39 57 addTSIG(pw, &trc, tt.name, tt.secret, "", false);
189f9579 58 }
39ec5d29 59 uint16_t len=htons(packet.size());
60 string msg((const char*)&len, 2);
61 msg.append((const char*)&packet[0], packet.size());
62
63 Socket s(master.sin4.sin_family, SOCK_STREAM);
64 // cout<<"going to connect"<<endl;
3e7dcee6 65 if(laddr)
66 s.bind(*laddr);
39ec5d29 67 s.connect(master);
68 // cout<<"Connected"<<endl;
69 s.writen(msg);
70
71 // CURRENT MASTER SOA
72 // REPEAT:
73 // SOA WHERE THIS DELTA STARTS
74 // RECORDS TO REMOVE
75 // SOA WHERE THIS DELTA GOES
76 // RECORDS TO ADD
77 // CURRENT MASTER SOA
78 shared_ptr<SOARecordContent> masterSOA;
79 vector<DNSRecord> records;
db8f9152 80 size_t receivedBytes = 0;
60a1c204 81
39ec5d29 82 for(;;) {
83 if(s.read((char*)&len, 2)!=2)
84 break;
85 len=ntohs(len);
86 // cout<<"Got chunk of "<<len<<" bytes"<<endl;
87 if(!len)
88 break;
db8f9152
RG
89
90 if (maxReceivedBytes > 0 && (maxReceivedBytes - receivedBytes) < (size_t) len)
91 throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toString()+"' from master '"+master.toStringWithPort());
92
39ec5d29 93 char reply[len];
94 readn2(s.getHandle(), reply, len);
db8f9152 95 receivedBytes += len;
27c0050c 96 MOADNSParser mdp(false, string(reply, len));
189f9579 97 if(mdp.d_header.rcode)
98 throw std::runtime_error("Got an error trying to IXFR zone '"+zone.toString()+"' from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
99
39ec5d29 100 // cout<<"Got a response, rcode: "<<mdp.d_header.rcode<<", got "<<mdp.d_answers.size()<<" answers"<<endl;
60a1c204
RG
101
102 if(!tt.algo.empty()) { // TSIG verify message
103 tsigVerifier.check(std::string(reply, len), mdp);
104 }
105
39ec5d29 106 for(auto& r: mdp.d_answers) {
189f9579 107 if(r.first.d_type == QType::TSIG)
108 continue;
39ec5d29 109 // cout<<r.first.d_name<< " " <<r.first.d_content->getZoneRepresentation()<<endl;
110 r.first.d_name = r.first.d_name.makeRelative(zone);
111 records.push_back(r.first);
112 if(r.first.d_type == QType::SOA) {
ba3c54cb
RG
113 auto sr = getRR<SOARecordContent>(r.first);
114 if(sr) {
115 if(!masterSOA) {
116 if(sr->d_st.serial == std::dynamic_pointer_cast<SOARecordContent>(oursr.d_content)->d_st.serial) { // we are up to date
117 goto done;
118 }
119 masterSOA=sr;
120 }
121 else if(sr->d_st.serial == masterSOA->d_st.serial)
39ec5d29 122 goto done;
39ec5d29 123 }
39ec5d29 124 }
125 }
126 }
127 // cout<<"Got "<<records.size()<<" records"<<endl;
128 done:;
129 for(unsigned int pos = 1;pos < records.size();) {
ba3c54cb 130 auto sr = getRR<SOARecordContent>(records[pos]);
7eafc52f 131 vector<DNSRecord> remove, add;
132 if(!sr) { // this is an actual AXFR!
133 return {{remove, records}};
134 }
39ec5d29 135 if(sr->d_st.serial == masterSOA->d_st.serial)
136 break;
137
7eafc52f 138
39ec5d29 139 remove.push_back(records[pos]); // this adds the SOA
140 for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
141 remove.push_back(records[pos]);
142 }
ba3c54cb 143 sr = getRR<SOARecordContent>(records[pos]);
39ec5d29 144
145 add.push_back(records[pos]); // this adds the new SOA
146 for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
147 add.push_back(records[pos]);
148 }
149 ret.push_back(make_pair(remove,add));
150 }
151 return ret;
152}