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