]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
It compiles
[thirdparty/pdns.git] / pdns / lwres.cc
CommitLineData
e14f094b
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
e125fc69 3 Copyright (C) 2002 - 2014 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 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
e14f094b
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
e14f094b 21*/
705f31ae
BH
22
23
870a0fe4
AT
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
36c5ee42 27#include "utility.hh"
e14f094b 28#include "lwres.hh"
e14f094b 29#include <iostream>
81883dcc 30#include "dnsrecords.hh"
e14f094b
BH
31#include <errno.h>
32#include "misc.hh"
33#include <algorithm>
34#include <sstream>
35#include <cstring>
36#include <string>
37#include <vector>
e14f094b
BH
38#include "dns.hh"
39#include "qtype.hh"
5c409fa2 40#include "pdnsexception.hh"
e14f094b 41#include "arguments.hh"
5c633640
BH
42#include "sstuff.hh"
43#include "syncres.hh"
ea634573
BH
44#include "dnswriter.hh"
45#include "dnsparser.hh"
aab4adb0 46#include "logger.hh"
51e2144e 47#include "dns_random.hh"
263f6a5a 48#include <boost/scoped_array.hpp>
51e2144e
BH
49#include <boost/algorithm/string.hpp>
50
81883dcc
BH
51//! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success
52/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
53 Never throws!
54 */
6893459d 55int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, LWResult *lwr)
e14f094b 56{
263f6a5a
BH
57 int len;
58 int bufsize=1500;
59 scoped_array<unsigned char> buf(new unsigned char[bufsize]);
ea634573 60 vector<uint8_t> vpacket;
51e2144e 61 // string mapped0x20=dns0x20(domain);
ea634573
BH
62 DNSPacketWriter pw(vpacket, domain, type);
63
c1d73d94 64 pw.getHeader()->rd=sendRDQuery;
51e2144e 65 pw.getHeader()->id=dns_random(0xffff);
81883dcc
BH
66
67 string ping;
68
81883dcc
BH
69 if(EDNS0Level && !doTCP) {
70 DNSPacketWriter::optvect_t opts;
71 if(EDNS0Level > 1) {
93d4a890 72 uint32_t nonce=dns_random(0xffffffff);
73 ping.assign((char*) &nonce, 4);
74
81883dcc
BH
75 opts.push_back(make_pair(5, ping));
76 }
2188dcc3 77
81883dcc 78 pw.addOpt(1200, 0, 0, opts); // 1200 bytes answer size
2188dcc3
BH
79 pw.commit();
80 }
81883dcc
BH
81 lwr->d_rcode = 0;
82 lwr->d_pingCorrect = false;
83 lwr->d_haveEDNS = false;
eefd15f9
BH
84 int ret;
85
86 DTime dt;
4c4765c1 87 dt.set();
88 *now=dt.getTimeval();
263f6a5a 89 errno=0;
5c633640 90 if(!doTCP) {
4ef015cd 91 int queryfd;
996c89cc
BH
92 if(ip.sin4.sin_family==AF_INET6)
93 g_stats.ipv6queries++;
94
787e5eab 95 if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id,
232f0877 96 domain, type, &queryfd)) < 0) {
998a4334 97 return ret; // passes back the -2 EMFILE
5c633640
BH
98 }
99
100 // sleep until we see an answer to this, interface to mtasker
101
263f6a5a 102 ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id,
232f0877 103 domain, type, queryfd, now);
e14f094b 104 }
5c633640 105 else {
998a4334 106 try {
93f4e5ce 107 Socket s(ip.sin4.sin_family, SOCK_STREAM);
fdf05fd4 108
998a4334 109 s.setNonBlocking();
1652a63e 110 ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
3ac2a2ab 111
5a38281c 112 s.bind(local);
4957a608 113
fdf05fd4
BH
114 ComboAddress remote = ip;
115 remote.sin4.sin_port = htons(53);
116 s.connect(remote);
998a4334 117
263f6a5a
BH
118 uint16_t tlen=htons(vpacket.size());
119 char *lenP=(char*)&tlen;
998a4334
BH
120 const char *msgP=(const char*)&*vpacket.begin();
121 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
122
123 ret=asendtcp(packet, &s);
124 if(!(ret>0))
4957a608 125 return ret;
998a4334
BH
126
127 packet.clear();
825fa717 128 ret=arecvtcp(packet, 2, &s, false);
998a4334 129 if(!(ret > 0))
4957a608 130 return ret;
998a4334 131
263f6a5a
BH
132 memcpy(&tlen, packet.c_str(), 2);
133 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334 134
825fa717 135 ret=arecvtcp(packet, len, &s, false);
998a4334 136 if(!(ret > 0))
4957a608 137 return ret;
998a4334 138
263f6a5a 139 if(len > bufsize) {
4957a608
BH
140 bufsize=len;
141 scoped_array<unsigned char> narray(new unsigned char[bufsize]);
142 buf.swap(narray);
998a4334 143 }
263f6a5a
BH
144 memcpy(buf.get(), packet.c_str(), len);
145
998a4334
BH
146 ret=1;
147 }
148 catch(NetworkError& ne) {
149 ret = -2; // OS limits error
66ab6a63 150 }
5c633640 151 }
998a4334 152
81883dcc 153
26de3092
BH
154 lwr->d_usec=dt.udiff();
155 *now=dt.getTimeval();
156
263f6a5a
BH
157 if(ret <= 0) // includes 'timeout'
158 return ret;
e14f094b 159
263f6a5a 160 lwr->d_result.clear();
c836dc19 161 try {
f1f85f12 162 lwr->d_tcbit=0;
263f6a5a
BH
163 MOADNSParser mdp((const char*)buf.get(), len);
164 lwr->d_aabit=mdp.d_header.aa;
165 lwr->d_tcbit=mdp.d_header.tc;
166 lwr->d_rcode=mdp.d_header.rcode;
167
81883dcc
BH
168 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
169 return 1; // this is "success", the error is set in lwr->d_rcode
170 }
171
ec6480f3 172 if(!pdns_iequals(domain, mdp.d_qname)) {
673c5f31 173 if(!mdp.d_qname.empty() && domain.find((char)0) == string::npos) {// embedded nulls are too noisy, plus empty domains are too
4957a608 174 L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01608dca 175 }
284aa5c2 176 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
177 goto out;
178 }
51e2144e 179
ea634573 180 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
ea634573
BH
181 DNSResourceRecord rr;
182 rr.qtype=i->first.d_type;
183 rr.qname=i->first.d_label;
184 rr.ttl=i->first.d_ttl;
185 rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form
ea634573 186 rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
263f6a5a 187 lwr->d_result.push_back(rr);
ea634573 188 }
81883dcc
BH
189
190 EDNSOpts edo;
191 if(EDNS0Level > 1 && getEDNSOpts(mdp, &edo)) {
192 lwr->d_haveEDNS = true;
193 for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
4957a608
BH
194 iter != edo.d_options.end();
195 ++iter) {
196 if(iter->first == 5 || iter->first == 4) {// 'EDNS PING'
197 if(iter->second == ping) {
198 lwr->d_pingCorrect = true;
199 }
200 }
81883dcc
BH
201 }
202 }
203
263f6a5a 204 return 1;
c836dc19 205 }
fdbf35ac 206 catch(std::exception &mde) {
aab4adb0 207 if(::arg().mustDo("log-common-errors"))
263f6a5a 208 L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
81883dcc
BH
209 lwr->d_rcode = RCode::FormErr;
210 g_stats.serverParseError++;
211 return 1; // success - oddly enough
aab4adb0 212 }
c836dc19 213 catch(...) {
ad1bb608 214 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 215 }
263f6a5a 216
aab4adb0 217 g_stats.serverParseError++;
263f6a5a 218
2353fffa 219 out:
81883dcc
BH
220 if(!lwr->d_rcode)
221 lwr->d_rcode=RCode::ServFail;
263f6a5a
BH
222
223 return -1;
e14f094b
BH
224}
225
263f6a5a 226