]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
More licensing everywhere
[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{
a683e8bd
RG
59 size_t len;
60 size_t 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);
5a7d2a18
PL
68 /* RFC 6840 section 5.9:
69 * This document further specifies that validating resolvers SHOULD set
70 * the CD bit on every upstream query. This is regardless of whether
71 * the CD bit was set on the incoming query [...]
72 *
73 * sendRDQuery is only true if the qname is part of a forward-zone-recurse (or
74 * set in the forward-zone-file), so we use this as an indicator for it being
75 * an "upstream query". To stay true to "dnssec=off means 3.X behaviour", we
76 * only set +CD on forwarded query in any mode other than dnssec=off.
77 */
e7b18884 78 pw.getHeader()->cd=(sendRDQuery && g_dnssecmode != DNSSECMode::Off);
5a7d2a18 79
81883dcc 80 string ping;
7bb598a0 81 bool weWantEDNSSubnet=false;
a2e0174c 82 if(EDNS0Level) {
81883dcc 83 DNSPacketWriter::optvect_t opts;
376effcf 84 if(srcmask) {
85 EDNSSubnetOpts eo;
86 eo.source = *srcmask;
bf4ab707 87 // cout<<"Adding request mask: "<<eo.source.toString()<<endl;
376effcf 88 opts.push_back(make_pair(8, makeEDNSSubnetOptsString(eo)));
89 srcmask=boost::optional<Netmask>(); // this is also our return value
7bb598a0 90 weWantEDNSSubnet=true;
376effcf 91 }
93d4a890 92
12ce523e 93 pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
2188dcc3
BH
94 pw.commit();
95 }
81883dcc 96 lwr->d_rcode = 0;
81883dcc 97 lwr->d_haveEDNS = false;
eefd15f9
BH
98 int ret;
99
100 DTime dt;
4c4765c1 101 dt.set();
102 *now=dt.getTimeval();
263f6a5a 103 errno=0;
5c633640 104 if(!doTCP) {
4ef015cd 105 int queryfd;
996c89cc
BH
106 if(ip.sin4.sin_family==AF_INET6)
107 g_stats.ipv6queries++;
108
a683e8bd 109 if((ret=asendto((const char*)&*vpacket.begin(), vpacket.size(), 0, ip, pw.getHeader()->id,
232f0877 110 domain, type, &queryfd)) < 0) {
998a4334 111 return ret; // passes back the -2 EMFILE
5c633640
BH
112 }
113
114 // sleep until we see an answer to this, interface to mtasker
115
263f6a5a 116 ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id,
232f0877 117 domain, type, queryfd, now);
e14f094b 118 }
5c633640 119 else {
998a4334 120 try {
93f4e5ce 121 Socket s(ip.sin4.sin_family, SOCK_STREAM);
fdf05fd4 122
998a4334 123 s.setNonBlocking();
1652a63e 124 ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
3ac2a2ab 125
5a38281c 126 s.bind(local);
4957a608 127
fdf05fd4
BH
128 ComboAddress remote = ip;
129 remote.sin4.sin_port = htons(53);
130 s.connect(remote);
998a4334 131
263f6a5a
BH
132 uint16_t tlen=htons(vpacket.size());
133 char *lenP=(char*)&tlen;
998a4334
BH
134 const char *msgP=(const char*)&*vpacket.begin();
135 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
136
137 ret=asendtcp(packet, &s);
138 if(!(ret>0))
4957a608 139 return ret;
998a4334
BH
140
141 packet.clear();
825fa717 142 ret=arecvtcp(packet, 2, &s, false);
998a4334 143 if(!(ret > 0))
4957a608 144 return ret;
998a4334 145
a683e8bd 146 memcpy(&tlen, packet.c_str(), sizeof(tlen));
263f6a5a 147 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334 148
825fa717 149 ret=arecvtcp(packet, len, &s, false);
998a4334 150 if(!(ret > 0))
4957a608 151 return ret;
998a4334 152
263f6a5a 153 if(len > bufsize) {
4957a608
BH
154 bufsize=len;
155 scoped_array<unsigned char> narray(new unsigned char[bufsize]);
156 buf.swap(narray);
998a4334 157 }
263f6a5a
BH
158 memcpy(buf.get(), packet.c_str(), len);
159
998a4334
BH
160 ret=1;
161 }
162 catch(NetworkError& ne) {
163 ret = -2; // OS limits error
66ab6a63 164 }
5c633640 165 }
998a4334 166
81883dcc 167
26de3092
BH
168 lwr->d_usec=dt.udiff();
169 *now=dt.getTimeval();
170
263f6a5a
BH
171 if(ret <= 0) // includes 'timeout'
172 return ret;
e14f094b 173
e325f20c 174 lwr->d_records.clear();
c836dc19 175 try {
f1f85f12 176 lwr->d_tcbit=0;
263f6a5a
BH
177 MOADNSParser mdp((const char*)buf.get(), len);
178 lwr->d_aabit=mdp.d_header.aa;
179 lwr->d_tcbit=mdp.d_header.tc;
180 lwr->d_rcode=mdp.d_header.rcode;
181
81883dcc
BH
182 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
183 return 1; // this is "success", the error is set in lwr->d_rcode
184 }
185
e325f20c 186 if(domain != mdp.d_qname) {
c5c066bf 187 if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too
4957a608 188 L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01608dca 189 }
284aa5c2 190 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
191 goto out;
192 }
e325f20c 193
194 for(const auto& a : mdp.d_answers)
195 lwr->d_records.push_back(a.first);
81883dcc
BH
196
197 EDNSOpts edo;
57769f13 198 if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
81883dcc 199 lwr->d_haveEDNS = true;
376effcf 200
7bb598a0 201 if(weWantEDNSSubnet) {
202 for(const auto& opt : edo.d_options) {
203 if(opt.first==8) {
204 EDNSSubnetOpts reso;
205 if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
206 // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
207 if(reso.scope.getBits())
208 srcmask = reso.scope;
209 }
210 }
211 }
376effcf 212 }
81883dcc
BH
213 }
214
263f6a5a 215 return 1;
c836dc19 216 }
fdbf35ac 217 catch(std::exception &mde) {
aab4adb0 218 if(::arg().mustDo("log-common-errors"))
263f6a5a 219 L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
81883dcc
BH
220 lwr->d_rcode = RCode::FormErr;
221 g_stats.serverParseError++;
222 return 1; // success - oddly enough
aab4adb0 223 }
c836dc19 224 catch(...) {
ad1bb608 225 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 226 }
263f6a5a 227
aab4adb0 228 g_stats.serverParseError++;
263f6a5a 229
2353fffa 230 out:
81883dcc
BH
231 if(!lwr->d_rcode)
232 lwr->d_rcode=RCode::ServFail;
263f6a5a
BH
233
234 return -1;
e14f094b
BH
235}
236