]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/resolver.cc
Merge pull request #1109 from mind04/not-referenced
[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*/
379ab445 22#include "packetcache.hh"
731f58b8 23#include "utility.hh"
12c86877
BH
24#include "resolver.hh"
25#include <pthread.h>
26#include <semaphore.h>
27#include <iostream>
28#include <errno.h>
29#include "misc.hh"
30#include <algorithm>
31#include <sstream>
3696224d 32#include "dnsrecords.hh"
12c86877
BH
33#include <cstring>
34#include <string>
35#include <vector>
b8e0f341 36#include <boost/algorithm/string.hpp>
12c86877
BH
37#include "dns.hh"
38#include "qtype.hh"
39#include "tcpreceiver.hh"
5c409fa2 40#include "pdnsexception.hh"
12c86877
BH
41#include "statbag.hh"
42#include "arguments.hh"
7597b3cf 43#include "base64.hh"
88c1bc50
BH
44#include "dnswriter.hh"
45#include "dnsparser.hh"
46#include <boost/shared_ptr.hpp>
48afcf83 47#include <boost/foreach.hpp>
afbc704a 48#include "dns_random.hh"
88c1bc50 49
eb4e3090 50#include "namespaces.hh"
12c86877 51
0c01dd7c 52int makeQuerySocket(const ComboAddress& local, bool udpOrTCP)
12c86877 53{
0c01dd7c 54 ComboAddress ourLocal(local);
12c86877 55
0c01dd7c 56 int sock=socket(ourLocal.sin4.sin_family, udpOrTCP ? SOCK_DGRAM : SOCK_STREAM, 0);
42c235e5 57 Utility::setCloseOnExec(sock);
5e2be4cf
BH
58 if(sock < 0) {
59 unixDie("Creating local resolver socket for "+ourLocal.toString() + ((local.sin4.sin_family == AF_INET6) ? ", does your OS miss IPv6?" : ""));
60 }
0c01dd7c 61
eabdf7e0
PD
62 if(udpOrTCP) {
63 // udp, try hard to bind an unpredictable port
0c01dd7c
BH
64 int tries=10;
65 while(--tries) {
66 ourLocal.sin4.sin_port = htons(10000+(dns_random(10000)));
67
68 if (::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) >= 0)
69 break;
70 }
eabdf7e0
PD
71 // cerr<<"bound udp port "<<ourLocal.sin4.sin_port<<", "<<tries<<" tries left"<<endl;
72
0c01dd7c
BH
73 if(!tries) {
74 Utility::closesocket(sock);
3f81d239 75 throw PDNSException("Resolver binding to local UDP socket on "+ourLocal.toString()+": "+stringerror());
0c01dd7c 76 }
12c86877 77 }
0c01dd7c 78 else {
eabdf7e0
PD
79 // tcp, let the kernel figure out the port
80 // cerr<<"letting kernel pick TCP port"<<endl;
0c01dd7c
BH
81 ourLocal.sin4.sin_port = 0;
82 if(::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) < 0)
3f81d239 83 throw PDNSException("Resolver binding to local TCP socket on "+ourLocal.toString()+": "+stringerror());
eab7dbda 84 }
0c01dd7c 85 return sock;
12c86877
BH
86}
87
88Resolver::Resolver()
0c01dd7c 89try
12c86877 90{
0c01dd7c
BH
91 d_sock4 = d_sock6 = 0;
92 d_sock4 = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true);
0a2915e2 93 if(!::arg()["query-local-address6"].empty())
0c01dd7c
BH
94 d_sock6 = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true);
95 else
96 d_sock6 = -1;
12c86877 97}
0c01dd7c
BH
98catch(...) {
99 if(d_sock4>=0)
100 close(d_sock4);
101 throw;
12c86877
BH
102}
103
0c01dd7c 104Resolver::~Resolver()
12c86877 105{
0c01dd7c
BH
106 if(d_sock4>=0)
107 Utility::closesocket(d_sock4);
108 if(d_sock6>=0)
109 Utility::closesocket(d_sock6);
12c86877
BH
110}
111
7597b3cf
BH
112uint16_t Resolver::sendResolve(const ComboAddress& remote, const char *domain, int type, bool dnssecOK,
113 const string& tsigkeyname, const string& tsigalgorithm,
114 const string& tsigsecret)
12c86877 115{
f0136bd5 116 uint16_t randomid;
88c1bc50
BH
117 vector<uint8_t> packet;
118 DNSPacketWriter pw(packet, domain, type);
f0136bd5 119 pw.getHeader()->id = randomid = dns_random(0xffff);
7597b3cf 120
48afcf83
BH
121 if(dnssecOK) {
122 pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
123 pw.commit();
124 }
7597b3cf
BH
125
126 if(!tsigkeyname.empty()) {
842c8dd2 127 // cerr<<"Adding TSIG to notification, key name: '"<<tsigkeyname<<"', algo: '"<<tsigalgorithm<<"', secret: "<<Base64Encode(tsigsecret)<<endl;
7597b3cf 128 TSIGRecordContent trc;
785594c9 129 if (tsigalgorithm == "hmac-md5")
9f782f99 130 trc.d_algoName = tsigalgorithm + ".sig-alg.reg.int.";
a56bc64d
AT
131 else
132 trc.d_algoName = tsigalgorithm;
7597b3cf
BH
133 trc.d_time = time(0);
134 trc.d_fudge = 300;
f0136bd5 135 trc.d_origID=ntohs(randomid);
7597b3cf
BH
136 trc.d_eRcode=0;
137 addTSIG(pw, &trc, tsigkeyname, tsigsecret, "", false);
138 }
0c01dd7c
BH
139
140 int sock = remote.sin4.sin_family == AF_INET ? d_sock4 : d_sock6;
141
142 if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
143 throw ResolverException("Unable to ask query of "+remote.toStringWithPort()+": "+stringerror());
144 }
f0136bd5 145 return randomid;
0c01dd7c 146}
48afcf83 147
ab4994df 148static int parseResult(MOADNSParser& mdp, const std::string& origQname, uint16_t origQtype, uint16_t id, Resolver::res_t* result)
0c01dd7c
BH
149{
150 result->clear();
0c01dd7c 151
ab4994df
BH
152 if(mdp.d_header.rcode)
153 return mdp.d_header.rcode;
0c01dd7c
BH
154
155 if(!origQname.empty()) { // not AXFR
ab4994df 156 if(mdp.d_header.id != id)
0c01dd7c 157 throw ResolverException("Remote nameserver replied with wrong id");
ab4994df
BH
158 if(mdp.d_header.qdcount != 1)
159 throw ResolverException("resolver: received answer with wrong number of questions ("+itoa(mdp.d_header.qdcount)+")");
160 if(mdp.d_qname != origQname+".")
161 throw ResolverException(string("resolver: received an answer to another question (")+mdp.d_qname+"!="+ origQname+".)");
12c86877 162 }
0c01dd7c 163
914353ca 164 vector<DNSResourceRecord> ret;
0c01dd7c 165 DNSResourceRecord rr;
914353ca 166 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
0c01dd7c
BH
167 rr.qname = i->first.d_label;
168 if(!rr.qname.empty())
169 boost::erase_tail(rr.qname, 1); // strip .
170 rr.qtype = i->first.d_type;
171 rr.ttl = i->first.d_ttl;
172 rr.content = i->first.d_content->getZoneRepresentation();
173 rr.priority = 0;
914353ca 174
0c01dd7c
BH
175 uint16_t qtype=rr.qtype.getCode();
176
177 if(!rr.content.empty() && (qtype==QType::MX || qtype==QType::NS || qtype==QType::CNAME))
178 boost::erase_tail(rr.content, 1);
179
180 if(rr.qtype.getCode() == QType::MX) {
181 vector<string> parts;
182 stringtok(parts, rr.content);
183 rr.priority = atoi(parts[0].c_str());
184 if(parts.size() > 1)
185 rr.content=parts[1];
161a1d59
PD
186 else
187 rr.content=".";
0c01dd7c
BH
188 } else if(rr.qtype.getCode() == QType::SRV) {
189 rr.priority = atoi(rr.content.c_str());
190 vector<pair<string::size_type, string::size_type> > fields;
191 vstringtok(fields, rr.content, " ");
0ab3fdc6 192 if(fields.size()==4) {
232f0877
CH
193 if(fields[3].second - fields[3].first > 1) // strip dot, unless root
194 fields[3].second--;
0c01dd7c 195 rr.content=string(rr.content.c_str() + fields[1].first, fields[3].second - fields[1].first);
0ab3fdc6 196 }
0c01dd7c
BH
197 }
198 result->push_back(rr);
199 }
200
201 return 0;
98e05fce 202}
12c86877 203
48afcf83 204bool Resolver::tryGetSOASerial(string* domain, uint32_t *theirSerial, uint32_t *theirInception, uint32_t *theirExpire, uint16_t* id)
98e05fce 205{
0c01dd7c
BH
206 Utility::setNonBlocking( d_sock4 );
207 Utility::setNonBlocking( d_sock6 );
3696224d 208
0c01dd7c
BH
209 int sock;
210 if(!waitFor2Data(d_sock4, d_sock6, 0, 250000, &sock)) // lame function, I know..
3696224d
BH
211 return false;
212
213 int err;
214 ComboAddress fromaddr;
215 socklen_t addrlen=fromaddr.getSocklen();
0c01dd7c
BH
216 char buf[3000];
217 err = recvfrom(sock, buf, sizeof(buf), 0,(struct sockaddr*)(&fromaddr), &addrlen);
3696224d
BH
218 if(err < 0) {
219 if(errno == EAGAIN)
220 return false;
221
222 throw ResolverException("recvfrom error waiting for answer: "+stringerror());
223 }
224
0c01dd7c 225 MOADNSParser mdp((char*)buf, err);
3696224d
BH
226 *id=mdp.d_header.id;
227 *domain = stripDot(mdp.d_qname);
228
229 if(mdp.d_answers.empty())
67672ba6 230 throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + *domain + "' produced no results (error code: "+strrcode(mdp.d_header.rcode)+")");
3696224d 231
48afcf83 232 if(mdp.d_qtype != QType::SOA)
3ba05fa7 233 throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + *domain + "' returned wrong record type");
12c86877 234
48afcf83
BH
235 *theirInception = *theirExpire = 0;
236 bool gotSOA=false;
237 BOOST_FOREACH(const MOADNSParser::answers_t::value_type& drc, mdp.d_answers) {
238 if(drc.first.d_type == QType::SOA) {
239 shared_ptr<SOARecordContent> src=boost::dynamic_pointer_cast<SOARecordContent>(drc.first.d_content);
240 *theirSerial=src->d_st.serial;
241 gotSOA = true;
242 }
243 if(drc.first.d_type == QType::RRSIG) {
244 shared_ptr<RRSIGRecordContent> rrc=boost::dynamic_pointer_cast<RRSIGRecordContent>(drc.first.d_content);
965f9774 245 if(rrc->d_type == QType::SOA) {
232f0877
CH
246 *theirInception= std::max(*theirInception, rrc->d_siginception);
247 *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
965f9774 248 }
48afcf83
BH
249 }
250 }
251 if(!gotSOA)
252 throw ResolverException("Query to '" + fromaddr.toString() + "' for SOA of '" + *domain + "' did not return a SOA");
3696224d
BH
253 return true;
254}
d3491d5a 255
0c01dd7c 256int Resolver::resolve(const string &ipport, const char *domain, int type, Resolver::res_t* res)
3696224d 257{
98e05fce 258 try {
0c01dd7c 259 ComboAddress to(ipport, 53);
a370ef31 260
0c01dd7c
BH
261 int id = sendResolve(to, domain, type);
262 int sock = to.sin4.sin_family == AF_INET ? d_sock4 : d_sock6;
7108e055 263 int err=waitForData(sock, 0, 3000000);
0c01dd7c
BH
264
265 if(!err) {
266 throw ResolverException("Timeout waiting for answer");
267 }
268 if(err < 0)
269 throw ResolverException("Error waiting for answer: "+stringerror());
270
271 ComboAddress from;
272 socklen_t addrlen = sizeof(from);
273 char buffer[3000];
274 int len;
275
276 if((len=recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*)(&from), &addrlen)) < 0)
277 throw ResolverException("recvfrom error waiting for answer: "+stringerror());
278
ab4994df
BH
279 MOADNSParser mdp(buffer, len);
280 return parseResult(mdp, domain, type, id, res);
98e05fce
BH
281 }
282 catch(ResolverException &re) {
a370ef31 283 throw ResolverException(re.reason+" from "+ipport);
98e05fce 284 }
0c01dd7c 285 return -1;
98e05fce 286}
12c86877 287
12c86877 288
12c86877 289
0c01dd7c
BH
290void Resolver::getSoaSerial(const string &ipport, const string &domain, uint32_t *serial)
291{
292 vector<DNSResourceRecord> res;
293 int ret = resolve(ipport, domain.c_str(), QType::SOA, &res);
3696224d 294
0c01dd7c
BH
295 if(ret || res.empty())
296 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain + "' produced no answers");
12c86877 297
0c01dd7c
BH
298 if(res[0].qtype.getCode() != QType::SOA)
299 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain + "' produced a "+res[0].qtype.getName()+" record");
300
301 vector<string>parts;
302 stringtok(parts, res[0].content);
303 if(parts.size()<3)
304 throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain + "' produced an unparseable response");
3696224d 305
0c01dd7c 306 *serial=(uint32_t)atol(parts[2].c_str());
12c86877
BH
307}
308
fc396d56 309AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
232f0877
CH
310 const string& domain,
311 const string& tsigkeyname,
312 const string& tsigalgorithm,
313 const string& tsigsecret,
314 const ComboAddress* laddr)
e9bc79c6 315: d_tsigkeyname(tsigkeyname), d_tsigsecret(tsigsecret), d_tsigPos(0), d_nonSignedMessages(0)
12c86877 316{
0c01dd7c 317 ComboAddress local;
fc396d56 318 if (laddr != NULL) {
232f0877 319 local = (ComboAddress) (*laddr);
fc396d56 320 } else {
232f0877
CH
321 if(remote.sin4.sin_family == AF_INET)
322 local=ComboAddress(::arg()["query-local-address"]);
323 else if(!::arg()["query-local-address6"].empty())
324 local=ComboAddress(::arg()["query-local-address6"]);
325 else
326 local=ComboAddress("::");
fc396d56 327 }
3ba05fa7
BH
328 d_sock = -1;
329 try {
330 d_sock = makeQuerySocket(local, false); // make a TCP socket
331 d_buf = shared_array<char>(new char[65536]);
332 d_remote = remote; // mostly for error reporting
333 this->connect();
334 d_soacount = 0;
335
336 vector<uint8_t> packet;
337 DNSPacketWriter pw(packet, domain, QType::AXFR);
338 pw.getHeader()->id = dns_random(0xffff);
339
340 if(!tsigkeyname.empty()) {
a56bc64d
AT
341 if (tsigalgorithm == "hmac-md5")
342 d_trc.d_algoName = tsigalgorithm + ".sig-alg.reg.int.";
343 else
344 d_trc.d_algoName = tsigalgorithm;
3ba05fa7
BH
345 d_trc.d_time = time(0);
346 d_trc.d_fudge = 300;
347 d_trc.d_origID=ntohs(pw.getHeader()->id);
348 d_trc.d_eRcode=0;
349 addTSIG(pw, &d_trc, tsigkeyname, tsigsecret, "", false);
350 }
351
352 uint16_t replen=htons(packet.size());
353 Utility::iovec iov[2];
354 iov[0].iov_base=(char*)&replen;
355 iov[0].iov_len=2;
356 iov[1].iov_base=(char*)&packet[0];
357 iov[1].iov_len=packet.size();
358
5b6d751e
BH
359 int ret=Utility::writev(d_sock, iov, 2);
360 if(ret < 0)
3ba05fa7 361 throw ResolverException("Error sending question to "+d_remote.toStringWithPort()+": "+stringerror());
5b6d751e
BH
362 if(ret != (int)(2+packet.size())) {
363 throw ResolverException("Partial write on AXFR request to "+d_remote.toStringWithPort());
364 }
3ba05fa7
BH
365
366 int res = waitForData(d_sock, 10, 0);
0c01dd7c 367
3ba05fa7
BH
368 if(!res)
369 throw ResolverException("Timeout waiting for answer from "+d_remote.toStringWithPort()+" during AXFR");
370 if(res<0)
371 throw ResolverException("Error waiting for answer from "+d_remote.toStringWithPort()+": "+stringerror());
372 }
373 catch(...) {
374 if(d_sock >= 0)
375 close(d_sock);
376 throw;
29b92d6f 377 }
12c86877
BH
378}
379
2577467d
BH
380AXFRRetriever::~AXFRRetriever()
381{
382 close(d_sock);
383}
12c86877 384
54d84273
PD
385
386
387int AXFRRetriever::getChunk(Resolver::res_t &res) // Implementation is making sure RFC2845 4.4 is followed.
12c86877 388{
0c01dd7c
BH
389 if(d_soacount > 1)
390 return false;
236e0c78 391
12c86877
BH
392 // d_sock is connected and is about to spit out a packet
393 int len=getLength();
394 if(len<0)
25b1d5d7 395 throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
12c86877 396
0c01dd7c 397 timeoutReadn(len);
ab4994df 398 MOADNSParser mdp(d_buf.get(), len);
236e0c78
PD
399
400 int err = parseResult(mdp, "", 0, 0, &res);
401 if(err)
402 throw ResolverException("AXFR chunk with a non-zero rcode "+lexical_cast<string>(err));
403
404 BOOST_FOREACH(const MOADNSParser::answers_t::value_type& answer, mdp.d_answers)
405 if (answer.first.d_type == QType::SOA)
406 d_soacount++;
407
54d84273 408 if(!d_tsigkeyname.empty()) { // TSIG verify message
236e0c78
PD
409 // If we have multiple messages, we need to concatenate them together. We also need to make sure we know the location of
410 // the TSIG record so we can remove it in makeTSIGMessageFromTSIGPacket
411 d_signData.append(d_buf.get(), len);
412 if (mdp.getTSIGPos() == 0)
413 d_tsigPos += len;
414 else
415 d_tsigPos += mdp.getTSIGPos();
416
ab4994df 417 string theirMac;
54d84273 418 bool checkTSIG = false;
236e0c78 419
ab4994df 420 BOOST_FOREACH(const MOADNSParser::answers_t::value_type& answer, mdp.d_answers) {
236e0c78 421 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 422 checkTSIG = true;
236e0c78 423
5b6d751e
BH
424 if(answer.first.d_type == QType::TSIG) {
425 shared_ptr<TSIGRecordContent> trc = boost::dynamic_pointer_cast<TSIGRecordContent>(answer.first.d_content);
426 theirMac = trc->d_mac;
427 d_trc.d_time = trc->d_time;
54d84273 428 checkTSIG = true;
5b6d751e 429 }
ab4994df 430 }
54d84273 431
236e0c78
PD
432 if( ! checkTSIG && d_nonSignedMessages > 99) { // We're allowed to get 100 digest without a TSIG.
433 throw ResolverException("No TSIG message received in last 100 messages of AXFR transfer.");
54d84273 434 }
54d84273 435
54d84273 436 if (checkTSIG) {
236e0c78
PD
437 if (theirMac.empty())
438 throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tsigkeyname+"'");
439
54d84273
PD
440 string message;
441 if (!d_prevMac.empty()) {
236e0c78 442 message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_prevMac, true, d_signData.size()-len);
54d84273 443 } else {
236e0c78 444 message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_trc.d_mac, false);
54d84273 445 }
e820c305 446
785594c9
KM
447 TSIGHashEnum algo;
448 if (!getTSIGHashEnum(d_trc.d_algoName, algo)) {
e820c305
AT
449 throw ResolverException("Unsupported TSIG HMAC algorithm " + d_trc.d_algoName);
450 }
451
452 string ourMac=calculateHMAC(d_tsigsecret, message, algo);
236e0c78 453
54d84273
PD
454 // ourMac[0]++; // sabotage == for testing :-)
455 if(ourMac != theirMac) {
456 throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname+"'");
457 }
a426be78 458
236e0c78
PD
459 // Reset and store some values for the next chunks.
460 d_prevMac = theirMac;
461 d_nonSignedMessages = 0;
462 d_signData.clear();
463 d_tsigPos = 0;
54d84273 464 }
236e0c78
PD
465 else
466 d_nonSignedMessages++;
54d84273 467 }
236e0c78 468
0c01dd7c
BH
469 return true;
470}
12c86877 471
0c01dd7c
BH
472void AXFRRetriever::timeoutReadn(uint16_t bytes)
473{
474 time_t start=time(0);
475 int n=0;
476 int numread;
477 while(n<bytes) {
016a0abb
PD
478 int res=waitForData(d_sock, 10-(time(0)-start));
479 if(res<0)
0c01dd7c 480 throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
016a0abb
PD
481 if(!res)
482 throw ResolverException("Timeout while reading data from remote nameserver over TCP");
0c01dd7c
BH
483
484 numread=recv(d_sock, d_buf.get()+n, bytes-n, 0);
485 if(numread<0)
486 throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
487 if(numread==0)
488 throw ResolverException("Remote nameserver closed TCP connection");
489 n+=numread;
490 }
12c86877
BH
491}
492
0c01dd7c 493void AXFRRetriever::connect()
12c86877 494{
0c01dd7c
BH
495 Utility::setNonBlocking( d_sock );
496
497 int err;
498
499 if((err=::connect(d_sock,(struct sockaddr*)&d_remote, d_remote.getSocklen()))<0 && errno!=EINPROGRESS) {
500 Utility::closesocket(d_sock);
501 d_sock=-1;
502 throw ResolverException("connect: "+stringerror());
88c1bc50 503 }
0c01dd7c
BH
504
505 if(!err)
506 goto done;
507
508 err=waitForRWData(d_sock, false, 10, 0); // wait for writeability
509
510 if(!err) {
511 Utility::closesocket(d_sock); // timeout
512 d_sock=-1;
513 errno=ETIMEDOUT;
514
515 throw ResolverException("Timeout connecting to server");
88c1bc50 516 }
0c01dd7c
BH
517 else if(err < 0) {
518 throw ResolverException("Error connecting: "+string(strerror(err)));
849fde0b 519 }
0c01dd7c
BH
520 else {
521 Utility::socklen_t len=sizeof(err);
522 if(getsockopt(d_sock, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
523 throw ResolverException("Error connecting: "+stringerror()); // Solaris
524
525 if(err)
526 throw ResolverException("Error connecting: "+string(strerror(err)));
8b3cfcd3 527 }
0c01dd7c
BH
528
529 done:
530 Utility::setBlocking( d_sock );
531 // d_sock now connected
12c86877
BH
532}
533
0c01dd7c 534int AXFRRetriever::getLength()
98e05fce 535{
0c01dd7c
BH
536 timeoutReadn(2);
537 return (unsigned char)d_buf[0]*256+(unsigned char)d_buf[1];
12c86877
BH
538}
539