]>
Commit | Line | Data |
---|---|---|
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! |
30 | vector<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 | } |