]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
dump recursor cache in sequential ordering, which allows us to debug our deletion...
[thirdparty/pdns.git] / pdns / lwres.cc
CommitLineData
e14f094b
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
a5c1b943 3 Copyright (C) 2002 - 2015 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 49#include <boost/algorithm/string.hpp>
12ce523e 50#include "validate-recursor.hh"
c4443ccb 51#include "ednssubnet.hh"
51e2144e 52
81883dcc
BH
53//! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success
54/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
55 Never throws!
56 */
376effcf 57int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult *lwr)
e14f094b 58{
263f6a5a 59 int len;
b33c2462 60 int bufsize=g_outgoingEDNSBufsize;
263f6a5a 61 scoped_array<unsigned char> buf(new unsigned char[bufsize]);
ea634573 62 vector<uint8_t> vpacket;
51e2144e 63 // string mapped0x20=dns0x20(domain);
ea634573
BH
64 DNSPacketWriter pw(vpacket, domain, type);
65
c1d73d94 66 pw.getHeader()->rd=sendRDQuery;
51e2144e 67 pw.getHeader()->id=dns_random(0xffff);
81883dcc
BH
68
69 string ping;
70
81883dcc
BH
71 if(EDNS0Level && !doTCP) {
72 DNSPacketWriter::optvect_t opts;
376effcf 73 if(srcmask) {
74 EDNSSubnetOpts eo;
75 eo.source = *srcmask;
bf4ab707 76 // cout<<"Adding request mask: "<<eo.source.toString()<<endl;
376effcf 77 opts.push_back(make_pair(8, makeEDNSSubnetOptsString(eo)));
78 srcmask=boost::optional<Netmask>(); // this is also our return value
79 }
93d4a890 80
12ce523e 81 pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
2188dcc3
BH
82 pw.commit();
83 }
81883dcc 84 lwr->d_rcode = 0;
81883dcc 85 lwr->d_haveEDNS = false;
eefd15f9
BH
86 int ret;
87
88 DTime dt;
4c4765c1 89 dt.set();
90 *now=dt.getTimeval();
263f6a5a 91 errno=0;
5c633640 92 if(!doTCP) {
4ef015cd 93 int queryfd;
996c89cc
BH
94 if(ip.sin4.sin_family==AF_INET6)
95 g_stats.ipv6queries++;
96
787e5eab 97 if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id,
232f0877 98 domain, type, &queryfd)) < 0) {
998a4334 99 return ret; // passes back the -2 EMFILE
5c633640
BH
100 }
101
102 // sleep until we see an answer to this, interface to mtasker
103
263f6a5a 104 ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id,
232f0877 105 domain, type, queryfd, now);
e14f094b 106 }
5c633640 107 else {
998a4334 108 try {
93f4e5ce 109 Socket s(ip.sin4.sin_family, SOCK_STREAM);
fdf05fd4 110
998a4334 111 s.setNonBlocking();
1652a63e 112 ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
3ac2a2ab 113
5a38281c 114 s.bind(local);
4957a608 115
fdf05fd4
BH
116 ComboAddress remote = ip;
117 remote.sin4.sin_port = htons(53);
118 s.connect(remote);
998a4334 119
263f6a5a
BH
120 uint16_t tlen=htons(vpacket.size());
121 char *lenP=(char*)&tlen;
998a4334
BH
122 const char *msgP=(const char*)&*vpacket.begin();
123 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
124
125 ret=asendtcp(packet, &s);
126 if(!(ret>0))
4957a608 127 return ret;
998a4334
BH
128
129 packet.clear();
825fa717 130 ret=arecvtcp(packet, 2, &s, false);
998a4334 131 if(!(ret > 0))
4957a608 132 return ret;
998a4334 133
263f6a5a
BH
134 memcpy(&tlen, packet.c_str(), 2);
135 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334 136
825fa717 137 ret=arecvtcp(packet, len, &s, false);
998a4334 138 if(!(ret > 0))
4957a608 139 return ret;
998a4334 140
263f6a5a 141 if(len > bufsize) {
4957a608
BH
142 bufsize=len;
143 scoped_array<unsigned char> narray(new unsigned char[bufsize]);
144 buf.swap(narray);
998a4334 145 }
263f6a5a
BH
146 memcpy(buf.get(), packet.c_str(), len);
147
998a4334
BH
148 ret=1;
149 }
150 catch(NetworkError& ne) {
151 ret = -2; // OS limits error
66ab6a63 152 }
5c633640 153 }
998a4334 154
81883dcc 155
26de3092
BH
156 lwr->d_usec=dt.udiff();
157 *now=dt.getTimeval();
158
263f6a5a
BH
159 if(ret <= 0) // includes 'timeout'
160 return ret;
e14f094b 161
e325f20c 162 lwr->d_records.clear();
c836dc19 163 try {
f1f85f12 164 lwr->d_tcbit=0;
263f6a5a
BH
165 MOADNSParser mdp((const char*)buf.get(), len);
166 lwr->d_aabit=mdp.d_header.aa;
167 lwr->d_tcbit=mdp.d_header.tc;
168 lwr->d_rcode=mdp.d_header.rcode;
169
81883dcc
BH
170 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
171 return 1; // this is "success", the error is set in lwr->d_rcode
172 }
173
e325f20c 174 if(domain != mdp.d_qname) {
c5c066bf 175 if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too
4957a608 176 L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01608dca 177 }
284aa5c2 178 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
179 goto out;
180 }
e325f20c 181
182 for(const auto& a : mdp.d_answers)
183 lwr->d_records.push_back(a.first);
81883dcc
BH
184
185 EDNSOpts edo;
57769f13 186 if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
81883dcc 187 lwr->d_haveEDNS = true;
376effcf 188
189 for(const auto& opt : edo.d_options) {
190 if(opt.first==8) {
191 EDNSSubnetOpts reso;
192 if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
bf4ab707 193 // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
6dd7e60c 194 if(reso.scope.getBits())
376effcf 195 srcmask = reso.scope;
196 }
197 }
198
199 }
81883dcc
BH
200 }
201
263f6a5a 202 return 1;
c836dc19 203 }
fdbf35ac 204 catch(std::exception &mde) {
aab4adb0 205 if(::arg().mustDo("log-common-errors"))
263f6a5a 206 L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
81883dcc
BH
207 lwr->d_rcode = RCode::FormErr;
208 g_stats.serverParseError++;
209 return 1; // success - oddly enough
aab4adb0 210 }
c836dc19 211 catch(...) {
ad1bb608 212 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 213 }
263f6a5a 214
aab4adb0 215 g_stats.serverParseError++;
263f6a5a 216
2353fffa 217 out:
81883dcc
BH
218 if(!lwr->d_rcode)
219 lwr->d_rcode=RCode::ServFail;
263f6a5a
BH
220
221 return -1;
e14f094b
BH
222}
223