]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/resolver.cc
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[thirdparty/pdns.git] / pdns / resolver.cc
CommitLineData
12c86877 1/*
6edbf68a
PL
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 */
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"
d824de38 50#include <poll.h>
ef03cc09 51#include "gss_context.hh"
eb4e3090 52#include "namespaces.hh"
12c86877 53
f688119e 54int makeQuerySocket(const ComboAddress& local, bool udpOrTCP, bool nonLocalBind)
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);
f688119e
RG
67
68 if(nonLocalBind)
69 Utility::setBindAny(local.sin4.sin_family, sock);
70
eabdf7e0
PD
71 if(udpOrTCP) {
72 // udp, try hard to bind an unpredictable port
0c01dd7c
BH
73 int tries=10;
74 while(--tries) {
75 ourLocal.sin4.sin_port = htons(10000+(dns_random(10000)));
76
77 if (::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) >= 0)
78 break;
79 }
eabdf7e0
PD
80 // cerr<<"bound udp port "<<ourLocal.sin4.sin_port<<", "<<tries<<" tries left"<<endl;
81
0c01dd7c 82 if(!tries) {
3897b9e1 83 closesocket(sock);
3f81d239 84 throw PDNSException("Resolver binding to local UDP socket on "+ourLocal.toString()+": "+stringerror());
0c01dd7c 85 }
12c86877 86 }
0c01dd7c 87 else {
eabdf7e0
PD
88 // tcp, let the kernel figure out the port
89 // cerr<<"letting kernel pick TCP port"<<endl;
0c01dd7c
BH
90 ourLocal.sin4.sin_port = 0;
91 if(::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) < 0)
3f81d239 92 throw PDNSException("Resolver binding to local TCP socket on "+ourLocal.toString()+": "+stringerror());
eab7dbda 93 }
0c01dd7c 94 return sock;
12c86877
BH
95}
96
97Resolver::Resolver()
98{
2056e985
CH
99 locals["default4"] = -1;
100 locals["default6"] = -1;
101 try {
f688119e 102 locals["default4"] = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true, ::arg().mustDo("non-local-bind"));
2056e985 103 if(!::arg()["query-local-address6"].empty())
f688119e 104 locals["default6"] = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true, ::arg().mustDo("non-local-bind"));
2056e985
CH
105 }
106 catch(...) {
107 if(locals["default4"]>=0)
108 close(locals["default4"]);
109 throw;
110 }
12c86877
BH
111}
112
0c01dd7c 113Resolver::~Resolver()
12c86877 114{
677aa52d
AT
115 for(std::map<std::string,int>::iterator iter = locals.begin(); iter != locals.end(); iter++) {
116 if (iter->second >= 0)
4a1ab5ed 117 close(iter->second);
677aa52d 118 }
12c86877
BH
119}
120
95302209 121uint16_t Resolver::sendResolve(const ComboAddress& remote, const ComboAddress& local,
561434a6
PD
122 const DNSName &domain, int type, bool dnssecOK,
123 const DNSName& tsigkeyname, const DNSName& tsigalgorithm,
7597b3cf 124 const string& tsigsecret)
12c86877 125{
f0136bd5 126 uint16_t randomid;
88c1bc50
BH
127 vector<uint8_t> packet;
128 DNSPacketWriter pw(packet, domain, type);
f0136bd5 129 pw.getHeader()->id = randomid = dns_random(0xffff);
7eb7ac3d 130
48afcf83
BH
131 if(dnssecOK) {
132 pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
133 pw.commit();
134 }
7eb7ac3d 135
7597b3cf 136 if(!tsigkeyname.empty()) {
842c8dd2 137 // cerr<<"Adding TSIG to notification, key name: '"<<tsigkeyname<<"', algo: '"<<tsigalgorithm<<"', secret: "<<Base64Encode(tsigsecret)<<endl;
7597b3cf 138 TSIGRecordContent trc;
290a083d 139 if (tsigalgorithm == DNSName("hmac-md5"))
140 trc.d_algoName = tsigalgorithm + DNSName("sig-alg.reg.int");
a56bc64d
AT
141 else
142 trc.d_algoName = tsigalgorithm;
7597b3cf
BH
143 trc.d_time = time(0);
144 trc.d_fudge = 300;
f0136bd5 145 trc.d_origID=ntohs(randomid);
7597b3cf 146 trc.d_eRcode=0;
ea3816cf 147 addTSIG(pw, trc, tsigkeyname, tsigsecret, "", false);
7597b3cf 148 }
7eb7ac3d 149
95302209
AT
150 int sock;
151
152 // choose socket based on local
153 if (local.sin4.sin_family == 0) {
7eb7ac3d
KM
154 // up to us.
155 sock = remote.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
95302209 156 } else {
7eb7ac3d
KM
157 std::string lstr = local.toString();
158 std::map<std::string, int>::iterator lptr;
159 // see if there is a local
160
161 if ((lptr = locals.find(lstr)) != locals.end()) {
162 sock = lptr->second;
163 } else {
164 // try to make socket
165 sock = makeQuerySocket(local, true);
b841314c
RG
166 if (sock < 0)
167 throw ResolverException("Unable to create socket to "+remote.toStringWithPort()+": "+stringerror());
3897b9e1 168 setNonBlocking( sock );
7eb7ac3d
KM
169 locals[lstr] = sock;
170 }
95302209 171 }
7eb7ac3d 172
0c01dd7c
BH
173 if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
174 throw ResolverException("Unable to ask query of "+remote.toStringWithPort()+": "+stringerror());
175 }
f0136bd5 176 return randomid;
0c01dd7c 177}
48afcf83 178
561434a6 179uint16_t Resolver::sendResolve(const ComboAddress& remote, const DNSName &domain,
95302209 180 int type, bool dnssecOK,
561434a6 181 const DNSName& tsigkeyname, const DNSName& tsigalgorithm,
95302209
AT
182 const string& tsigsecret)
183{
4a1ab5ed
AT
184 ComboAddress local;
185 local.sin4.sin_family = 0;
186 return this->sendResolve(remote, local, domain, type, dnssecOK, tsigkeyname, tsigalgorithm, tsigsecret);
95302209
AT
187}
188
561434a6 189static int parseResult(MOADNSParser& mdp, const DNSName& origQname, uint16_t origQtype, uint16_t id, Resolver::res_t* result)
0c01dd7c
BH
190{
191 result->clear();
1813c5ff
KM
192
193 if(mdp.d_header.rcode)
ab4994df 194 return mdp.d_header.rcode;
1813c5ff 195
561434a6 196 if(origQname.countLabels()) { // not AXFR
ab4994df 197 if(mdp.d_header.id != id)
0c01dd7c 198 throw ResolverException("Remote nameserver replied with wrong id");
ab4994df
BH
199 if(mdp.d_header.qdcount != 1)
200 throw ResolverException("resolver: received answer with wrong number of questions ("+itoa(mdp.d_header.qdcount)+")");
561434a6
PD
201 if(mdp.d_qname != origQname)
202 throw ResolverException(string("resolver: received an answer to another question (")+mdp.d_qname.toString()+"!="+ origQname.toString()+".)");
12c86877 203 }
1813c5ff 204
914353ca 205 vector<DNSResourceRecord> ret;
0c01dd7c 206 DNSResourceRecord rr;
914353ca 207 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
f809c028 208 rr.qname = i->first.d_name;
0c01dd7c
BH
209 rr.qtype = i->first.d_type;
210 rr.ttl = i->first.d_ttl;
1813c5ff 211 rr.content = i->first.d_content->getZoneRepresentation(true);
0c01dd7c
BH
212 result->push_back(rr);
213 }
1813c5ff 214
0c01dd7c 215 return 0;
98e05fce 216}
12c86877 217
561434a6 218bool Resolver::tryGetSOASerial(DNSName *domain, uint32_t *theirSerial, uint32_t *theirInception, uint32_t *theirExpire, uint16_t* id)
98e05fce 219{
95302209
AT
220 struct pollfd *fds = new struct pollfd[locals.size()];
221 size_t i = 0, k;
0c01dd7c 222 int sock;
95302209
AT
223
224 for(std::map<string,int>::iterator iter=locals.begin(); iter != locals.end(); iter++, i++) {
225 fds[i].fd = iter->second;
226 fds[i].events = POLLIN;
227 }
228
229 if (poll(fds, i, 250) < 1) { // wait for 0.25s
7eb7ac3d
KM
230 delete [] fds;
231 return false;
95302209
AT
232 }
233
234 sock = -1;
235
236 // determine who
237 for(k=0;k<i;k++) {
238 if ((fds[k].revents & POLLIN) == POLLIN) {
239 sock = fds[k].fd;
240 break;
241 }
242 }
243
244 delete [] fds;
7eb7ac3d 245
95302209 246 if (sock < 0) return false; // false alarm
7eb7ac3d 247
3696224d
BH
248 int err;
249 ComboAddress fromaddr;
250 socklen_t addrlen=fromaddr.getSocklen();
0c01dd7c
BH
251 char buf[3000];
252 err = recvfrom(sock, buf, sizeof(buf), 0,(struct sockaddr*)(&fromaddr), &addrlen);
3696224d
BH
253 if(err < 0) {
254 if(errno == EAGAIN)
255 return false;
95302209 256
3696224d
BH
257 throw ResolverException("recvfrom error waiting for answer: "+stringerror());
258 }
95302209 259
27c0050c 260 MOADNSParser mdp(false, (char*)buf, err);
3696224d 261 *id=mdp.d_header.id;
561434a6 262 *domain = mdp.d_qname;
3696224d
BH
263
264 if(mdp.d_answers.empty())
561434a6 265 throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' produced no results (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
3696224d 266
48afcf83 267 if(mdp.d_qtype != QType::SOA)
561434a6 268 throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' returned wrong record type");
12c86877 269
48afcf83
BH
270 *theirInception = *theirExpire = 0;
271 bool gotSOA=false;
ef7cd021 272 for(const MOADNSParser::answers_t::value_type& drc : mdp.d_answers) {
48afcf83 273 if(drc.first.d_type == QType::SOA) {
ba3c54cb
RG
274 shared_ptr<SOARecordContent> src=getRR<SOARecordContent>(drc.first);
275 if (src) {
276 *theirSerial=src->d_st.serial;
277 gotSOA = true;
278 }
48afcf83
BH
279 }
280 if(drc.first.d_type == QType::RRSIG) {
ba3c54cb
RG
281 shared_ptr<RRSIGRecordContent> rrc=getRR<RRSIGRecordContent>(drc.first);
282 if(rrc && rrc->d_type == QType::SOA) {
232f0877
CH
283 *theirInception= std::max(*theirInception, rrc->d_siginception);
284 *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
965f9774 285 }
48afcf83
BH
286 }
287 }
288 if(!gotSOA)
561434a6 289 throw ResolverException("Query to '" + fromaddr.toString() + "' for SOA of '" + domain->toString() + "' did not return a SOA");
3696224d
BH
290 return true;
291}
d3491d5a 292
561434a6 293int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res, const ComboAddress &local)
3696224d 294{
98e05fce 295 try {
0c01dd7c 296 ComboAddress to(ipport, 53);
a370ef31 297
95302209
AT
298 int id = sendResolve(to, local, domain, type);
299 int sock;
300
301 // choose socket based on local
302 if (local.sin4.sin_family == 0) {
7eb7ac3d
KM
303 // up to us.
304 sock = to.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
95302209 305 } else {
7eb7ac3d
KM
306 std::string lstr = local.toString();
307 std::map<std::string, int>::iterator lptr;
308 // see if there is a local
95302209 309
7eb7ac3d
KM
310 if ((lptr = locals.find(lstr)) != locals.end()) sock = lptr->second;
311 else throw ResolverException("sendResolve did not create socket for " + lstr);
95302209
AT
312 }
313
7108e055 314 int err=waitForData(sock, 0, 3000000);
0c01dd7c
BH
315
316 if(!err) {
317 throw ResolverException("Timeout waiting for answer");
318 }
319 if(err < 0)
320 throw ResolverException("Error waiting for answer: "+stringerror());
321
322 ComboAddress from;
323 socklen_t addrlen = sizeof(from);
324 char buffer[3000];
325 int len;
326
327 if((len=recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*)(&from), &addrlen)) < 0)
328 throw ResolverException("recvfrom error waiting for answer: "+stringerror());
329
27c0050c 330 MOADNSParser mdp(false, buffer, len);
ab4994df 331 return parseResult(mdp, domain, type, id, res);
98e05fce
BH
332 }
333 catch(ResolverException &re) {
a370ef31 334 throw ResolverException(re.reason+" from "+ipport);
98e05fce 335 }
0c01dd7c 336 return -1;
98e05fce 337}
12c86877 338
561434a6 339int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res) {
4a1ab5ed
AT
340 ComboAddress local;
341 local.sin4.sin_family = 0;
342 return resolve(ipport, domain, type, res, local);
95302209 343}
12c86877 344
561434a6 345void Resolver::getSoaSerial(const string &ipport, const DNSName &domain, uint32_t *serial)
0c01dd7c
BH
346{
347 vector<DNSResourceRecord> res;
561434a6 348 int ret = resolve(ipport, domain, QType::SOA, &res);
3696224d 349
0c01dd7c 350 if(ret || res.empty())
561434a6 351 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced no answers");
12c86877 352
0c01dd7c 353 if(res[0].qtype.getCode() != QType::SOA)
561434a6 354 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced a "+res[0].qtype.getName()+" record");
0c01dd7c
BH
355
356 vector<string>parts;
357 stringtok(parts, res[0].content);
358 if(parts.size()<3)
561434a6 359 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable response");
95dd3b90
RG
360
361 try {
362 *serial=pdns_stou(parts[2]);
363 }
364 catch(const std::out_of_range& oor) {
365 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable serial");
366 }
12c86877
BH
367}
368
fc396d56 369AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
98c9ec39 370 const DNSName& domain,
371 const TSIGTriplet& tt,
db8f9152
RG
372 const ComboAddress* laddr,
373 size_t maxReceivedBytes)
60a1c204 374 : d_tsigVerifier(tt, remote, d_trc), d_receivedBytes(0), d_maxReceivedBytes(maxReceivedBytes)
12c86877 375{
0c01dd7c 376 ComboAddress local;
fc396d56 377 if (laddr != NULL) {
4a1ab5ed 378 local = (ComboAddress) (*laddr);
fc396d56 379 } else {
4a1ab5ed
AT
380 if(remote.sin4.sin_family == AF_INET)
381 local=ComboAddress(::arg()["query-local-address"]);
382 else if(!::arg()["query-local-address6"].empty())
383 local=ComboAddress(::arg()["query-local-address6"]);
384 else
385 local=ComboAddress("::");
fc396d56 386 }
3ba05fa7
BH
387 d_sock = -1;
388 try {
389 d_sock = makeQuerySocket(local, false); // make a TCP socket
b841314c
RG
390 if (d_sock < 0)
391 throw ResolverException("Error creating socket for AXFR request to "+d_remote.toStringWithPort());
3ba05fa7
BH
392 d_buf = shared_array<char>(new char[65536]);
393 d_remote = remote; // mostly for error reporting
394 this->connect();
395 d_soacount = 0;
396
397 vector<uint8_t> packet;
398 DNSPacketWriter pw(packet, domain, QType::AXFR);
399 pw.getHeader()->id = dns_random(0xffff);
400
98c9ec39 401 if(!tt.name.empty()) {
402 if (tt.algo == DNSName("hmac-md5"))
403 d_trc.d_algoName = tt.algo + DNSName("sig-alg.reg.int");
a56bc64d 404 else
98c9ec39 405 d_trc.d_algoName = tt.algo;
3ba05fa7
BH
406 d_trc.d_time = time(0);
407 d_trc.d_fudge = 300;
408 d_trc.d_origID=ntohs(pw.getHeader()->id);
409 d_trc.d_eRcode=0;
ea3816cf 410 addTSIG(pw, d_trc, tt.name, tt.secret, "", false);
3ba05fa7
BH
411 }
412
413 uint16_t replen=htons(packet.size());
414 Utility::iovec iov[2];
72a93ecc 415 iov[0].iov_base=reinterpret_cast<char*>(&replen);
3ba05fa7 416 iov[0].iov_len=2;
72a93ecc 417 iov[1].iov_base=packet.data();
3ba05fa7
BH
418 iov[1].iov_len=packet.size();
419
5b6d751e
BH
420 int ret=Utility::writev(d_sock, iov, 2);
421 if(ret < 0)
3ba05fa7 422 throw ResolverException("Error sending question to "+d_remote.toStringWithPort()+": "+stringerror());
5b6d751e
BH
423 if(ret != (int)(2+packet.size())) {
424 throw ResolverException("Partial write on AXFR request to "+d_remote.toStringWithPort());
425 }
3ba05fa7
BH
426
427 int res = waitForData(d_sock, 10, 0);
0c01dd7c 428
3ba05fa7
BH
429 if(!res)
430 throw ResolverException("Timeout waiting for answer from "+d_remote.toStringWithPort()+" during AXFR");
431 if(res<0)
432 throw ResolverException("Error waiting for answer from "+d_remote.toStringWithPort()+": "+stringerror());
433 }
434 catch(...) {
435 if(d_sock >= 0)
436 close(d_sock);
b841314c 437 d_sock = -1;
3ba05fa7 438 throw;
29b92d6f 439 }
12c86877
BH
440}
441
2577467d
BH
442AXFRRetriever::~AXFRRetriever()
443{
444 close(d_sock);
445}
12c86877 446
54d84273
PD
447
448
5aa12996 449int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records) // Implementation is making sure RFC2845 4.4 is followed.
12c86877 450{
0c01dd7c
BH
451 if(d_soacount > 1)
452 return false;
236e0c78 453
12c86877
BH
454 // d_sock is connected and is about to spit out a packet
455 int len=getLength();
456 if(len<0)
25b1d5d7 457 throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
db8f9152
RG
458
459 if (d_maxReceivedBytes > 0 && (d_maxReceivedBytes - d_receivedBytes) < (size_t) len)
460 throw ResolverException("Reached the maximum number of received bytes during AXFR");
461
462 timeoutReadn(len);
463
464 d_receivedBytes += (uint16_t) len;
465
27c0050c 466 MOADNSParser mdp(false, d_buf.get(), len);
236e0c78 467
5aa12996 468 int err;
469 if(!records)
470 err=parseResult(mdp, DNSName(), 0, 0, &res);
471 else {
472 records->clear();
473 for(const auto& r: mdp.d_answers)
474 records->push_back(r.first);
475 err = mdp.d_header.rcode;
476 }
477
236e0c78 478 if(err)
bf491f9b 479 throw ResolverException("AXFR chunk error: " + RCode::to_s(err));
236e0c78 480
ef7cd021 481 for(const MOADNSParser::answers_t::value_type& answer : mdp.d_answers)
236e0c78
PD
482 if (answer.first.d_type == QType::SOA)
483 d_soacount++;
484
60a1c204
RG
485 try {
486 d_tsigVerifier.check(std::string(d_buf.get(), len), mdp);
54d84273 487 }
60a1c204
RG
488 catch(const std::runtime_error& re) {
489 throw ResolverException(re.what());
490 }
491
0c01dd7c
BH
492 return true;
493}
12c86877 494
0c01dd7c
BH
495void AXFRRetriever::timeoutReadn(uint16_t bytes)
496{
497 time_t start=time(0);
498 int n=0;
499 int numread;
500 while(n<bytes) {
016a0abb
PD
501 int res=waitForData(d_sock, 10-(time(0)-start));
502 if(res<0)
0c01dd7c 503 throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
016a0abb
PD
504 if(!res)
505 throw ResolverException("Timeout while reading data from remote nameserver over TCP");
0c01dd7c
BH
506
507 numread=recv(d_sock, d_buf.get()+n, bytes-n, 0);
508 if(numread<0)
509 throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
510 if(numread==0)
511 throw ResolverException("Remote nameserver closed TCP connection");
512 n+=numread;
513 }
12c86877
BH
514}
515
0c01dd7c 516void AXFRRetriever::connect()
12c86877 517{
3897b9e1 518 setNonBlocking( d_sock );
0c01dd7c
BH
519
520 int err;
521
522 if((err=::connect(d_sock,(struct sockaddr*)&d_remote, d_remote.getSocklen()))<0 && errno!=EINPROGRESS) {
a7b68ae7
RG
523 try {
524 closesocket(d_sock);
525 }
526 catch(const PDNSException& e) {
527 d_sock=-1;
528 throw ResolverException("Error closing AXFR socket after connect() failed: "+e.reason);
529 }
530
0c01dd7c 531 throw ResolverException("connect: "+stringerror());
88c1bc50 532 }
0c01dd7c
BH
533
534 if(!err)
535 goto done;
536
537 err=waitForRWData(d_sock, false, 10, 0); // wait for writeability
538
539 if(!err) {
a7b68ae7
RG
540 try {
541 closesocket(d_sock); // timeout
542 }
543 catch(const PDNSException& e) {
544 d_sock=-1;
545 throw ResolverException("Error closing AXFR socket after timeout: "+e.reason);
546 }
547
0c01dd7c
BH
548 d_sock=-1;
549 errno=ETIMEDOUT;
550
551 throw ResolverException("Timeout connecting to server");
88c1bc50 552 }
0c01dd7c
BH
553 else if(err < 0) {
554 throw ResolverException("Error connecting: "+string(strerror(err)));
849fde0b 555 }
0c01dd7c
BH
556 else {
557 Utility::socklen_t len=sizeof(err);
558 if(getsockopt(d_sock, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
559 throw ResolverException("Error connecting: "+stringerror()); // Solaris
560
561 if(err)
562 throw ResolverException("Error connecting: "+string(strerror(err)));
8b3cfcd3 563 }
0c01dd7c
BH
564
565 done:
3897b9e1 566 setBlocking( d_sock );
0c01dd7c 567 // d_sock now connected
12c86877
BH
568}
569
0c01dd7c 570int AXFRRetriever::getLength()
98e05fce 571{
0c01dd7c
BH
572 timeoutReadn(2);
573 return (unsigned char)d_buf[0]*256+(unsigned char)d_buf[1];
12c86877
BH
574}
575