]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
Merge pull request #7677 from rgacogne/dnsdist-logging-facility
[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
d61aa945
RG
53#include "uuid-utils.hh"
54
3fe06137 55static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, 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, boost::optional<Netmask>& srcmask)
4898a348 56{
b773359c 57 if(!outgoingLoggers)
4898a348
RG
58 return;
59
60 RecProtoBufMessage message(DNSProtoBufMessage::OutgoingQuery, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
c165308b
RG
61 message.setServerIdentity(SyncRes::s_serverID);
62
4898a348
RG
63 if (initialRequestId) {
64 message.setInitialRequestID(*initialRequestId);
65 }
66
0ff13512
RG
67 if (srcmask) {
68 message.setEDNSSubnet(*srcmask);
69 }
70
4898a348
RG
71// cerr <<message.toDebugString()<<endl;
72 std::string str;
73 message.serialize(str);
b773359c
RG
74
75 for (auto& logger : *outgoingLoggers) {
76 logger->queueData(str);
77 }
4898a348
RG
78}
79
3fe06137 80static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, 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, const std::set<uint16_t>& exportTypes)
4898a348 81{
b773359c 82 if(!outgoingLoggers)
4898a348
RG
83 return;
84
85 RecProtoBufMessage message(DNSProtoBufMessage::IncomingResponse, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
c165308b 86 message.setServerIdentity(SyncRes::s_serverID);
4898a348
RG
87 if (initialRequestId) {
88 message.setInitialRequestID(*initialRequestId);
89 }
90 message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
91 message.setResponseCode(rcode);
0bd2e252 92 message.addRRs(records, exportTypes);
4898a348
RG
93
94// cerr <<message.toDebugString()<<endl;
95 std::string str;
96 message.serialize(str);
b773359c
RG
97
98 for (auto& logger : *outgoingLoggers) {
99 logger->queueData(str);
100 }
4898a348
RG
101}
102#endif /* HAVE_PROTOBUF */
103
81883dcc
BH
104//! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success
105/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
106 Never throws!
107 */
3fe06137 108int 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, const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const std::set<uint16_t>& exportTypes, LWResult *lwr, bool* chained)
e14f094b 109{
a683e8bd
RG
110 size_t len;
111 size_t bufsize=g_outgoingEDNSBufsize;
78f56b38
RG
112 std::string buf;
113 buf.resize(bufsize);
ea634573 114 vector<uint8_t> vpacket;
51e2144e 115 // string mapped0x20=dns0x20(domain);
4898a348 116 uint16_t qid = dns_random(0xffff);
ea634573
BH
117 DNSPacketWriter pw(vpacket, domain, type);
118
c1d73d94 119 pw.getHeader()->rd=sendRDQuery;
4898a348 120 pw.getHeader()->id=qid;
5a7d2a18
PL
121 /* RFC 6840 section 5.9:
122 * This document further specifies that validating resolvers SHOULD set
123 * the CD bit on every upstream query. This is regardless of whether
124 * the CD bit was set on the incoming query [...]
125 *
126 * sendRDQuery is only true if the qname is part of a forward-zone-recurse (or
127 * set in the forward-zone-file), so we use this as an indicator for it being
128 * an "upstream query". To stay true to "dnssec=off means 3.X behaviour", we
129 * only set +CD on forwarded query in any mode other than dnssec=off.
130 */
e7b18884 131 pw.getHeader()->cd=(sendRDQuery && g_dnssecmode != DNSSECMode::Off);
5a7d2a18 132
81883dcc 133 string ping;
7bb598a0 134 bool weWantEDNSSubnet=false;
30d4402d
RG
135 uint8_t outgoingECSBits = 0;
136 ComboAddress outgoingECSAddr;
fe61f5d8 137 if(EDNS0Level > 0) {
81883dcc 138 DNSPacketWriter::optvect_t opts;
376effcf 139 if(srcmask) {
140 EDNSSubnetOpts eo;
141 eo.source = *srcmask;
30d4402d
RG
142 outgoingECSBits = srcmask->getBits();
143 outgoingECSAddr = srcmask->getNetwork();
bf4ab707 144 // cout<<"Adding request mask: "<<eo.source.toString()<<endl;
30d4402d 145 opts.push_back(make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(eo)));
7bb598a0 146 weWantEDNSSubnet=true;
376effcf 147 }
93d4a890 148
12ce523e 149 pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
2188dcc3
BH
150 pw.commit();
151 }
81883dcc 152 lwr->d_rcode = 0;
81883dcc 153 lwr->d_haveEDNS = false;
eefd15f9
BH
154 int ret;
155
156 DTime dt;
4c4765c1 157 dt.set();
158 *now=dt.getTimeval();
4898a348
RG
159
160#ifdef HAVE_PROTOBUF
161 boost::uuids::uuid uuid;
162 const struct timeval queryTime = *now;
163
b773359c 164 if (outgoingLoggers) {
d61aa945 165 uuid = getUniqueID();
b773359c 166 logOutgoingQuery(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size(), srcmask);
4898a348
RG
167 }
168#endif
169
0ff13512
RG
170 srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0
171
263f6a5a 172 errno=0;
5c633640 173 if(!doTCP) {
4ef015cd 174 int queryfd;
996c89cc
BH
175 if(ip.sin4.sin_family==AF_INET6)
176 g_stats.ipv6queries++;
177
4898a348 178 if((ret=asendto((const char*)&*vpacket.begin(), vpacket.size(), 0, ip, qid,
232f0877 179 domain, type, &queryfd)) < 0) {
998a4334 180 return ret; // passes back the -2 EMFILE
5c633640 181 }
deca7d8f
RG
182
183 if (queryfd == -1) {
184 *chained = true;
185 }
186
5c633640
BH
187 // sleep until we see an answer to this, interface to mtasker
188
f128d20d 189 ret=arecvfrom(buf, 0, ip, &len, qid,
232f0877 190 domain, type, queryfd, now);
e14f094b 191 }
5c633640 192 else {
998a4334 193 try {
93f4e5ce 194 Socket s(ip.sin4.sin_family, SOCK_STREAM);
fdf05fd4 195
998a4334 196 s.setNonBlocking();
1652a63e 197 ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
3ac2a2ab 198
5a38281c 199 s.bind(local);
4957a608 200
1bde6efa 201 s.connect(ip);
998a4334 202
263f6a5a
BH
203 uint16_t tlen=htons(vpacket.size());
204 char *lenP=(char*)&tlen;
998a4334
BH
205 const char *msgP=(const char*)&*vpacket.begin();
206 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
207
208 ret=asendtcp(packet, &s);
209 if(!(ret>0))
4957a608 210 return ret;
998a4334
BH
211
212 packet.clear();
825fa717 213 ret=arecvtcp(packet, 2, &s, false);
998a4334 214 if(!(ret > 0))
4957a608 215 return ret;
998a4334 216
a683e8bd 217 memcpy(&tlen, packet.c_str(), sizeof(tlen));
263f6a5a 218 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334 219
825fa717 220 ret=arecvtcp(packet, len, &s, false);
998a4334 221 if(!(ret > 0))
4957a608 222 return ret;
998a4334 223
78f56b38
RG
224 buf.resize(len);
225 memcpy(const_cast<char*>(buf.data()), packet.c_str(), len);
263f6a5a 226
998a4334
BH
227 ret=1;
228 }
229 catch(NetworkError& ne) {
230 ret = -2; // OS limits error
66ab6a63 231 }
5c633640 232 }
998a4334 233
81883dcc 234
26de3092
BH
235 lwr->d_usec=dt.udiff();
236 *now=dt.getTimeval();
237
263f6a5a
BH
238 if(ret <= 0) // includes 'timeout'
239 return ret;
e14f094b 240
78f56b38 241 buf.resize(len);
e325f20c 242 lwr->d_records.clear();
c836dc19 243 try {
f1f85f12 244 lwr->d_tcbit=0;
78f56b38 245 MOADNSParser mdp(false, buf);
263f6a5a
BH
246 lwr->d_aabit=mdp.d_header.aa;
247 lwr->d_tcbit=mdp.d_header.tc;
248 lwr->d_rcode=mdp.d_header.rcode;
249
81883dcc 250 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
4898a348 251#ifdef HAVE_PROTOBUF
b773359c
RG
252 if(outgoingLoggers) {
253 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
4898a348
RG
254 }
255#endif
269ac73d 256 lwr->d_validpacket=true;
81883dcc
BH
257 return 1; // this is "success", the error is set in lwr->d_rcode
258 }
259
e325f20c 260 if(domain != mdp.d_qname) {
c5c066bf 261 if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too
e6a9dde5 262 g_log<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01608dca 263 }
284aa5c2 264 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
265 goto out;
266 }
f128d20d
RG
267
268 lwr->d_records.reserve(mdp.d_answers.size());
e325f20c 269 for(const auto& a : mdp.d_answers)
270 lwr->d_records.push_back(a.first);
81883dcc
BH
271
272 EDNSOpts edo;
57769f13 273 if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
81883dcc 274 lwr->d_haveEDNS = true;
376effcf 275
7bb598a0 276 if(weWantEDNSSubnet) {
277 for(const auto& opt : edo.d_options) {
30d4402d 278 if(opt.first==EDNSOptionCode::ECS) {
7bb598a0 279 EDNSSubnetOpts reso;
280 if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
281 // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
fe61f5d8
RG
282 /* rfc7871 states that 0 "indicate[s] that the answer is suitable for all addresses in FAMILY",
283 so we might want to still pass the information along to be able to differentiate between
284 IPv4 and IPv6. Still I'm pretty sure it doesn't matter in real life, so let's not duplicate
285 entries in our cache. */
30d4402d
RG
286 if(reso.scope.getBits()) {
287 uint8_t bits = std::min(reso.scope.getBits(), outgoingECSBits);
288 outgoingECSAddr.truncate(bits);
289 srcmask = Netmask(outgoingECSAddr, bits);
290 }
7bb598a0 291 }
292 }
293 }
376effcf 294 }
81883dcc
BH
295 }
296
4898a348 297#ifdef HAVE_PROTOBUF
b773359c
RG
298 if(outgoingLoggers) {
299 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
4898a348
RG
300 }
301#endif
269ac73d 302 lwr->d_validpacket=true;
263f6a5a 303 return 1;
c836dc19 304 }
fdbf35ac 305 catch(std::exception &mde) {
aab4adb0 306 if(::arg().mustDo("log-common-errors"))
e6a9dde5 307 g_log<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
81883dcc 308 lwr->d_rcode = RCode::FormErr;
4898a348
RG
309 g_stats.serverParseError++;
310#ifdef HAVE_PROTOBUF
b773359c
RG
311 if(outgoingLoggers) {
312 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
4898a348
RG
313 }
314#endif
269ac73d 315 lwr->d_validpacket=false;
81883dcc 316 return 1; // success - oddly enough
aab4adb0 317 }
c836dc19 318 catch(...) {
e6a9dde5 319 g_log<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 320 }
263f6a5a 321
aab4adb0 322 g_stats.serverParseError++;
263f6a5a 323
2353fffa 324 out:
81883dcc
BH
325 if(!lwr->d_rcode)
326 lwr->d_rcode=RCode::ServFail;
263f6a5a
BH
327
328 return -1;
e14f094b
BH
329}
330