]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/resolver.cc
fix nsec3 wrapping issue for insecure delegations
[thirdparty/pdns.git] / pdns / resolver.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
0c01dd7c 3 Copyright (C) 2002 - 2011 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
a640a9d4
BH
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation.
12c86877 8
f782fe38
MH
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
12c86877
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 21*/
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
731f58b8 25#include "utility.hh"
12c86877
BH
26#include "resolver.hh"
27#include <pthread.h>
28#include <semaphore.h>
29#include <iostream>
30#include <errno.h>
31#include "misc.hh"
32#include <algorithm>
33#include <sstream>
3696224d 34#include "dnsrecords.hh"
12c86877
BH
35#include <cstring>
36#include <string>
37#include <vector>
b8e0f341 38#include <boost/algorithm/string.hpp>
12c86877
BH
39#include "dns.hh"
40#include "qtype.hh"
ef03cc09 41
5c409fa2 42#include "pdnsexception.hh"
12c86877 43#include "arguments.hh"
7597b3cf 44#include "base64.hh"
88c1bc50
BH
45#include "dnswriter.hh"
46#include "dnsparser.hh"
dd7da6cd 47
fa8fd4d2 48
afbc704a 49#include "dns_random.hh"
ef03cc09 50#include <sys/poll.h>
51#include "gss_context.hh"
eb4e3090 52#include "namespaces.hh"
12c86877 53
0c01dd7c 54int makeQuerySocket(const ComboAddress& local, bool udpOrTCP)
12c86877 55{
0c01dd7c 56 ComboAddress ourLocal(local);
12c86877 57
0c01dd7c 58 int sock=socket(ourLocal.sin4.sin_family, udpOrTCP ? SOCK_DGRAM : SOCK_STREAM, 0);
5e2be4cf 59 if(sock < 0) {
883ad072 60 if(errno == EAFNOSUPPORT && local.sin4.sin_family == AF_INET6) {
0a462407 61 return -1;
883ad072
YG
62 }
63 unixDie("Creating local resolver socket for "+ourLocal.toString());
5e2be4cf 64 }
0c01dd7c 65
883ad072 66 setCloseOnExec(sock);
eabdf7e0
PD
67 if(udpOrTCP) {
68 // udp, try hard to bind an unpredictable port
0c01dd7c
BH
69 int tries=10;
70 while(--tries) {
71 ourLocal.sin4.sin_port = htons(10000+(dns_random(10000)));
72
73 if (::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) >= 0)
74 break;
75 }
eabdf7e0
PD
76 // cerr<<"bound udp port "<<ourLocal.sin4.sin_port<<", "<<tries<<" tries left"<<endl;
77
0c01dd7c 78 if(!tries) {
3897b9e1 79 closesocket(sock);
3f81d239 80 throw PDNSException("Resolver binding to local UDP socket on "+ourLocal.toString()+": "+stringerror());
0c01dd7c 81 }
12c86877 82 }
0c01dd7c 83 else {
eabdf7e0
PD
84 // tcp, let the kernel figure out the port
85 // cerr<<"letting kernel pick TCP port"<<endl;
0c01dd7c
BH
86 ourLocal.sin4.sin_port = 0;
87 if(::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) < 0)
3f81d239 88 throw PDNSException("Resolver binding to local TCP socket on "+ourLocal.toString()+": "+stringerror());
eab7dbda 89 }
0c01dd7c 90 return sock;
12c86877
BH
91}
92
93Resolver::Resolver()
0c01dd7c 94try
12c86877 95{
95302209 96 locals["default4"] = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true);
0a2915e2 97 if(!::arg()["query-local-address6"].empty())
95302209 98 locals["default6"] = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true);
0c01dd7c 99 else
95302209 100 locals["default6"] = -1;
12c86877 101}
0c01dd7c 102catch(...) {
95302209
AT
103 if(locals["default4"]>=0)
104 close(locals["default4"]);
0c01dd7c 105 throw;
12c86877
BH
106}
107
0c01dd7c 108Resolver::~Resolver()
12c86877 109{
677aa52d
AT
110 for(std::map<std::string,int>::iterator iter = locals.begin(); iter != locals.end(); iter++) {
111 if (iter->second >= 0)
4a1ab5ed 112 close(iter->second);
677aa52d 113 }
12c86877
BH
114}
115
95302209 116uint16_t Resolver::sendResolve(const ComboAddress& remote, const ComboAddress& local,
561434a6
PD
117 const DNSName &domain, int type, bool dnssecOK,
118 const DNSName& tsigkeyname, const DNSName& tsigalgorithm,
7597b3cf 119 const string& tsigsecret)
12c86877 120{
f0136bd5 121 uint16_t randomid;
88c1bc50
BH
122 vector<uint8_t> packet;
123 DNSPacketWriter pw(packet, domain, type);
f0136bd5 124 pw.getHeader()->id = randomid = dns_random(0xffff);
7eb7ac3d 125
48afcf83
BH
126 if(dnssecOK) {
127 pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
128 pw.commit();
129 }
7eb7ac3d 130
7597b3cf 131 if(!tsigkeyname.empty()) {
842c8dd2 132 // cerr<<"Adding TSIG to notification, key name: '"<<tsigkeyname<<"', algo: '"<<tsigalgorithm<<"', secret: "<<Base64Encode(tsigsecret)<<endl;
7597b3cf 133 TSIGRecordContent trc;
290a083d 134 if (tsigalgorithm == DNSName("hmac-md5"))
135 trc.d_algoName = tsigalgorithm + DNSName("sig-alg.reg.int");
a56bc64d
AT
136 else
137 trc.d_algoName = tsigalgorithm;
7597b3cf
BH
138 trc.d_time = time(0);
139 trc.d_fudge = 300;
f0136bd5 140 trc.d_origID=ntohs(randomid);
7597b3cf
BH
141 trc.d_eRcode=0;
142 addTSIG(pw, &trc, tsigkeyname, tsigsecret, "", false);
143 }
7eb7ac3d 144
95302209
AT
145 int sock;
146
147 // choose socket based on local
148 if (local.sin4.sin_family == 0) {
7eb7ac3d
KM
149 // up to us.
150 sock = remote.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
95302209 151 } else {
7eb7ac3d
KM
152 std::string lstr = local.toString();
153 std::map<std::string, int>::iterator lptr;
154 // see if there is a local
155
156 if ((lptr = locals.find(lstr)) != locals.end()) {
157 sock = lptr->second;
158 } else {
159 // try to make socket
160 sock = makeQuerySocket(local, true);
b841314c
RG
161 if (sock < 0)
162 throw ResolverException("Unable to create socket to "+remote.toStringWithPort()+": "+stringerror());
3897b9e1 163 setNonBlocking( sock );
7eb7ac3d
KM
164 locals[lstr] = sock;
165 }
95302209 166 }
7eb7ac3d 167
0c01dd7c
BH
168 if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
169 throw ResolverException("Unable to ask query of "+remote.toStringWithPort()+": "+stringerror());
170 }
f0136bd5 171 return randomid;
0c01dd7c 172}
48afcf83 173
561434a6 174uint16_t Resolver::sendResolve(const ComboAddress& remote, const DNSName &domain,
95302209 175 int type, bool dnssecOK,
561434a6 176 const DNSName& tsigkeyname, const DNSName& tsigalgorithm,
95302209
AT
177 const string& tsigsecret)
178{
4a1ab5ed
AT
179 ComboAddress local;
180 local.sin4.sin_family = 0;
181 return this->sendResolve(remote, local, domain, type, dnssecOK, tsigkeyname, tsigalgorithm, tsigsecret);
95302209
AT
182}
183
561434a6 184static int parseResult(MOADNSParser& mdp, const DNSName& origQname, uint16_t origQtype, uint16_t id, Resolver::res_t* result)
0c01dd7c
BH
185{
186 result->clear();
1813c5ff
KM
187
188 if(mdp.d_header.rcode)
ab4994df 189 return mdp.d_header.rcode;
1813c5ff 190
561434a6 191 if(origQname.countLabels()) { // not AXFR
ab4994df 192 if(mdp.d_header.id != id)
0c01dd7c 193 throw ResolverException("Remote nameserver replied with wrong id");
ab4994df
BH
194 if(mdp.d_header.qdcount != 1)
195 throw ResolverException("resolver: received answer with wrong number of questions ("+itoa(mdp.d_header.qdcount)+")");
561434a6
PD
196 if(mdp.d_qname != origQname)
197 throw ResolverException(string("resolver: received an answer to another question (")+mdp.d_qname.toString()+"!="+ origQname.toString()+".)");
12c86877 198 }
1813c5ff 199
914353ca 200 vector<DNSResourceRecord> ret;
0c01dd7c 201 DNSResourceRecord rr;
914353ca 202 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
f809c028 203 rr.qname = i->first.d_name;
0c01dd7c
BH
204 rr.qtype = i->first.d_type;
205 rr.ttl = i->first.d_ttl;
1813c5ff 206 rr.content = i->first.d_content->getZoneRepresentation(true);
0c01dd7c
BH
207 result->push_back(rr);
208 }
1813c5ff 209
0c01dd7c 210 return 0;
98e05fce 211}
12c86877 212
561434a6 213bool Resolver::tryGetSOASerial(DNSName *domain, uint32_t *theirSerial, uint32_t *theirInception, uint32_t *theirExpire, uint16_t* id)
98e05fce 214{
95302209
AT
215 struct pollfd *fds = new struct pollfd[locals.size()];
216 size_t i = 0, k;
0c01dd7c 217 int sock;
95302209
AT
218
219 for(std::map<string,int>::iterator iter=locals.begin(); iter != locals.end(); iter++, i++) {
220 fds[i].fd = iter->second;
221 fds[i].events = POLLIN;
222 }
223
224 if (poll(fds, i, 250) < 1) { // wait for 0.25s
7eb7ac3d
KM
225 delete [] fds;
226 return false;
95302209
AT
227 }
228
229 sock = -1;
230
231 // determine who
232 for(k=0;k<i;k++) {
233 if ((fds[k].revents & POLLIN) == POLLIN) {
234 sock = fds[k].fd;
235 break;
236 }
237 }
238
239 delete [] fds;
7eb7ac3d 240
95302209 241 if (sock < 0) return false; // false alarm
7eb7ac3d 242
3696224d
BH
243 int err;
244 ComboAddress fromaddr;
245 socklen_t addrlen=fromaddr.getSocklen();
0c01dd7c
BH
246 char buf[3000];
247 err = recvfrom(sock, buf, sizeof(buf), 0,(struct sockaddr*)(&fromaddr), &addrlen);
3696224d
BH
248 if(err < 0) {
249 if(errno == EAGAIN)
250 return false;
95302209 251
3696224d
BH
252 throw ResolverException("recvfrom error waiting for answer: "+stringerror());
253 }
95302209 254
0c01dd7c 255 MOADNSParser mdp((char*)buf, err);
3696224d 256 *id=mdp.d_header.id;
561434a6 257 *domain = mdp.d_qname;
3696224d
BH
258
259 if(mdp.d_answers.empty())
561434a6 260 throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' produced no results (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
3696224d 261
48afcf83 262 if(mdp.d_qtype != QType::SOA)
561434a6 263 throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' returned wrong record type");
12c86877 264
48afcf83
BH
265 *theirInception = *theirExpire = 0;
266 bool gotSOA=false;
ef7cd021 267 for(const MOADNSParser::answers_t::value_type& drc : mdp.d_answers) {
48afcf83 268 if(drc.first.d_type == QType::SOA) {
ba3c54cb
RG
269 shared_ptr<SOARecordContent> src=getRR<SOARecordContent>(drc.first);
270 if (src) {
271 *theirSerial=src->d_st.serial;
272 gotSOA = true;
273 }
48afcf83
BH
274 }
275 if(drc.first.d_type == QType::RRSIG) {
ba3c54cb
RG
276 shared_ptr<RRSIGRecordContent> rrc=getRR<RRSIGRecordContent>(drc.first);
277 if(rrc && rrc->d_type == QType::SOA) {
232f0877
CH
278 *theirInception= std::max(*theirInception, rrc->d_siginception);
279 *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
965f9774 280 }
48afcf83
BH
281 }
282 }
283 if(!gotSOA)
561434a6 284 throw ResolverException("Query to '" + fromaddr.toString() + "' for SOA of '" + domain->toString() + "' did not return a SOA");
3696224d
BH
285 return true;
286}
d3491d5a 287
561434a6 288int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res, const ComboAddress &local)
3696224d 289{
98e05fce 290 try {
0c01dd7c 291 ComboAddress to(ipport, 53);
a370ef31 292
95302209
AT
293 int id = sendResolve(to, local, domain, type);
294 int sock;
295
296 // choose socket based on local
297 if (local.sin4.sin_family == 0) {
7eb7ac3d
KM
298 // up to us.
299 sock = to.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
95302209 300 } else {
7eb7ac3d
KM
301 std::string lstr = local.toString();
302 std::map<std::string, int>::iterator lptr;
303 // see if there is a local
95302209 304
7eb7ac3d
KM
305 if ((lptr = locals.find(lstr)) != locals.end()) sock = lptr->second;
306 else throw ResolverException("sendResolve did not create socket for " + lstr);
95302209
AT
307 }
308
7108e055 309 int err=waitForData(sock, 0, 3000000);
0c01dd7c
BH
310
311 if(!err) {
312 throw ResolverException("Timeout waiting for answer");
313 }
314 if(err < 0)
315 throw ResolverException("Error waiting for answer: "+stringerror());
316
317 ComboAddress from;
318 socklen_t addrlen = sizeof(from);
319 char buffer[3000];
320 int len;
321
322 if((len=recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*)(&from), &addrlen)) < 0)
323 throw ResolverException("recvfrom error waiting for answer: "+stringerror());
324
ab4994df
BH
325 MOADNSParser mdp(buffer, len);
326 return parseResult(mdp, domain, type, id, res);
98e05fce
BH
327 }
328 catch(ResolverException &re) {
a370ef31 329 throw ResolverException(re.reason+" from "+ipport);
98e05fce 330 }
0c01dd7c 331 return -1;
98e05fce 332}
12c86877 333
561434a6 334int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res) {
4a1ab5ed
AT
335 ComboAddress local;
336 local.sin4.sin_family = 0;
337 return resolve(ipport, domain, type, res, local);
95302209 338}
12c86877 339
561434a6 340void Resolver::getSoaSerial(const string &ipport, const DNSName &domain, uint32_t *serial)
0c01dd7c
BH
341{
342 vector<DNSResourceRecord> res;
561434a6 343 int ret = resolve(ipport, domain, QType::SOA, &res);
3696224d 344
0c01dd7c 345 if(ret || res.empty())
561434a6 346 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced no answers");
12c86877 347
0c01dd7c 348 if(res[0].qtype.getCode() != QType::SOA)
561434a6 349 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced a "+res[0].qtype.getName()+" record");
0c01dd7c
BH
350
351 vector<string>parts;
352 stringtok(parts, res[0].content);
353 if(parts.size()<3)
561434a6 354 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable response");
3696224d 355
335da0ba 356 *serial=pdns_stou(parts[2]);
12c86877
BH
357}
358
fc396d56 359AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
98c9ec39 360 const DNSName& domain,
361 const TSIGTriplet& tt,
362 const ComboAddress* laddr)
363 : d_tt(tt), d_tsigPos(0), d_nonSignedMessages(0)
12c86877 364{
0c01dd7c 365 ComboAddress local;
fc396d56 366 if (laddr != NULL) {
4a1ab5ed 367 local = (ComboAddress) (*laddr);
fc396d56 368 } else {
4a1ab5ed
AT
369 if(remote.sin4.sin_family == AF_INET)
370 local=ComboAddress(::arg()["query-local-address"]);
371 else if(!::arg()["query-local-address6"].empty())
372 local=ComboAddress(::arg()["query-local-address6"]);
373 else
374 local=ComboAddress("::");
fc396d56 375 }
3ba05fa7
BH
376 d_sock = -1;
377 try {
378 d_sock = makeQuerySocket(local, false); // make a TCP socket
b841314c
RG
379 if (d_sock < 0)
380 throw ResolverException("Error creating socket for AXFR request to "+d_remote.toStringWithPort());
3ba05fa7
BH
381 d_buf = shared_array<char>(new char[65536]);
382 d_remote = remote; // mostly for error reporting
383 this->connect();
384 d_soacount = 0;
385
386 vector<uint8_t> packet;
387 DNSPacketWriter pw(packet, domain, QType::AXFR);
388 pw.getHeader()->id = dns_random(0xffff);
389
98c9ec39 390 if(!tt.name.empty()) {
391 if (tt.algo == DNSName("hmac-md5"))
392 d_trc.d_algoName = tt.algo + DNSName("sig-alg.reg.int");
a56bc64d 393 else
98c9ec39 394 d_trc.d_algoName = tt.algo;
3ba05fa7
BH
395 d_trc.d_time = time(0);
396 d_trc.d_fudge = 300;
397 d_trc.d_origID=ntohs(pw.getHeader()->id);
398 d_trc.d_eRcode=0;
98c9ec39 399 addTSIG(pw, &d_trc, tt.name, tt.secret, "", false);
3ba05fa7
BH
400 }
401
402 uint16_t replen=htons(packet.size());
403 Utility::iovec iov[2];
72a93ecc 404 iov[0].iov_base=reinterpret_cast<char*>(&replen);
3ba05fa7 405 iov[0].iov_len=2;
72a93ecc 406 iov[1].iov_base=packet.data();
3ba05fa7
BH
407 iov[1].iov_len=packet.size();
408
5b6d751e
BH
409 int ret=Utility::writev(d_sock, iov, 2);
410 if(ret < 0)
3ba05fa7 411 throw ResolverException("Error sending question to "+d_remote.toStringWithPort()+": "+stringerror());
5b6d751e
BH
412 if(ret != (int)(2+packet.size())) {
413 throw ResolverException("Partial write on AXFR request to "+d_remote.toStringWithPort());
414 }
3ba05fa7
BH
415
416 int res = waitForData(d_sock, 10, 0);
0c01dd7c 417
3ba05fa7
BH
418 if(!res)
419 throw ResolverException("Timeout waiting for answer from "+d_remote.toStringWithPort()+" during AXFR");
420 if(res<0)
421 throw ResolverException("Error waiting for answer from "+d_remote.toStringWithPort()+": "+stringerror());
422 }
423 catch(...) {
424 if(d_sock >= 0)
425 close(d_sock);
b841314c 426 d_sock = -1;
3ba05fa7 427 throw;
29b92d6f 428 }
12c86877
BH
429}
430
2577467d
BH
431AXFRRetriever::~AXFRRetriever()
432{
433 close(d_sock);
434}
12c86877 435
54d84273
PD
436
437
5aa12996 438int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records) // Implementation is making sure RFC2845 4.4 is followed.
12c86877 439{
0c01dd7c
BH
440 if(d_soacount > 1)
441 return false;
236e0c78 442
12c86877
BH
443 // d_sock is connected and is about to spit out a packet
444 int len=getLength();
445 if(len<0)
25b1d5d7 446 throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
12c86877 447
0c01dd7c 448 timeoutReadn(len);
ab4994df 449 MOADNSParser mdp(d_buf.get(), len);
236e0c78 450
5aa12996 451 int err;
452 if(!records)
453 err=parseResult(mdp, DNSName(), 0, 0, &res);
454 else {
455 records->clear();
456 for(const auto& r: mdp.d_answers)
457 records->push_back(r.first);
458 err = mdp.d_header.rcode;
459 }
460
236e0c78 461 if(err)
bf491f9b 462 throw ResolverException("AXFR chunk error: " + RCode::to_s(err));
236e0c78 463
ef7cd021 464 for(const MOADNSParser::answers_t::value_type& answer : mdp.d_answers)
236e0c78
PD
465 if (answer.first.d_type == QType::SOA)
466 d_soacount++;
467
98c9ec39 468 if(!d_tt.name.empty()) { // TSIG verify message
236e0c78
PD
469 // If we have multiple messages, we need to concatenate them together. We also need to make sure we know the location of
470 // the TSIG record so we can remove it in makeTSIGMessageFromTSIGPacket
471 d_signData.append(d_buf.get(), len);
472 if (mdp.getTSIGPos() == 0)
473 d_tsigPos += len;
474 else
475 d_tsigPos += mdp.getTSIGPos();
476
ab4994df 477 string theirMac;
54d84273 478 bool checkTSIG = false;
236e0c78 479
ef7cd021 480 for(const MOADNSParser::answers_t::value_type& answer : mdp.d_answers) {
236e0c78 481 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.
54d84273 482 checkTSIG = true;
236e0c78 483
5b6d751e 484 if(answer.first.d_type == QType::TSIG) {
ba3c54cb
RG
485 shared_ptr<TSIGRecordContent> trc = getRR<TSIGRecordContent>(answer.first);
486 if(trc) {
487 theirMac = trc->d_mac;
488 d_trc.d_time = trc->d_time;
489 checkTSIG = true;
490 }
5b6d751e 491 }
ab4994df 492 }
54d84273 493
236e0c78
PD
494 if( ! checkTSIG && d_nonSignedMessages > 99) { // We're allowed to get 100 digest without a TSIG.
495 throw ResolverException("No TSIG message received in last 100 messages of AXFR transfer.");
54d84273 496 }
54d84273 497
54d84273 498 if (checkTSIG) {
236e0c78 499 if (theirMac.empty())
98c9ec39 500 throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tt.name.toString()+"'");
236e0c78 501
54d84273
PD
502 string message;
503 if (!d_prevMac.empty()) {
98c9ec39 504 message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tt.name, d_trc, d_prevMac, true, d_signData.size()-len);
54d84273 505 } else {
98c9ec39 506 message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tt.name, d_trc, d_trc.d_mac, false);
54d84273 507 }
e820c305 508
785594c9
KM
509 TSIGHashEnum algo;
510 if (!getTSIGHashEnum(d_trc.d_algoName, algo)) {
4a51ff72 511 throw ResolverException("Unsupported TSIG HMAC algorithm " + d_trc.d_algoName.toString());
e820c305
AT
512 }
513
7f9ac49b 514 if (algo == TSIG_GSS) {
98c9ec39 515 GssContext gssctx(d_tt.name);
516 if (!gss_verify_signature(d_tt.name, message, theirMac)) {
517 throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tt.name.toString()+"'");
7f9ac49b
AT
518 }
519 } else {
98c9ec39 520 string ourMac=calculateHMAC(d_tt.secret, message, algo);
236e0c78 521
7f9ac49b
AT
522 // ourMac[0]++; // sabotage == for testing :-)
523 if(ourMac != theirMac) {
98c9ec39 524 throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tt.name.toString()+"'");
7f9ac49b 525 }
54d84273 526 }
a426be78 527
236e0c78
PD
528 // Reset and store some values for the next chunks.
529 d_prevMac = theirMac;
530 d_nonSignedMessages = 0;
531 d_signData.clear();
532 d_tsigPos = 0;
54d84273 533 }
236e0c78
PD
534 else
535 d_nonSignedMessages++;
54d84273 536 }
236e0c78 537
0c01dd7c
BH
538 return true;
539}
12c86877 540
0c01dd7c
BH
541void AXFRRetriever::timeoutReadn(uint16_t bytes)
542{
543 time_t start=time(0);
544 int n=0;
545 int numread;
546 while(n<bytes) {
016a0abb
PD
547 int res=waitForData(d_sock, 10-(time(0)-start));
548 if(res<0)
0c01dd7c 549 throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
016a0abb
PD
550 if(!res)
551 throw ResolverException("Timeout while reading data from remote nameserver over TCP");
0c01dd7c
BH
552
553 numread=recv(d_sock, d_buf.get()+n, bytes-n, 0);
554 if(numread<0)
555 throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
556 if(numread==0)
557 throw ResolverException("Remote nameserver closed TCP connection");
558 n+=numread;
559 }
12c86877
BH
560}
561
0c01dd7c 562void AXFRRetriever::connect()
12c86877 563{
3897b9e1 564 setNonBlocking( d_sock );
0c01dd7c
BH
565
566 int err;
567
568 if((err=::connect(d_sock,(struct sockaddr*)&d_remote, d_remote.getSocklen()))<0 && errno!=EINPROGRESS) {
3897b9e1 569 closesocket(d_sock);
0c01dd7c
BH
570 d_sock=-1;
571 throw ResolverException("connect: "+stringerror());
88c1bc50 572 }
0c01dd7c
BH
573
574 if(!err)
575 goto done;
576
577 err=waitForRWData(d_sock, false, 10, 0); // wait for writeability
578
579 if(!err) {
3897b9e1 580 closesocket(d_sock); // timeout
0c01dd7c
BH
581 d_sock=-1;
582 errno=ETIMEDOUT;
583
584 throw ResolverException("Timeout connecting to server");
88c1bc50 585 }
0c01dd7c
BH
586 else if(err < 0) {
587 throw ResolverException("Error connecting: "+string(strerror(err)));
849fde0b 588 }
0c01dd7c
BH
589 else {
590 Utility::socklen_t len=sizeof(err);
591 if(getsockopt(d_sock, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
592 throw ResolverException("Error connecting: "+stringerror()); // Solaris
593
594 if(err)
595 throw ResolverException("Error connecting: "+string(strerror(err)));
8b3cfcd3 596 }
0c01dd7c
BH
597
598 done:
3897b9e1 599 setBlocking( d_sock );
0c01dd7c 600 // d_sock now connected
12c86877
BH
601}
602
0c01dd7c 603int AXFRRetriever::getLength()
98e05fce 604{
0c01dd7c
BH
605 timeoutReadn(2);
606 return (unsigned char)d_buf[0]*256+(unsigned char)d_buf[1];
12c86877
BH
607}
608