]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
fix subtle bug with repeated timeouts on same fd
[thirdparty/pdns.git] / pdns / lwres.cc
CommitLineData
e14f094b
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
02ac88c8 3 Copyright (C) 2002 - 2006 PowerDNS.COM BV
e14f094b
BH
4
5 This program is free software; you can redistribute it and/or modify
d0166f4a
BH
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
e14f094b
BH
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
e14f094b 17*/
705f31ae
BH
18
19
36c5ee42 20#include "utility.hh"
e14f094b 21#include "lwres.hh"
e14f094b
BH
22#include <iostream>
23#include <errno.h>
24#include "misc.hh"
25#include <algorithm>
26#include <sstream>
27#include <cstring>
28#include <string>
29#include <vector>
e14f094b
BH
30#include "dns.hh"
31#include "qtype.hh"
e14f094b 32#include "ahuexception.hh"
e14f094b 33#include "arguments.hh"
5c633640
BH
34#include "sstuff.hh"
35#include "syncres.hh"
ea634573
BH
36#include "dnswriter.hh"
37#include "dnsparser.hh"
aab4adb0 38#include "logger.hh"
e14f094b
BH
39
40LWRes::LWRes()
41{
42 d_sock=-1;
43 d_timeout=500000;
b636533b 44 d_bufsize=1500;
d39704c0 45 d_buf = 0;
e14f094b
BH
46}
47
48LWRes::~LWRes()
49{
50 if(d_sock>=0)
51 Utility::closesocket(d_sock);
52 delete[] d_buf;
53}
54
998a4334 55//! returns -2 for OS limits error, -1 for permanent error that has to do with remote, 0 for timeout, 1 for success
e14f094b 56/** Never throws! */
996c89cc 57int LWRes::asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, struct timeval* now)
e14f094b 58{
d39704c0
BH
59 if(!d_buf)
60 d_buf=new unsigned char[d_bufsize];
61
2353fffa 62 d_ip=ip;
ea634573
BH
63 vector<uint8_t> vpacket;
64 DNSPacketWriter pw(vpacket, domain, type);
65
66 pw.getHeader()->rd=0;
f14ebffb 67 pw.getHeader()->id=Utility::random();
e14f094b
BH
68 d_domain=domain;
69 d_type=type;
70 d_inaxfr=false;
36f5e3db 71 d_rcode=0;
e14f094b 72
eefd15f9
BH
73 int ret;
74
75 DTime dt;
5e3da48d 76 dt.setTimeval(*now);
5c633640
BH
77
78 if(!doTCP) {
4ef015cd 79 int queryfd;
996c89cc
BH
80 if(ip.sin4.sin_family==AF_INET6)
81 g_stats.ipv6queries++;
82
787e5eab
BH
83 if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id,
84 domain, type, &queryfd)) < 0) {
998a4334 85 return ret; // passes back the -2 EMFILE
5c633640
BH
86 }
87
88 // sleep until we see an answer to this, interface to mtasker
89
787e5eab 90 ret=arecvfrom(reinterpret_cast<char *>(d_buf), d_bufsize-1,0, ip, &d_len, pw.getHeader()->id,
f6c254c1 91 domain, type, queryfd, now->tv_sec);
e14f094b 92 }
5c633640 93 else {
998a4334 94 try {
ccd3ed60 95 if(ip.sin4.sin_family != AF_INET) // sstuff isn't yet ready for IPv6
996c89cc 96 return -1;
998a4334 97 Socket s(InterNetwork, Stream);
ccd3ed60 98 IPEndpoint ie(U32ToIP(ntohl(ip.sin4.sin_addr.s_addr)), 53); // WRONG WRONG WRONG XXX FIXME
998a4334
BH
99 s.setNonBlocking();
100 s.connect(ie);
101
4ca15bca 102 uint16_t len=htons(vpacket.size());
998a4334
BH
103 char *lenP=(char*)&len;
104 const char *msgP=(const char*)&*vpacket.begin();
105 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
106
107 ret=asendtcp(packet, &s);
108 if(!(ret>0))
109 return ret;
110
111 packet.clear();
112 ret=arecvtcp(packet, 2, &s);
113 if(!(ret > 0))
114 return ret;
115
116 memcpy(&len, packet.c_str(), 2);
117 len=ntohs(len);
118
119 ret=arecvtcp(packet, len, &s);
120 if(!(ret > 0))
121 return ret;
122
02ac88c8
BH
123 if(len > d_bufsize) {
124 // cerr<<"Reallocating to "<<len<<" bytes ("<<packet.size()<<")\n";
998a4334
BH
125 d_bufsize=len;
126 delete[] d_buf;
127 d_buf = new unsigned char[d_bufsize];
128 }
129 memcpy(d_buf, packet.c_str(), len);
130 d_len=len;
131 ret=1;
132 }
133 catch(NetworkError& ne) {
134 ret = -2; // OS limits error
66ab6a63 135 }
5c633640 136 }
998a4334 137
5c633640 138 d_usec=dt.udiff();
5e3da48d 139 *now=dt.getTimeval();
eefd15f9 140 return ret;
e14f094b
BH
141}
142
143
eefd15f9 144LWRes::res_t LWRes::result()
e14f094b 145{
c836dc19 146 try {
ea634573
BH
147 MOADNSParser mdp((const char*)d_buf, d_len);
148 // if(p.parse((char *)d_buf, d_len)<0)
149 // throw LWResException("resolver: unable to parse packet of "+itoa(d_len)+" bytes");
150 d_aabit=mdp.d_header.aa;
151 d_tcbit=mdp.d_header.tc;
152 d_rcode=mdp.d_header.rcode;
153
705f31ae 154 if(Utility::strcasecmp(d_domain.c_str(), mdp.d_qname.c_str())) {
01608dca 155 if(d_domain.find((char)0)==string::npos) {// embedded nulls are too noisy
ad1bb608 156 L<<Logger::Notice<<"Packet purporting to come from remote server "<<d_ip.toString()<<" contained wrong answer: '" << d_domain << "' != '" << mdp.d_qname << "'" << endl;
01ed3112 157 g_stats.unexpectedCount++;
01608dca 158 }
2353fffa
BH
159 goto out;
160 }
161
ea634573
BH
162 LWRes::res_t ret;
163 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
164 // cout<<i->first.d_place<<"\t"<<i->first.d_label<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
165 // cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<endl;
166 DNSResourceRecord rr;
167 rr.qtype=i->first.d_type;
168 rr.qname=i->first.d_label;
169 rr.ttl=i->first.d_ttl;
170 rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form
ea634573
BH
171 rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
172 ret.push_back(rr);
173 }
174
175 return ret;
176 // return p.getAnswers();
c836dc19 177 }
aab4adb0
BH
178 catch(exception &mde) {
179 if(::arg().mustDo("log-common-errors"))
ad1bb608 180 L<<Logger::Notice<<"Unable to parse packet from remote server "<<d_ip.toString()<<": "<<mde.what()<<endl;
aab4adb0 181 }
c836dc19 182 catch(...) {
ad1bb608 183 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 184 }
2353fffa 185
aab4adb0 186 g_stats.serverParseError++;
2353fffa
BH
187
188 out:
aab4adb0
BH
189 d_rcode=RCode::ServFail;
190 LWRes::res_t empty;
191 return empty;
e14f094b
BH
192}
193