]>
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 | */ | |
aea0480e | 22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
18ca5fa4 | 25 | #include "arguments.hh" |
aea0480e | 26 | #include "base64.hh" |
ae7af19f | 27 | |
aea0480e | 28 | #include "misc.hh" |
aea0480e | 29 | #include "dnsrecords.hh" |
30 | #include "statbag.hh" | |
31 | #include "base32.hh" | |
32 | #include "dnssecinfra.hh" | |
fa8fd4d2 | 33 | |
aea0480e | 34 | #include "dns_random.hh" |
35 | #include "gss_context.hh" | |
7cc1c350 | 36 | #include <boost/multi_index_container.hpp> |
18ca5fa4 | 37 | #include "resolver.hh" |
7cc1c350 | 38 | #include <fstream> |
39ec5d29 | 39 | #include "ixfr.hh" |
4db8fd44 | 40 | #include "ixfrutils.hh" |
aea0480e | 41 | StatBag S; |
42 | ||
18ca5fa4 | 43 | ArgvMap &arg() |
7cc1c350 | 44 | { |
18ca5fa4 | 45 | static ArgvMap theArg; |
46 | return theArg; | |
47 | } | |
48 | ||
4ce666fd PL |
49 | void usage() { |
50 | cerr<<"Syntax: ixplore diff ZONE BEFORE_FILE AFTER_FILE"<<endl; | |
51 | cerr<<"Syntax: ixplore track IP-ADDRESS PORT ZONE DIRECTORY [TSIGKEY TSIGALGO TSIGSECRET]"<<endl; | |
52 | } | |
53 | ||
ae7af19f PL |
54 | int main(int argc, char** argv) { |
55 | try { | |
56 | for(int n=1 ; n < argc; ++n) { | |
57 | if ((string) argv[n] == "--help") { | |
58 | usage(); | |
59 | return EXIT_SUCCESS; | |
60 | } | |
4ce666fd | 61 | |
ae7af19f PL |
62 | if ((string) argv[n] == "--version") { |
63 | cerr<<"ixplore "<<VERSION<<endl; | |
64 | return EXIT_SUCCESS; | |
65 | } | |
4ce666fd | 66 | } |
4ce666fd | 67 | |
ae7af19f PL |
68 | reportAllTypes(); |
69 | string command; | |
70 | if(argc < 5 || (command=argv[1], (command!="diff" && command !="track"))) { | |
71 | usage(); | |
72 | exit(EXIT_FAILURE); | |
18ca5fa4 | 73 | } |
ae7af19f PL |
74 | if(command=="diff") { |
75 | records_t before, after; | |
76 | DNSName zone(argv[2]); | |
77 | cout<<"Loading before from "<<argv[3]<<endl; | |
78 | loadZoneFromDisk(before, argv[3], zone); | |
f79adaa3 PL |
79 | cout<<"Parsed "<<before.size()<<" records"<<endl; |
80 | cout<<"Zone was complete (SOA at end)"<<endl; | |
ae7af19f PL |
81 | cout<<"Loading after from "<<argv[4]<<endl; |
82 | loadZoneFromDisk(after, argv[4], zone); | |
f79adaa3 PL |
83 | cout<<"Parsed "<<after.size()<<" records"<<endl; |
84 | cout<<"Zone was complete (SOA at end)"<<endl; | |
ae7af19f PL |
85 | |
86 | vector<DNSRecord> diff; | |
87 | ||
88 | set_difference(before.cbegin(), before.cend(), after.cbegin(), after.cend(), back_inserter(diff), before.value_comp()); | |
89 | for(const auto& d : diff) { | |
90 | cout<<'-'<< (d.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(d.d_type)<<" "<<d.d_content->getZoneRepresentation()<<endl; | |
91 | } | |
92 | diff.clear(); | |
93 | set_difference(after.cbegin(), after.cend(), before.cbegin(), before.cend(), back_inserter(diff), before.value_comp()); | |
94 | for(const auto& d : diff) { | |
95 | cout<<'+'<< (d.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(d.d_type)<<" "<<d.d_content->getZoneRepresentation()<<endl; | |
96 | } | |
97 | exit(1); | |
18ca5fa4 | 98 | } |
ae7af19f PL |
99 | |
100 | // must be "track" then | |
aea0480e | 101 | |
7cc1c350 | 102 | /* goal in life: |
ae7af19f PL |
103 | in directory/zone-name we leave files with their name the serial number |
104 | at startup, retrieve current SOA SERIAL for domain from master server | |
aea0480e | 105 | |
ae7af19f PL |
106 | compare with what the best is we have in our directory, IXFR from that. |
107 | Store result in memory, read that best zone in memory, apply deltas, write it out. | |
aea0480e | 108 | |
ae7af19f | 109 | Next up, loop this every REFRESH seconds */ |
aea0480e | 110 | |
ae7af19f PL |
111 | DNSName zone(argv[4]); |
112 | ComboAddress master(argv[2], atoi(argv[3])); | |
113 | string directory(argv[5]); | |
114 | records_t records; | |
7cc1c350 | 115 | |
28942414 | 116 | uint32_t ourSerial = getSerialFromDir(directory); |
7cc1c350 | 117 | |
ae7af19f | 118 | cout<<"Loading zone, our highest available serial is "<< ourSerial<<endl; |
98c9ec39 | 119 | |
ae7af19f PL |
120 | TSIGTriplet tt; |
121 | if(argc > 6) | |
122 | tt.name=DNSName(toLower(argv[6])); | |
123 | if(argc > 7) | |
124 | tt.algo=DNSName(toLower(argv[7])); | |
189f9579 | 125 | |
ae7af19f PL |
126 | if(argc > 8) { |
127 | if(B64Decode(argv[8], tt.secret) < 0) { | |
128 | cerr<<"Could not decode tsig secret!"<<endl; | |
129 | exit(EXIT_FAILURE); | |
7cc1c350 | 130 | } |
131 | } | |
132 | ||
ae7af19f PL |
133 | try { |
134 | if(!ourSerial) | |
135 | throw std::runtime_error("There is no local zone available"); | |
136 | string fname=directory+"/"+std::to_string(ourSerial); | |
137 | cout<<"Loading serial number "<<ourSerial<<" from file "<<fname<<endl; | |
138 | loadZoneFromDisk(records, fname, zone); | |
f79adaa3 PL |
139 | cout<<"Parsed "<<records.size()<<" records"<<endl; |
140 | cout<<"Zone was complete (SOA at end)"<<endl; | |
18ca5fa4 | 141 | } |
ae7af19f PL |
142 | catch(std::exception& e) { |
143 | cout<<"Could not load zone from disk: "<<e.what()<<endl; | |
144 | cout<<"Retrieving latest from master "<<master.toStringWithPort()<<endl; | |
145 | ComboAddress local = master.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::"); | |
146 | AXFRRetriever axfr(master, zone, tt, &local); | |
147 | unsigned int nrecords=0; | |
148 | Resolver::res_t nop; | |
149 | vector<DNSRecord> chunk; | |
150 | char wheel[]="|/-\\"; | |
151 | int count=0; | |
152 | time_t last=0; | |
153 | while(axfr.getChunk(nop, &chunk)) { | |
154 | for(auto& dr : chunk) { | |
155 | if(dr.d_type == QType::TSIG) | |
156 | continue; | |
157 | dr.d_name.makeUsRelative(zone); | |
158 | records.insert(dr); | |
159 | nrecords++; | |
160 | } | |
161 | ||
162 | if(last != time(0)) { | |
163 | cout << '\r' << wheel[count % (sizeof(wheel)-1)] << ' ' <<nrecords; | |
164 | count++; | |
165 | cout.flush(); | |
166 | last=time(0); | |
167 | } | |
7eafc52f | 168 | } |
ae7af19f PL |
169 | cout <<"\rDone, got "<<nrecords<<" "<<endl; |
170 | cout<<"Writing to disk.."<<endl; | |
171 | writeZoneToDisk(records, zone, directory); | |
172 | } | |
7eafc52f | 173 | |
ae7af19f PL |
174 | for(;;) { |
175 | DNSRecord ourSoa; | |
176 | ourSerial = getSerialFromRecords(records, ourSoa); | |
177 | ||
178 | cout<<"Checking for update, our serial number is "<<ourSerial<<".. "; | |
179 | cout.flush(); | |
180 | shared_ptr<SOARecordContent> sr; | |
181 | uint32_t serial = getSerialFromMaster(master, zone, sr, tt); | |
182 | if(ourSerial == serial) { | |
183 | cout<<"still up to date, their serial is "<<serial<<", sleeping "<<sr->d_st.refresh<<" seconds"<<endl; | |
184 | sleep(sr->d_st.refresh); | |
185 | continue; | |
7cc1c350 | 186 | } |
7cc1c350 | 187 | |
ae7af19f PL |
188 | cout<<"got new serial: "<<serial<<", initiating IXFR!"<<endl; |
189 | auto deltas = getIXFRDeltas(master, zone, ourSoa, tt); | |
190 | cout<<"Got "<<deltas.size()<<" deltas, applying.."<<endl; | |
191 | ||
192 | for(const auto& delta : deltas) { | |
193 | ||
194 | const auto& remove = delta.first; | |
195 | const auto& add = delta.second; | |
196 | ||
197 | ourSerial=getSerialFromRecords(records, ourSoa); | |
198 | uint32_t newserial=0; | |
199 | for(const auto& rr : add) { | |
200 | if(rr.d_type == QType::SOA) { | |
201 | newserial=std::dynamic_pointer_cast<SOARecordContent>(rr.d_content)->d_st.serial; | |
202 | } | |
203 | } | |
204 | ||
205 | cout<<"This delta ("<<ourSerial<<" - "<<newserial<<") has "<<remove.size()<<" removals, "<<add.size()<<" additions"<<endl; | |
206 | ofstream report(directory +"/delta."+std::to_string(ourSerial)+"-"+std::to_string(newserial)); | |
207 | if(remove.empty()) { | |
208 | cout<<"This delta is a whole new zone"<<endl; | |
209 | report<<"- everything, whole new zone update follow"<<endl; | |
210 | records.clear(); | |
211 | } | |
212 | ||
213 | bool stop=false; | |
214 | ||
215 | for(const auto& rr : remove) { | |
216 | report<<'-'<< (rr.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(rr.d_type)<<" "<<rr.d_content->getZoneRepresentation()<<endl; | |
217 | auto range = records.equal_range(tie(rr.d_name, rr.d_type, rr.d_class, rr.d_content)); | |
218 | if(range.first == range.second) { | |
219 | cout<<endl<<" !! Could not find record "<<rr.d_name<<" to remove!!"<<endl; | |
220 | // stop=true; | |
221 | report.flush(); | |
222 | } | |
223 | records.erase(range.first, range.second); | |
224 | } | |
225 | ||
226 | for(const auto& rr : add) { | |
227 | report<<'+'<< (rr.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(rr.d_type)<<" "<<rr.d_content->getZoneRepresentation()<<endl; | |
228 | records.insert(rr); | |
229 | } | |
230 | if(stop) { | |
231 | cerr<<"Had error condition, stopping.."<<endl; | |
232 | report.flush(); | |
233 | exit(1); | |
234 | } | |
7cc1c350 | 235 | } |
ae7af19f PL |
236 | cout<<"Writing zone to disk.. "; cout.flush(); |
237 | writeZoneToDisk(records, zone, directory); | |
238 | cout<<"Done"<<endl; | |
7cc1c350 | 239 | } |
240 | } | |
ae7af19f PL |
241 | catch(PDNSException &e2) { |
242 | cerr<<"Fatal: "<<e2.reason<<endl; | |
243 | } | |
244 | catch(std::exception &e) | |
245 | { | |
246 | cerr<<"Fatal: "<<e.what()<<endl; | |
247 | } | |
248 | catch(...) | |
249 | { | |
250 | cerr<<"Any other exception"<<endl; | |
251 | } | |
18ca5fa4 | 252 | } |