]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
Introducing TCounters
[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"
20829585 50#include "query-local-address.hh"
2a17f6c6 51#include "tcpiohandler.hh"
5abc5e10 52#include "ednsoptions.hh"
1050a5c8 53#include "ednspadding.hh"
00b3e94a 54#include "rec-protozero.hh"
d61aa945 55#include "uuid-utils.hh"
631cb36b
O
56#include "rec-tcpout.hh"
57
58thread_local TCPOutConnectionManager t_tcp_manager;
91092a9f 59std::shared_ptr<Logr::Logger> g_slogout;
fcf47f49 60bool g_paddingOutgoing;
d61aa945 61
4d7db3d7
OM
62void remoteLoggerQueueData(RemoteLoggerInterface& r, const std::string& data)
63{
64 auto ret = r.queueData(data);
65
66 switch (ret) {
67 case RemoteLoggerInterface::Result::Queued:
68 break;
69 case RemoteLoggerInterface::Result::PipeFull: {
74b9e43d 70 const auto msg = RemoteLoggerInterface::toErrorString(ret);
4d7db3d7 71 const auto name = r.name();
4d7db3d7
OM
72 SLOG(g_log << Logger::Debug << name << ": " << msg <<std::endl,
73 g_slog->withName(name)->info(Logr::Debug, msg));
74 break;
75 }
76 case RemoteLoggerInterface::Result::TooLarge: {
74b9e43d 77 const auto msg = RemoteLoggerInterface::toErrorString(ret);
4d7db3d7 78 const auto name = r.name();
4d7db3d7
OM
79 SLOG(g_log << Logger::Notice << name << ": " << msg <<endl,
80 g_slog->withName(name)->info(Logr::Debug, msg));
81 break;
82 }
83 case RemoteLoggerInterface::Result::OtherError: {
74b9e43d 84 const auto msg = RemoteLoggerInterface::toErrorString(ret);
4d7db3d7 85 const auto name = r.name();
4d7db3d7
OM
86 SLOG(g_log << Logger::Warning << name << ": " << msg << std::endl,
87 g_slog->withName(name)->info(Logr::Warning, msg));
88 break;
89 }
90 }
91}
92
66927b32
OM
93#ifdef HAVE_FSTRM
94#include "dnstap.hh"
95#include "fstrm_logger.hh"
96
97bool g_syslog;
98
10ba6d01 99static bool isEnabledForQueries(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers)
573f4ff0
OM
100{
101 if (fstreamLoggers == nullptr) {
102 return false;
103 }
104 for (auto& logger : *fstreamLoggers) {
10ba6d01 105 if (logger->logQueries()) {
573f4ff0
OM
106 return true;
107 }
108 }
109 return false;
110}
111
46314dcf 112static void logFstreamQuery(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers, const struct timeval &queryTime, const ComboAddress& localip, const ComboAddress& ip, DnstapMessage::ProtocolType protocol, boost::optional<const DNSName&> auth, const vector<uint8_t>& packet)
4898a348 113{
b9fa43e0 114 if (fstreamLoggers == nullptr)
4898a348
RG
115 return;
116
b9fa43e0
OM
117 struct timespec ts;
118 TIMEVAL_TO_TIMESPEC(&queryTime, &ts);
b9fa43e0 119 std::string str;
46314dcf 120 DnstapMessage message(str, DnstapMessage::MessageType::resolver_query, SyncRes::s_serverID, &localip, &ip, protocol, reinterpret_cast<const char*>(&*packet.begin()), packet.size(), &ts, nullptr, auth);
c165308b 121
b9fa43e0 122 for (auto& logger : *fstreamLoggers) {
4d7db3d7 123 remoteLoggerQueueData(*logger, str);
b9fa43e0
OM
124 }
125}
4898a348 126
10ba6d01 127static bool isEnabledForResponses(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers)
573f4ff0
OM
128{
129 if (fstreamLoggers == nullptr) {
130 return false;
131 }
132 for (auto& logger : *fstreamLoggers) {
10ba6d01 133 if (logger->logResponses()) {
573f4ff0
OM
134 return true;
135 }
136 }
137 return false;
138}
139
46314dcf 140static void logFstreamResponse(const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstreamLoggers, const ComboAddress&localip, const ComboAddress& ip, DnstapMessage::ProtocolType protocol, boost::optional<const DNSName&> auth, const PacketBuffer& packet, const struct timeval& queryTime, const struct timeval& replyTime)
b9fa43e0
OM
141{
142 if (fstreamLoggers == nullptr)
143 return;
0ff13512 144
b9fa43e0
OM
145 struct timespec ts1, ts2;
146 TIMEVAL_TO_TIMESPEC(&queryTime, &ts1);
147 TIMEVAL_TO_TIMESPEC(&replyTime, &ts2);
b9fa43e0 148 std::string str;
46314dcf 149 DnstapMessage message(str, DnstapMessage::MessageType::resolver_response, SyncRes::s_serverID, &localip, &ip, protocol, reinterpret_cast<const char*>(packet.data()), packet.size(), &ts1, &ts2, auth);
b773359c 150
b9fa43e0 151 for (auto& logger : *fstreamLoggers) {
4d7db3d7 152 remoteLoggerQueueData(*logger, str);
b773359c 153 }
4898a348
RG
154}
155
b9fa43e0 156#endif // HAVE_FSTRM
ebd67986 157
cffd3a17 158static 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, bool tls, size_t bytes, boost::optional<Netmask>& srcmask)
4898a348 159{
5d6c7a46 160 if (!outgoingLoggers) {
4898a348 161 return;
5d6c7a46
RG
162 }
163
164 bool log = false;
165 for (auto& logger : *outgoingLoggers) {
166 if (logger->logQueries()) {
167 log = true;
168 break;
169 }
170 }
171
172 if (!log) {
173 return;
174 }
4898a348 175
00b3e94a
RG
176 static thread_local std::string buffer;
177 buffer.clear();
178 pdns::ProtoZero::Message m{buffer};
89addb82 179 m.setType(pdns::ProtoZero::Message::MessageType::DNSOutgoingQueryType);
00b3e94a
RG
180 m.setMessageIdentity(uuid);
181 m.setSocketFamily(ip.sin4.sin_family);
cffd3a17
RG
182 if (!doTCP) {
183 m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::UDP);
184 }
185 else if (!tls) {
186 m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::TCP);
187 }
188 else {
189 m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::DoT);
190 }
191
00b3e94a
RG
192 m.setTo(ip);
193 m.setInBytes(bytes);
194 m.setTime();
195 m.setId(qid);
196 m.setQuestion(domain, type, QClass::IN);
197 m.setToPort(ip.getPort());
198 m.setServerIdentity(SyncRes::s_serverID);
c165308b 199
4898a348 200 if (initialRequestId) {
00b3e94a 201 m.setInitialRequestID(*initialRequestId);
4898a348
RG
202 }
203
0ff13512 204 if (srcmask) {
00b3e94a 205 m.setEDNSSubnet(*srcmask, 128);
0ff13512
RG
206 }
207
b773359c 208 for (auto& logger : *outgoingLoggers) {
5d6c7a46 209 if (logger->logQueries()) {
4d7db3d7 210 remoteLoggerQueueData(*logger, buffer);
5d6c7a46 211 }
b773359c 212 }
4898a348
RG
213}
214
cffd3a17 215static 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, bool tls, boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
4898a348 216{
5d6c7a46
RG
217 if (!outgoingLoggers) {
218 return;
219 }
220
221 bool log = false;
222 for (auto& logger : *outgoingLoggers) {
223 if (logger->logResponses()) {
224 log = true;
225 break;
226 }
227 }
228
229 if (!log) {
4898a348 230 return;
5d6c7a46
RG
231 }
232
00b3e94a
RG
233 static thread_local std::string buffer;
234 buffer.clear();
235 pdns::ProtoZero::RecMessage m{buffer};
89addb82 236 m.setType(pdns::ProtoZero::Message::MessageType::DNSIncomingResponseType);
00b3e94a
RG
237 m.setMessageIdentity(uuid);
238 m.setSocketFamily(ip.sin4.sin_family);
cffd3a17
RG
239 if (!doTCP) {
240 m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::UDP);
241 }
242 else if (!tls) {
243 m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::TCP);
244 }
245 else {
246 m.setSocketProtocol(pdns::ProtoZero::Message::TransportProtocol::DoT);
247 }
00b3e94a
RG
248 m.setTo(ip);
249 m.setInBytes(bytes);
250 m.setTime();
251 m.setId(qid);
252 m.setQuestion(domain, type, QClass::IN);
253 m.setToPort(ip.getPort());
254 m.setServerIdentity(SyncRes::s_serverID);
5d6c7a46 255
00b3e94a
RG
256 if (initialRequestId) {
257 m.setInitialRequestID(*initialRequestId);
5d6c7a46 258 }
00b3e94a
RG
259
260 if (srcmask) {
261 m.setEDNSSubnet(*srcmask, 128);
5d6c7a46 262 }
4898a348 263
00b3e94a
RG
264 m.startResponse();
265 m.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
57f8413e 266 if (rcode == -1) {
00b3e94a 267 m.setNetworkErrorResponseCode();
57f8413e
RG
268 }
269 else {
00b3e94a 270 m.setResponseCode(rcode);
57f8413e 271 }
4898a348 272
00b3e94a
RG
273 for (const auto& record : records) {
274 m.addRR(record, exportTypes, false);
275 }
276 m.commitResponse();
b773359c
RG
277
278 for (auto& logger : *outgoingLoggers) {
5d6c7a46 279 if (logger->logResponses()) {
4d7db3d7 280 remoteLoggerQueueData(*logger, buffer);
5d6c7a46 281 }
b773359c 282 }
4898a348 283}
4898a348 284
086c80cd 285static bool tcpconnect(const struct timeval& now, const ComboAddress& ip, TCPOutConnectionManager::Connection& connection, bool& dnsOverTLS, const std::string& nsName)
caaea007
O
286{
287 dnsOverTLS = SyncRes::s_dot_to_port_853 && ip.getPort() == 853;
288
050b64ac
O
289 connection = t_tcp_manager.get(ip);
290 if (connection.d_handler) {
291 return false;
292 }
f3a69323 293
050b64ac
O
294 const struct timeval timeout{ g_networkTimeoutMsec / 1000, static_cast<suseconds_t>(g_networkTimeoutMsec) % 1000 * 1000};
295 Socket s(ip.sin4.sin_family, SOCK_STREAM);
296 s.setNonBlocking();
34b7ae04 297 setTCPNoDelay(s.getHandle());
050b64ac
O
298 ComboAddress localip = pdns::getQueryLocalAddress(ip.sin4.sin_family, 0);
299 s.bind(localip);
300
301 std::shared_ptr<TLSCtx> tlsCtx{nullptr};
302 if (dnsOverTLS) {
303 TLSContextParameters tlsParams;
304 tlsParams.d_provider = "openssl";
305 tlsParams.d_validateCertificates = false;
306 // tlsParams.d_caStore
307 tlsCtx = getTLSContext(tlsParams);
308 if (tlsCtx == nullptr) {
91092a9f
OM
309 SLOG(g_log << Logger::Error << "DoT to " << ip << " requested but not available" << endl,
310 g_slogout->info(Logr::Error, "DoT requested but not available", "server", Logging::Loggable(ip)));
050b64ac 311 dnsOverTLS = false;
caaea007 312 }
caaea007 313 }
74b08b2a 314 connection.d_handler = std::make_shared<TCPIOHandler>(nsName, false, s.releaseHandle(), timeout, tlsCtx, now.tv_sec);
050b64ac
O
315 // Returned state ignored
316 // This can throw an exception, retry will need to happen at higher level
317 connection.d_handler->tryConnect(SyncRes::s_tcp_fast_open_connect, ip);
318 return true;
caaea007
O
319}
320
f3a69323
O
321static LWResult::Result tcpsendrecv(const ComboAddress& ip, TCPOutConnectionManager::Connection& connection,
322 ComboAddress& localip, const vector<uint8_t>& vpacket, size_t& len, PacketBuffer& buf)
323{
324 socklen_t slen = ip.getSocklen();
325 uint16_t tlen = htons(vpacket.size());
326 const char *lenP = reinterpret_cast<const char*>(&tlen);
f3a69323 327
da886835 328 len = 0; // in case of error
f3a69323 329 localip.sin4.sin_family = ip.sin4.sin_family;
0344192c
OM
330 if (getsockname(connection.d_handler->getDescriptor(), reinterpret_cast<sockaddr*>(&localip), &slen) != 0) {
331 return LWResult::Result::PermanentError;
332 }
f3a69323
O
333
334 PacketBuffer packet;
335 packet.reserve(2 + vpacket.size());
336 packet.insert(packet.end(), lenP, lenP + 2);
050b64ac 337 packet.insert(packet.end(), vpacket.begin(), vpacket.end());
f3a69323
O
338
339 LWResult::Result ret = asendtcp(packet, connection.d_handler);
340 if (ret != LWResult::Result::Success) {
341 return ret;
342 }
343
344 ret = arecvtcp(packet, 2, connection.d_handler, false);
345 if (ret != LWResult::Result::Success) {
346 return ret;
347 }
348
349 memcpy(&tlen, packet.data(), sizeof(tlen));
350 len = ntohs(tlen); // switch to the 'len' shared with the rest of the calling function
351
352 // XXX receive into buf directly?
353 packet.resize(len);
354 ret = arecvtcp(packet, len, connection.d_handler, false);
355 if (ret != LWResult::Result::Success) {
356 return ret;
357 }
358 buf.resize(len);
359 memcpy(buf.data(), packet.data(), len);
360 return LWResult::Result::Success;
361}
362
1050a5c8
OM
363static void addPadding(const DNSPacketWriter& pw, size_t bufsize, DNSPacketWriter::optvect_t& opts)
364{
365 const size_t currentSize = pw.getSizeWithOpts(opts);
366 if (currentSize < (bufsize - 4)) {
367 const size_t remaining = bufsize - (currentSize + 4);
368 /* from rfc8647, "4.1. Recommended Strategy: Block-Length Padding":
369 Clients SHOULD pad queries to the closest multiple of 128 octets.
370 Note we are in the client role here.
371 */
372 const size_t blockSize = 128;
373 const size_t modulo = (currentSize + 4) % blockSize;
374 size_t padSize = 0;
375 if (modulo > 0) {
376 padSize = std::min(blockSize - modulo, remaining);
377 }
378 opts.emplace_back(EDNSOptionCode::PADDING, makeEDNSPaddingOptString(padSize));
379 }
380}
381
81883dcc
BH
382/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
383 Never throws!
384 */
80252248 385static LWResult::Result 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::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstrmLoggers, const std::set<uint16_t>& exportTypes, LWResult *lwr, bool* chained, TCPOutConnectionManager::Connection& connection)
e14f094b 386{
a683e8bd
RG
387 size_t len;
388 size_t bufsize=g_outgoingEDNSBufsize;
2a17f6c6 389 PacketBuffer buf;
78f56b38 390 buf.resize(bufsize);
ea634573 391 vector<uint8_t> vpacket;
51e2144e 392 // string mapped0x20=dns0x20(domain);
a410b176 393 uint16_t qid = dns_random_uint16();
ea634573 394 DNSPacketWriter pw(vpacket, domain, type);
1050a5c8 395 bool dnsOverTLS = SyncRes::s_dot_to_port_853 && ip.getPort() == 853;
ea634573 396
c1d73d94 397 pw.getHeader()->rd=sendRDQuery;
4898a348 398 pw.getHeader()->id=qid;
5a7d2a18
PL
399 /* RFC 6840 section 5.9:
400 * This document further specifies that validating resolvers SHOULD set
401 * the CD bit on every upstream query. This is regardless of whether
402 * the CD bit was set on the incoming query [...]
403 *
404 * sendRDQuery is only true if the qname is part of a forward-zone-recurse (or
405 * set in the forward-zone-file), so we use this as an indicator for it being
406 * an "upstream query". To stay true to "dnssec=off means 3.X behaviour", we
407 * only set +CD on forwarded query in any mode other than dnssec=off.
408 */
e7b18884 409 pw.getHeader()->cd=(sendRDQuery && g_dnssecmode != DNSSECMode::Off);
5a7d2a18 410
81883dcc 411 string ping;
7bb598a0 412 bool weWantEDNSSubnet=false;
30d4402d
RG
413 uint8_t outgoingECSBits = 0;
414 ComboAddress outgoingECSAddr;
fe61f5d8 415 if(EDNS0Level > 0) {
81883dcc 416 DNSPacketWriter::optvect_t opts;
376effcf 417 if(srcmask) {
418 EDNSSubnetOpts eo;
419 eo.source = *srcmask;
30d4402d
RG
420 outgoingECSBits = srcmask->getBits();
421 outgoingECSAddr = srcmask->getNetwork();
bf4ab707 422 // cout<<"Adding request mask: "<<eo.source.toString()<<endl;
e32a8d46 423 opts.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(eo));
7bb598a0 424 weWantEDNSSubnet=true;
376effcf 425 }
93d4a890 426
fcf47f49 427 if (dnsOverTLS && g_paddingOutgoing) {
1050a5c8
OM
428 addPadding(pw, bufsize, opts);
429 }
430
431 pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts);
2188dcc3
BH
432 pw.commit();
433 }
81883dcc 434 lwr->d_rcode = 0;
81883dcc 435 lwr->d_haveEDNS = false;
308f4c43 436 LWResult::Result ret;
eefd15f9
BH
437
438 DTime dt;
4c4765c1 439 dt.set();
440 *now=dt.getTimeval();
4898a348 441
4898a348
RG
442 boost::uuids::uuid uuid;
443 const struct timeval queryTime = *now;
444
b773359c 445 if (outgoingLoggers) {
d61aa945 446 uuid = getUniqueID();
cffd3a17 447 logOutgoingQuery(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, vpacket.size(), srcmask);
4898a348 448 }
00b3e94a 449
82c0899c
O
450 srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0
451
452 // We only store the localip if needed for fstrm logging
453 ComboAddress localip;
bc82867a 454#ifdef HAVE_FSTRM
82c0899c
O
455 bool fstrmQEnabled = false;
456 bool fstrmREnabled = false;
5a00d3a3 457
573f4ff0 458 if (isEnabledForQueries(fstrmLoggers)) {
82c0899c 459 fstrmQEnabled = true;
b9fa43e0 460 }
82c0899c
O
461 if (isEnabledForResponses(fstrmLoggers)) {
462 fstrmREnabled = true;
463 }
464#endif
0ff13512 465
5c633640 466 if(!doTCP) {
4ef015cd 467 int queryfd;
308f4c43 468 if (ip.sin4.sin_family==AF_INET6) {
7d3d2f4f 469 t_Counters.at(rec::Counter::ipv6queries)++;
308f4c43
RG
470 }
471
82c0899c 472 ret = asendto((const char*)&*vpacket.begin(), vpacket.size(), 0, ip, qid, domain, type, &queryfd);
996c89cc 473
308f4c43
RG
474 if (ret != LWResult::Result::Success) {
475 return ret;
5c633640 476 }
deca7d8f
RG
477
478 if (queryfd == -1) {
479 *chained = true;
480 }
481
82c0899c
O
482#ifdef HAVE_FSTRM
483 if (!*chained) {
484 if (fstrmQEnabled || fstrmREnabled) {
485 localip.sin4.sin_family = ip.sin4.sin_family;
486 socklen_t slen = ip.getSocklen();
487 getsockname(queryfd, reinterpret_cast<sockaddr*>(&localip), &slen);
488 }
489 if (fstrmQEnabled) {
46314dcf 490 logFstreamQuery(fstrmLoggers, queryTime, localip, ip, DnstapMessage::ProtocolType::DoUDP, context ? context->d_auth : boost::none, vpacket);
82c0899c
O
491 }
492 }
493#endif /* HAVE_FSTRM */
494
5c633640 495 // sleep until we see an answer to this, interface to mtasker
82c0899c 496 ret = arecvfrom(buf, 0, ip, &len, qid, domain, type, queryfd, now);
e14f094b 497 }
5c633640 498 else {
5db4dcaa
OM
499 bool isNew;
500 do {
501 try {
502 // If we get a new (not re-used) TCP connection that does not
503 // work, we give up. For reused connections, we assume the
504 // peer has closed it on error, so we retry. At some point we
505 // *will* get a new connection, so this loop is not endless.
8ae4f2bc 506 isNew = true; // tcpconnect() might throw for new connections. In that case, we want to break the loop, scanbuild complains here, which is a false positive afaik
086c80cd
OM
507 std::string nsName;
508 if (context && !context->d_nsName.empty()) {
509 nsName = context->d_nsName.toStringNoDot();
510 }
511 isNew = tcpconnect(*now, ip, connection, dnsOverTLS, nsName);
5db4dcaa 512 ret = tcpsendrecv(ip, connection, localip, vpacket, len, buf);
82c0899c 513#ifdef HAVE_FSTRM
5db4dcaa
OM
514 if (fstrmQEnabled) {
515 logFstreamQuery(fstrmLoggers, queryTime, localip, ip, !dnsOverTLS ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoT, context ? context->d_auth : boost::none, vpacket);
8daba80b 516 }
5db4dcaa
OM
517#endif /* HAVE_FSTRM */
518 if (ret == LWResult::Result::Success) {
519 break;
f3a69323 520 }
5db4dcaa
OM
521 connection.d_handler->close();
522 }
523 catch (const NetworkError&) {
524 ret = LWResult::Result::OSLimitError; // OS limits error
525 }
526 catch (const runtime_error&) {
527 ret = LWResult::Result::OSLimitError; // OS limits error (PermanentError is transport related)
528 }
529 } while (!isNew);
5c633640 530 }
998a4334 531
26de3092
BH
532 lwr->d_usec=dt.udiff();
533 *now=dt.getTimeval();
534
308f4c43 535 if (ret != LWResult::Result::Success) { // includes 'timeout'
57f8413e 536 if (outgoingLoggers) {
cffd3a17 537 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes);
57f8413e 538 }
263f6a5a 539 return ret;
57f8413e 540 }
e14f094b 541
78f56b38 542 buf.resize(len);
b9fa43e0
OM
543
544#ifdef HAVE_FSTRM
82c0899c 545 if (fstrmREnabled && (!*chained || doTCP)) {
46314dcf
RG
546 DnstapMessage::ProtocolType protocol = doTCP ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoUDP;
547 if (dnsOverTLS) {
548 protocol = DnstapMessage::ProtocolType::DoT;
549 }
550 logFstreamResponse(fstrmLoggers, localip, ip, protocol, context ? context->d_auth : boost::none, buf, queryTime, *now);
b9fa43e0
OM
551 }
552#endif /* HAVE_FSTRM */
553
e325f20c 554 lwr->d_records.clear();
c836dc19 555 try {
f1f85f12 556 lwr->d_tcbit=0;
2a17f6c6 557 MOADNSParser mdp(false, reinterpret_cast<const char*>(buf.data()), buf.size());
263f6a5a
BH
558 lwr->d_aabit=mdp.d_header.aa;
559 lwr->d_tcbit=mdp.d_header.tc;
560 lwr->d_rcode=mdp.d_header.rcode;
561
81883dcc 562 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
b773359c 563 if(outgoingLoggers) {
cffd3a17 564 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
4898a348 565 }
308f4c43
RG
566 lwr->d_validpacket = true;
567 return LWResult::Result::Success; // this is "success", the error is set in lwr->d_rcode
81883dcc
BH
568 }
569
e325f20c 570 if(domain != mdp.d_qname) {
c5c066bf 571 if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too
91092a9f
OM
572 SLOG(g_log<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl,
573 g_slogout->info(Logr::Notice, "Packet purporting to come from remote server contained wrong answer",
574 "server", Logging::Loggable(ip),
575 "qname", Logging::Loggable(domain),
576 "onwire", Logging::Loggable(mdp.d_qname)));
01608dca 577 }
284aa5c2 578 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
579 goto out;
580 }
f128d20d
RG
581
582 lwr->d_records.reserve(mdp.d_answers.size());
e325f20c 583 for(const auto& a : mdp.d_answers)
584 lwr->d_records.push_back(a.first);
81883dcc
BH
585
586 EDNSOpts edo;
57769f13 587 if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
81883dcc 588 lwr->d_haveEDNS = true;
376effcf 589
7bb598a0 590 if(weWantEDNSSubnet) {
591 for(const auto& opt : edo.d_options) {
30d4402d 592 if(opt.first==EDNSOptionCode::ECS) {
7bb598a0 593 EDNSSubnetOpts reso;
594 if(getEDNSSubnetOptsFromString(opt.second, &reso)) {
595 // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
fe61f5d8
RG
596 /* rfc7871 states that 0 "indicate[s] that the answer is suitable for all addresses in FAMILY",
597 so we might want to still pass the information along to be able to differentiate between
598 IPv4 and IPv6. Still I'm pretty sure it doesn't matter in real life, so let's not duplicate
599 entries in our cache. */
30d4402d
RG
600 if(reso.scope.getBits()) {
601 uint8_t bits = std::min(reso.scope.getBits(), outgoingECSBits);
602 outgoingECSAddr.truncate(bits);
603 srcmask = Netmask(outgoingECSAddr, bits);
604 }
7bb598a0 605 }
606 }
607 }
376effcf 608 }
81883dcc
BH
609 }
610
b773359c 611 if(outgoingLoggers) {
cffd3a17 612 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
4898a348 613 }
8daba80b 614
308f4c43
RG
615 lwr->d_validpacket = true;
616 return LWResult::Result::Success;
c836dc19 617 }
308f4c43
RG
618 catch (const std::exception &mde) {
619 if (::arg().mustDo("log-common-errors")) {
91092a9f
OM
620 SLOG(g_log<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl,
621 g_slogout->error(Logr::Notice, mde.what(), "Unable to parse packet from remote server", "server", Logging::Loggable(ip),
622 "exception", Logging::Loggable("std::exception")));
308f4c43
RG
623 }
624
81883dcc 625 lwr->d_rcode = RCode::FormErr;
308f4c43 626 lwr->d_validpacket = false;
7d3d2f4f 627 t_Counters.at(rec::Counter::serverParseError)++;
308f4c43 628
b773359c 629 if(outgoingLoggers) {
cffd3a17 630 logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
4898a348 631 }
308f4c43
RG
632
633 return LWResult::Result::Success; // success - oddly enough
aab4adb0 634 }
308f4c43 635 catch (...) {
91092a9f
OM
636 SLOG(g_log<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl,
637 g_slogout->info(Logr::Notice, "Unknown error parsing packet from remote server", "server", Logging::Loggable(ip)));
c836dc19 638 }
91092a9f 639
7d3d2f4f 640 t_Counters.at(rec::Counter::serverParseError)++;
91092a9f 641
2353fffa 642 out:
308f4c43 643 if (!lwr->d_rcode) {
81883dcc 644 lwr->d_rcode=RCode::ServFail;
308f4c43 645 }
263f6a5a 646
308f4c43 647 return LWResult::Result::PermanentError;
e14f094b
BH
648}
649
8daba80b
O
650LWResult::Result 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::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstrmLoggers, const std::set<uint16_t>& exportTypes, LWResult *lwr, bool* chained)
651{
652 TCPOutConnectionManager::Connection connection;
f3a69323 653 auto ret = asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNS0Level, now, srcmask, context, outgoingLoggers, fstrmLoggers, exportTypes, lwr, chained, connection);
8daba80b
O
654
655 if (doTCP) {
8daba80b 656 if (connection.d_handler && lwr->d_validpacket) {
2a863502 657 t_tcp_manager.store(*now, ip, std::move(connection));
8daba80b
O
658 }
659 }
660 return ret;
661}
662