]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/saxfr.cc
Fix number conversions in core
[thirdparty/pdns.git] / pdns / saxfr.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "base64.hh"
5 #include "dnsparser.hh"
6 #include "sstuff.hh"
7 #include "misc.hh"
8 #include "dnswriter.hh"
9 #include "dnsrecords.hh"
10 #include "statbag.hh"
11 #include "base32.hh"
12 #include "dnssecinfra.hh"
13
14 #include "dns_random.hh"
15 #include "gss_context.hh"
16
17 StatBag S;
18
19 bool validateTSIG(const string& message, const TSIGHashEnum& algo, const DNSName& key, const string& secret, const TSIGRecordContent *trc) {
20 int64_t now = time(0);
21 if(abs(static_cast<int64_t>(trc->d_time) - now) > trc->d_fudge) {
22 cerr<<"TSIG (key '"<<key<<"') time delta "<< abs(static_cast<int64_t>(trc->d_time) - now)<<" > 'fudge' "<<trc->d_fudge<<endl;
23 return false;
24 }
25 if (algo == TSIG_GSS) {
26 // authorization is done later
27 GssContext gssctx(key);
28 if (!gssctx.valid()) {
29 cerr<<"no context"<<endl;
30 return false;
31 }
32 if (!gssctx.verify(message, trc->d_mac)) {
33 cerr<<"invalid mac"<<endl;
34 return false;
35 }
36 return true;
37 }
38 return calculateHMAC(secret, message, algo) == trc->d_mac;
39 }
40
41
42 int main(int argc, char** argv)
43 try
44 {
45 if(argc < 4) {
46 cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [gss:remote-principal] [tsig:keyname:algo:secret]"<<endl;
47 exit(EXIT_FAILURE);
48 }
49
50 bool showdetails=false;
51 bool showflags=false;
52 bool unhash=false;
53 bool gss=false;
54 bool tsig=false;
55 TSIGHashEnum tsig_algo;
56 DNSName tsig_key;
57 string tsig_secret;
58 string tsigprevious;
59 string remote_principal;
60
61 if (argc > 4) {
62 for(int i=4; i<argc; i++) {
63 if (strcmp(argv[i], "showdetails") == 0)
64 showdetails=true;
65 if (strcmp(argv[i], "showflags") == 0)
66 showflags=true;
67 if (strcmp(argv[i], "unhash") == 0)
68 unhash=true;
69 if (strncmp(argv[i], "gss:",4) == 0) {
70 gss=true;
71 tsig=true;
72 tsig_algo=TSIG_GSS;
73 remote_principal = string(argv[i]+4);
74 if (remote_principal.empty()) {
75 cerr<<"Remote principal is required"<<endl;
76 exit(EXIT_FAILURE);
77 }
78 }
79 if (strncmp(argv[i], "tsig:",5) == 0) {
80 vector<string> parts;
81 tsig=true;
82 stringtok(parts, argv[i], ":");
83 if (parts.size()!=4) {
84 cerr<<"Invalid syntax for tsig"<<endl;
85 exit(EXIT_FAILURE);
86 }
87 if (!getTSIGHashEnum(DNSName(parts[2]), tsig_algo)) {
88 cerr<<"Cannot understand TSIG algorithm '"<<parts[1]<<"'"<<endl;
89 exit(EXIT_FAILURE);
90 }
91 tsig_key = DNSName(parts[1]);
92 if (tsig_key == DNSName()) {
93 cerr<<"Key name must be set for tsig"<<endl;
94 exit(EXIT_FAILURE);
95 }
96 if (B64Decode(parts[3], tsig_secret)) {
97 cerr<<"Secret must be base64 encoded"<<endl;
98 exit(EXIT_FAILURE);
99 }
100 if (tsig_secret.size()==0) {
101 cerr<<"Secret must be set for tsig"<<endl;
102 exit(EXIT_FAILURE);
103 }
104 }
105 }
106 }
107
108 reportAllTypes();
109 dns_random_init("0123456789abcdef");
110
111 vector<uint8_t> packet;
112 uint16_t len;
113 ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
114 Socket sock(dest.sin4.sin_family, SOCK_STREAM);
115 sock.connect(dest);
116
117 if (gss) {
118 #ifndef ENABLE_GSS_TSIG
119 cerr<<"No GSS support compiled in"<<endl;
120 exit(EXIT_FAILURE);
121 #else
122 string input,output;
123 GssContext gssctx;
124 gssctx.generateLabel(argv[3]);
125 gssctx.setPeerPrincipal(remote_principal);
126
127 while(gssctx.init(input, output) && gssctx.valid() == false) {
128 input="";
129 DNSPacketWriter pwtkey(packet, gssctx.getLabel(), QType::TKEY, QClass::ANY);
130 TKEYRecordContent tkrc;
131 tkrc.d_algo = DNSName("gss-tsig.");
132 tkrc.d_inception = time((time_t*)NULL);
133 tkrc.d_expiration = tkrc.d_inception+15;
134 tkrc.d_mode = 3;
135 tkrc.d_error = 0;
136 tkrc.d_keysize = output.size();
137 tkrc.d_key = output;
138 tkrc.d_othersize = 0;
139 pwtkey.getHeader()->id = dns_random(0xffff);
140 pwtkey.startRecord(gssctx.getLabel(), QType::TKEY, 3600, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
141 tkrc.toPacket(pwtkey);
142 pwtkey.commit();
143 for(const string& msg : gssctx.getErrorStrings()) {
144 cerr<<msg<<endl;
145 }
146
147 len = htons(packet.size());
148 if(sock.write((char *) &len, 2) != 2)
149 throw PDNSException("tcp write failed");
150 sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
151 if(sock.read((char *) &len, 2) != 2)
152 throw PDNSException("tcp read failed");
153
154 len=ntohs(len);
155 char *creply = new char[len];
156 int n=0;
157 int numread;
158 while(n<len) {
159 numread=sock.read(creply+n, len-n);
160 if(numread<0)
161 throw PDNSException("tcp read failed");
162 n+=numread;
163 }
164
165 MOADNSParser mdp(string(creply, len));
166 if (mdp.d_header.rcode != 0) {
167 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
168 }
169 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
170 if(i->first.d_type != QType::TKEY) continue;
171 // recover TKEY record
172 tkrc = TKEYRecordContent(i->first.d_content->getZoneRepresentation());
173 input = tkrc.d_key;
174 }
175 }
176
177 if (gssctx.valid() == false) {
178 cerr<<"Could not create GSS context"<<endl;
179 exit(EXIT_FAILURE);
180 }
181
182 tsig_key = DNSName(gssctx.getLabel());
183 #endif
184 }
185
186 DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
187
188 pw.getHeader()->id = dns_random(0xffff);
189
190 if (tsig) {
191 TSIGRecordContent trc;
192 trc.d_algoName = getTSIGAlgoName(tsig_algo);
193 trc.d_time = time((time_t*)NULL);
194 trc.d_fudge = 300;
195 trc.d_origID=ntohs(pw.getHeader()->id);
196 trc.d_eRcode=0;
197 addTSIG(pw, &trc, tsig_key, tsig_secret, "", false);
198 }
199
200 len = htons(packet.size());
201 if(sock.write((char *) &len, 2) != 2)
202 throw PDNSException("tcp write failed");
203
204 sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
205
206 bool isNSEC3 = false;
207 int soacount=0;
208 vector<pair<DNSName,string> > records;
209 set<DNSName> labels;
210 map<string,DNSName> hashes;
211 NSEC3PARAMRecordContent ns3pr;
212
213 while(soacount<2) {
214 TSIGRecordContent trc;
215
216 if(sock.read((char *) &len, 2) != 2)
217 throw PDNSException("tcp read failed");
218
219 len=ntohs(len);
220 char *creply = new char[len];
221 int n=0;
222 int numread;
223 while(n<len) {
224 numread=sock.read(creply+n, len-n);
225 if(numread<0)
226 throw PDNSException("tcp read failed");
227 n+=numread;
228 }
229
230 string packet = string(creply, len);
231
232 MOADNSParser mdp(packet);
233 if (mdp.d_header.rcode != 0) {
234 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
235 }
236 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
237 if (i->first.d_type == QType::TSIG) {
238 string message;
239 if (!tsig) {
240 std::cerr<<"Unexpected TSIG signature in data"<<endl;
241 }
242 trc = TSIGRecordContent(i->first.d_content->getZoneRepresentation());
243 continue;
244 }
245 if(i->first.d_type == QType::SOA)
246 {
247 ++soacount;
248 }
249 else if (i->first.d_type == QType::NSEC3PARAM) {
250 ns3pr = NSEC3PARAMRecordContent(i->first.d_content->getZoneRepresentation());
251 isNSEC3 = true;
252 }
253
254 ostringstream o;
255 o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
256 if(showdetails)
257 {
258 o<<"\t"<<i->first.d_content->getZoneRepresentation();
259 }
260 else if(i->first.d_type == QType::RRSIG)
261 {
262 string zoneRep = i->first.d_content->getZoneRepresentation();
263 vector<string> parts;
264 stringtok(parts, zoneRep);
265 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
266 }
267 else if(i->first.d_type == QType::NSEC3)
268 {
269 string zoneRep = i->first.d_content->getZoneRepresentation();
270 vector<string> parts;
271 stringtok(parts, zoneRep);
272 o<<"\t"<<parts[0]<<" ";
273 if (showflags)
274 o<<parts[1];
275 else
276 o<<"[flags]";
277 o<<" "<<parts[2]<<" "<<parts[3]<<" "<<"[next owner]";
278 for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
279 o<<" "<<*iter;
280 }
281 else if(i->first.d_type == QType::DNSKEY)
282 {
283 string zoneRep = i->first.d_content->getZoneRepresentation();
284 vector<string> parts;
285 stringtok(parts, zoneRep);
286 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
287 }
288 else
289 {
290 o<<"\t"<<i->first.d_content->getZoneRepresentation();
291 }
292
293 records.push_back(make_pair(i->first.d_name,o.str()));
294
295 DNSName shorter(i->first.d_name);
296 do {
297 labels.insert(shorter);
298 if (shorter == DNSName(argv[3]))
299 break;
300 }while(shorter.chopOff());
301
302 }
303
304 delete[] creply;
305 }
306
307 if (isNSEC3 && unhash)
308 {
309 string hashed;
310 for(const auto &label: labels) {
311 hashed=toBase32Hex(hashQNameWithSalt(ns3pr, label));
312 hashes.insert(pair<string,DNSName>(hashed, label));
313 }
314 }
315
316 for(auto &record: records) {
317 DNSName label /* FIXME400 rename */=record.first;
318 if (isNSEC3 && unhash)
319 {
320 auto i = hashes.find(label.makeRelative(DNSName(argv[3])).toStringNoDot());
321 if (i != hashes.end())
322 label=i->second;
323 }
324 cout<<label.toString()<<record.second<<endl;
325 }
326
327 }
328 catch(PDNSException &e2) {
329 cerr<<"Fatal: "<<e2.reason<<endl;
330 }
331 catch(std::exception &e)
332 {
333 cerr<<"Fatal: "<<e.what()<<endl;
334 }