]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
fix SOA record in HOWTO
[thirdparty/pdns.git] / pdns / lwres.cc
CommitLineData
e14f094b 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
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
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
36c5ee42 25#include "utility.hh"
e14f094b 26#include "lwres.hh"
e14f094b 27#include <iostream>
81883dcc 28#include "dnsrecords.hh"
e14f094b
BH
29#include <errno.h>
30#include "misc.hh"
31#include <algorithm>
32#include <sstream>
33#include <cstring>
34#include <string>
35#include <vector>
e14f094b
BH
36#include "dns.hh"
37#include "qtype.hh"
5c409fa2 38#include "pdnsexception.hh"
e14f094b 39#include "arguments.hh"
5c633640
BH
40#include "sstuff.hh"
41#include "syncres.hh"
ea634573
BH
42#include "dnswriter.hh"
43#include "dnsparser.hh"
aab4adb0 44#include "logger.hh"
51e2144e 45#include "dns_random.hh"
263f6a5a 46#include <boost/scoped_array.hpp>
51e2144e 47#include <boost/algorithm/string.hpp>
12ce523e 48#include "validate-recursor.hh"
c4443ccb 49#include "ednssubnet.hh"
51e2144e 50
4898a348
RG
51#ifdef HAVE_PROTOBUF
52
53static void logOutgoingQuery(std::shared_ptr<RemoteLogger> outgoingLogger, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes)
54{
55 if(!outgoingLogger)
56 return;
57
58 RecProtoBufMessage message(DNSProtoBufMessage::OutgoingQuery, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
59 if (initialRequestId) {
60 message.setInitialRequestID(*initialRequestId);
61 }
62
63// cerr <<message.toDebugString()<<endl;
64 std::string str;
65 message.serialize(str);
66 outgoingLogger->queueData(str);
67}
68
69static void logIncomingResponse(std::shared_ptr<RemoteLogger> outgoingLogger, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime)
70{
71 if(!outgoingLogger)
72 return;
73
74 RecProtoBufMessage message(DNSProtoBufMessage::IncomingResponse, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
75 if (initialRequestId) {
76 message.setInitialRequestID(*initialRequestId);
77 }
78 message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
79 message.setResponseCode(rcode);
80 message.addRRs(records);
81
82// cerr <<message.toDebugString()<<endl;
83 std::string str;
84 message.serialize(str);
85 outgoingLogger->queueData(str);
86}
87#endif /* HAVE_PROTOBUF */
88
81883dcc
BH
89//! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success
90/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
91 Never throws!
92 */
4898a348 93int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult *lwr)
e14f094b 94{
a683e8bd
RG
95 size_t len;
96 size_t bufsize=g_outgoingEDNSBufsize;
263f6a5a 97 scoped_array<unsigned char> buf(new unsigned char[bufsize]);
ea634573 98 vector<uint8_t> vpacket;
51e2144e 99 // string mapped0x20=dns0x20(domain);
4898a348 100 uint16_t qid = dns_random(0xffff);
ea634573
BH
101 DNSPacketWriter pw(vpacket, domain, type);
102
c1d73d94 103 pw.getHeader()->rd=sendRDQuery;
4898a348 104 pw.getHeader()->id=qid;
5a7d2a18
PL
105 /* RFC 6840 section 5.9:
106 * This document further specifies that validating resolvers SHOULD set
107 * the CD bit on every upstream query. This is regardless of whether
108 * the CD bit was set on the incoming query [...]
109 *
110 * sendRDQuery is only true if the qname is part of a forward-zone-recurse (or
111 * set in the forward-zone-file), so we use this as an indicator for it being
112 * an "upstream query". To stay true to "dnssec=off means 3.X behaviour", we
113 * only set +CD on forwarded query in any mode other than dnssec=off.
114 */
e7b18884 115 pw.getHeader()->cd=(sendRDQuery && g_dnssecmode != DNSSECMode::Off);
5a7d2a18 116
81883dcc 117 string ping;
7bb598a0 118 bool weWantEDNSSubnet=false;
a2e0174c 119 if(EDNS0Level) {
81883dcc 120 DNSPacketWriter::optvect_t opts;
376effcf 121 if(srcmask) {
122 EDNSSubnetOpts eo;
123 eo.source = *srcmask;
bf4ab707 124 // cout<<"Adding request mask: "<<eo.source.toString()<<endl;
376effcf 125 opts.push_back(make_pair(8, makeEDNSSubnetOptsString(eo)));
126 srcmask=boost::optional<Netmask>(); // this is also our return value
7bb598a0 127 weWantEDNSSubnet=true;
376effcf 128 }
93d4a890 129
12ce523e 130 pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
2188dcc3
BH
131 pw.commit();
132 }
81883dcc 133 lwr->d_rcode = 0;
81883dcc 134 lwr->d_haveEDNS = false;
eefd15f9
BH
135 int ret;
136
137 DTime dt;
4c4765c1 138 dt.set();
139 *now=dt.getTimeval();
4898a348
RG
140
141#ifdef HAVE_PROTOBUF
142 boost::uuids::uuid uuid;
143 const struct timeval queryTime = *now;
144
145 if (outgoingLogger) {
146 uuid = (*t_uuidGenerator)();
147 logOutgoingQuery(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size());
148 }
149#endif
150
263f6a5a 151 errno=0;
5c633640 152 if(!doTCP) {
4ef015cd 153 int queryfd;
996c89cc
BH
154 if(ip.sin4.sin_family==AF_INET6)
155 g_stats.ipv6queries++;
156
4898a348 157 if((ret=asendto((const char*)&*vpacket.begin(), vpacket.size(), 0, ip, qid,
232f0877 158 domain, type, &queryfd)) < 0) {
998a4334 159 return ret; // passes back the -2 EMFILE
5c633640
BH
160 }
161
162 // sleep until we see an answer to this, interface to mtasker
163
4898a348 164 ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, qid,
232f0877 165 domain, type, queryfd, now);
e14f094b 166 }
5c633640 167 else {
998a4334 168 try {
93f4e5ce 169 Socket s(ip.sin4.sin_family, SOCK_STREAM);
fdf05fd4 170
998a4334 171 s.setNonBlocking();
1652a63e 172 ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
3ac2a2ab 173
5a38281c 174 s.bind(local);
4957a608 175
fdf05fd4
BH
176 ComboAddress remote = ip;
177 remote.sin4.sin_port = htons(53);
178 s.connect(remote);
998a4334 179
263f6a5a
BH
180 uint16_t tlen=htons(vpacket.size());
181 char *lenP=(char*)&tlen;
998a4334
BH
182 const char *msgP=(const char*)&*vpacket.begin();
183 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
184
185 ret=asendtcp(packet, &s);
186 if(!(ret>0))
4957a608 187 return ret;
998a4334
BH
188
189 packet.clear();
825fa717 190 ret=arecvtcp(packet, 2, &s, false);
998a4334 191 if(!(ret > 0))
4957a608 192 return ret;
998a4334 193
a683e8bd 194 memcpy(&tlen, packet.c_str(), sizeof(tlen));
263f6a5a 195 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334 196
825fa717 197 ret=arecvtcp(packet, len, &s, false);
998a4334 198 if(!(ret > 0))
4957a608 199 return ret;
998a4334 200
263f6a5a 201 if(len > bufsize) {
4957a608
BH
202 bufsize=len;
203 scoped_array<unsigned char> narray(new unsigned char[bufsize]);
204 buf.swap(narray);
998a4334 205 }
263f6a5a
BH
206 memcpy(buf.get(), packet.c_str(), len);
207
998a4334
BH
208 ret=1;
209 }
210 catch(NetworkError& ne) {
211 ret = -2; // OS limits error
66ab6a63 212 }
5c633640 213 }
998a4334 214
81883dcc 215
26de3092
BH
216 lwr->d_usec=dt.udiff();
217 *now=dt.getTimeval();
218
263f6a5a
BH
219 if(ret <= 0) // includes 'timeout'
220 return ret;
e14f094b 221
e325f20c 222 lwr->d_records.clear();
c836dc19 223 try {
f1f85f12 224 lwr->d_tcbit=0;
263f6a5a
BH
225 MOADNSParser mdp((const char*)buf.get(), len);
226 lwr->d_aabit=mdp.d_header.aa;
227 lwr->d_tcbit=mdp.d_header.tc;
228 lwr->d_rcode=mdp.d_header.rcode;
229
81883dcc 230 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
4898a348
RG
231#ifdef HAVE_PROTOBUF
232 if(outgoingLogger) {
233 logIncomingResponse(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime);
234 }
235#endif
81883dcc
BH
236 return 1; // this is "success", the error is set in lwr->d_rcode
237 }
238
e325f20c 239 if(domain != mdp.d_qname) {
c5c066bf 240 if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too
4957a608 241 L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01608dca 242 }
284aa5c2 243 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
244 goto out;
245 }
e325f20c 246
247 for(const auto& a : mdp.d_answers)
248 lwr->d_records.push_back(a.first);
81883dcc
BH
249
250 EDNSOpts edo;
57769f13 251 if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
81883dcc 252 lwr->d_haveEDNS = true;
376effcf 253
7bb598a0 254 if(weWantEDNSSubnet) {
255 for(const auto& opt : edo.d_options) {
256 if(opt.first==8) {
257 EDNSSubnetOpts reso;
258 if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
259 // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
260 if(reso.scope.getBits())
261 srcmask = reso.scope;
262 }
263 }
264 }
376effcf 265 }
81883dcc
BH
266 }
267
4898a348
RG
268#ifdef HAVE_PROTOBUF
269 if(outgoingLogger) {
270 logIncomingResponse(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime);
271 }
272#endif
263f6a5a 273 return 1;
c836dc19 274 }
fdbf35ac 275 catch(std::exception &mde) {
aab4adb0 276 if(::arg().mustDo("log-common-errors"))
263f6a5a 277 L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
81883dcc 278 lwr->d_rcode = RCode::FormErr;
4898a348
RG
279 g_stats.serverParseError++;
280#ifdef HAVE_PROTOBUF
281 if(outgoingLogger) {
282 logIncomingResponse(outgoingLogger, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime);
283 }
284#endif
81883dcc 285 return 1; // success - oddly enough
aab4adb0 286 }
c836dc19 287 catch(...) {
ad1bb608 288 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 289 }
263f6a5a 290
aab4adb0 291 g_stats.serverParseError++;
263f6a5a 292
2353fffa 293 out:
81883dcc
BH
294 if(!lwr->d_rcode)
295 lwr->d_rcode=RCode::ServFail;
263f6a5a
BH
296
297 return -1;
e14f094b
BH
298}
299