Loading DnsTlsDispatcher.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -146,7 +146,7 @@ DnsTlsTransport::Response DnsTlsDispatcher::query(const std::list<DnsTlsServer>& DnsTlsTransport::Response DnsTlsDispatcher::query(const DnsTlsServer& server, unsigned mark, const Slice query, const Slice ans, int* resplen, bool* connectTriggered) { uint32_t connectCounter; int connectCounter; const Key key = std::make_pair(mark, server); Transport* xport; { Loading DnsTlsTransport.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ std::future<DnsTlsTransport::Result> DnsTlsTransport::query(const netdutils::Sli return std::move(record->result); } uint32_t DnsTlsTransport::getConnectCounter() const { int DnsTlsTransport::getConnectCounter() const { std::lock_guard guard(mLock); return mConnectCounter; } Loading DnsTlsTransport.h +2 −2 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ class DnsTlsTransport : public IDnsTlsSocketObserver { // on networks where it doesn't actually work. static bool validate(const DnsTlsServer& server, unsigned netid, uint32_t mark); uint32_t getConnectCounter() const EXCLUDES(mLock); int getConnectCounter() const EXCLUDES(mLock); // Implement IDnsTlsSocketObserver void onResponse(std::vector<uint8_t> response) override; Loading Loading @@ -89,7 +89,7 @@ class DnsTlsTransport : public IDnsTlsSocketObserver { bool sendQuery(const DnsTlsQueryMap::Query q) REQUIRES(mLock); // The number of times an attempt to connect the nameserver. uint32_t mConnectCounter GUARDED_BY(mLock) = 0; int mConnectCounter GUARDED_BY(mLock) = 0; }; } // end of namespace net Loading resolv_tls_unit_test.cpp +16 −17 Original line number Diff line number Diff line Loading @@ -148,7 +148,7 @@ TEST_F(TransportTest, Query) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Fake Socket that echoes the observed query ID as the response body. Loading Loading @@ -189,7 +189,7 @@ TEST_F(TransportTest, IdReuse) { // after each use. EXPECT_EQ(0, (r.response[2] << 8) | r.response[3]); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // These queries might be handled in serial or parallel as they race the Loading @@ -209,7 +209,7 @@ TEST_F(TransportTest, RacingQueries_10000) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // A server that waits until sDelay queries are queued before responding. Loading Loading @@ -275,7 +275,7 @@ TEST_F(TransportTest, ParallelColliding) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ParallelColliding_Max) { Loading @@ -295,7 +295,7 @@ TEST_F(TransportTest, ParallelColliding_Max) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ParallelUnique) { Loading @@ -315,7 +315,7 @@ TEST_F(TransportTest, ParallelUnique) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ParallelUnique_Max) { Loading @@ -337,7 +337,7 @@ TEST_F(TransportTest, ParallelUnique_Max) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, IdExhaustion) { Loading Loading @@ -365,7 +365,7 @@ TEST_F(TransportTest, IdExhaustion) { EXPECT_EQ(std::future_status::timeout, result.wait_for(std::chrono::duration<int>::zero())); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Responses can come back from the server in any order. This should have no Loading @@ -387,7 +387,7 @@ TEST_F(TransportTest, ReverseOrder) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ReverseOrder_Max) { Loading @@ -407,7 +407,7 @@ TEST_F(TransportTest, ReverseOrder_Max) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Returning null from the factory indicates a connection failure. Loading @@ -430,7 +430,7 @@ TEST_F(TransportTest, ConnectFail) { EXPECT_EQ(DnsTlsTransport::Response::network_error, r.code); EXPECT_TRUE(r.response.empty()); EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Simulate a socket that connects but then immediately receives a server Loading Loading @@ -458,7 +458,7 @@ TEST_F(TransportTest, CloseRetryFail) { EXPECT_TRUE(r.response.empty()); // Reconnections are triggered since DnsTlsQueryMap is not empty. EXPECT_EQ(transport.getConnectCounter(), static_cast<uint32_t>(DnsTlsQueryMap::kMaxTries)); EXPECT_EQ(transport.getConnectCounter(), DnsTlsQueryMap::kMaxTries); } // Simulate a server that occasionally closes the connection and silently Loading Loading @@ -553,7 +553,7 @@ TEST_F(TransportTest, SilentDrop) { } // Reconnections are triggered since DnsTlsQueryMap is not empty. EXPECT_EQ(transport.getConnectCounter(), static_cast<uint32_t>(DnsTlsQueryMap::kMaxTries)); EXPECT_EQ(transport.getConnectCounter(), DnsTlsQueryMap::kMaxTries); } TEST_F(TransportTest, PartialDrop) { Loading Loading @@ -590,7 +590,7 @@ TEST_F(TransportTest, ConnectCounter) { DnsTlsTransport transport(SERVER1, MARK, &factory); // Connecting on demand. EXPECT_EQ(transport.getConnectCounter(), 0U); EXPECT_EQ(transport.getConnectCounter(), 0); const int num_queries = 10; std::vector<std::future<DnsTlsTransport::Result>> results; Loading @@ -604,8 +604,7 @@ TEST_F(TransportTest, ConnectCounter) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); } EXPECT_EQ(transport.getConnectCounter(), static_cast<uint32_t>(num_queries / FakeSocketLimited::sLimit)); EXPECT_EQ(transport.getConnectCounter(), num_queries / FakeSocketLimited::sLimit); } // Simulate a malfunctioning server that injects extra miscellaneous Loading Loading @@ -649,7 +648,7 @@ TEST_F(TransportTest, IgnoringGarbage) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); // Don't check the response because this server is malfunctioning. } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Dispatcher tests Loading tests/dns_responder/dns_responder.cpp +79 −18 Original line number Diff line number Diff line Loading @@ -623,6 +623,15 @@ void DNSResponder::clearQueries() { queries_.clear(); } bool DNSResponder::hasOptPseudoRR(DNSHeader* header) const { if (header->additionals.empty()) return false; // OPT RR may be placed anywhere within the additional section. See RFC 6891 section 6.1.1. auto found = std::find_if(header->additionals.begin(), header->additionals.end(), [](const auto& a) { return a.rtype == ns_type::ns_t_opt; }); return found != header->additionals.end(); } void DNSResponder::requestHandler() { epoll_event evs[EPOLL_MAX_EVENTS]; while (true) { Loading Loading @@ -713,15 +722,7 @@ bool DNSResponder::handleDNSRequest(const char* buffer, ssize_t len, int protoco // Make the response. The query has been read into |header| which is used to build and return // the response as well. switch (mapping_type_) { case MappingType::DNS_HEADER: return makeResponseFromDnsHeader(&header, response, response_len); case MappingType::BINARY_PACKET: return makeResponseFromBinaryPacket(&header, response, response_len); case MappingType::ADDRESS_OR_HOSTNAME: default: return makeResponse(&header, response, response_len); } return makeResponse(&header, protocol, response, response_len); } bool DNSResponder::addAnswerRecords(const DNSQuestion& question, Loading Loading @@ -841,7 +842,66 @@ bool DNSResponder::makeErrorResponse(DNSHeader* header, ns_rcode rcode, char* re return writePacket(header, response, response_len); } bool DNSResponder::makeResponse(DNSHeader* header, char* response, size_t* response_len) const { bool DNSResponder::makeTruncatedResponse(DNSHeader* header, char* response, size_t* response_len) const { // Build a minimal response for non-EDNS response over UDP. Truncate all stub RRs in answer, // authority and additional section. EDNS response truncation has not supported here yet // because the EDNS response must have an OPT record. See RFC 6891 section 7. header->answers.clear(); header->authorities.clear(); header->additionals.clear(); header->qr = true; header->tr = true; return writePacket(header, response, response_len); } bool DNSResponder::makeResponse(DNSHeader* header, int protocol, char* response, size_t* response_len) const { char buffer[4096]; size_t buffer_len = sizeof(buffer); bool ret; switch (mapping_type_) { case MappingType::DNS_HEADER: ret = makeResponseFromDnsHeader(header, buffer, &buffer_len); break; case MappingType::BINARY_PACKET: ret = makeResponseFromBinaryPacket(header, buffer, &buffer_len); break; case MappingType::ADDRESS_OR_HOSTNAME: default: ret = makeResponseFromAddressOrHostname(header, buffer, &buffer_len); } if (!ret) return false; // Return truncated response if the built non-EDNS response size which is larger than 512 bytes // will be responded over UDP. The truncated response implementation here just simply set up // the TC bit and truncate all stub RRs in answer, authority and additional section. It is // because the resolver will retry DNS query over TCP and use the full TCP response. See also // RFC 1035 section 4.2.1 for UDP response truncation and RFC 6891 section 4.3 for EDNS larger // response size capability. // TODO: Perhaps keep the stub RRs as possible. // TODO: Perhaps truncate the EDNS based response over UDP. See also RFC 6891 section 4.3, // section 6.2.5 and section 7. if (protocol == IPPROTO_UDP && buffer_len > kMaximumUdpSize && !hasOptPseudoRR(header) /* non-EDNS */) { LOG(INFO) << "Return truncated response because original response length " << buffer_len << " is larger than " << kMaximumUdpSize << " bytes."; return makeTruncatedResponse(header, response, response_len); } if (buffer_len > *response_len) { LOG(ERROR) << "buffer overflow on line " << __LINE__; return false; } memcpy(response, buffer, buffer_len); *response_len = buffer_len; return true; } bool DNSResponder::makeResponseFromAddressOrHostname(DNSHeader* header, char* response, size_t* response_len) const { for (const DNSQuestion& question : header->questions) { if (question.qclass != ns_class::ns_c_in && question.qclass != ns_class::ns_c_any) { LOG(INFO) << "unsupported question class " << question.qclass; Loading Loading @@ -894,9 +954,9 @@ bool DNSResponder::makeResponseFromDnsHeader(DNSHeader* header, char* response, LOG(INFO) << "no mapping found for " << name << " " << dnstype2str(qtype) << ", couldn't build a response from DNSHeader mapping"; // Note that do nothing as makeResponse() if no mapping is found. It just changes the QR // flag from query (0) to response (1) in the query. Then, send the modified query back as // a response. // Note that do nothing as makeResponseFromAddressOrHostname() if no mapping is found. It // just changes the QR flag from query (0) to response (1) in the query. Then, send the // modified query back as a response. header->qr = true; } return writePacket(header, response, response_len); Loading Loading @@ -932,9 +992,9 @@ bool DNSResponder::makeResponseFromBinaryPacket(DNSHeader* header, char* respons // TODO: handle correctly. See also TODO in addAnswerRecords(). // TODO: Perhaps dump packet content to indicate which query failed. LOG(INFO) << "no mapping found, couldn't build a response from BinaryPacket mapping"; // Note that do nothing as makeResponse() if no mapping is found. It just changes the QR // flag from query (0) to response (1) in the query. Then, send the modified query back as // a response. // Note that do nothing as makeResponseFromAddressOrHostname() if no mapping is found. It // just changes the QR flag from query (0) to response (1) in the query. Then, send the // modified query back as a response. header->qr = true; return writePacket(header, response, response_len); } Loading Loading @@ -1049,8 +1109,9 @@ void DNSResponder::handleQuery(int protocol) { LOG(ERROR) << method_str << " failed for " << host_str; } // Test that the response is actually a correct DNS message. // TODO: Make DNS message test to support name compression. Or it throws a warning for // a valid DNS message with name compression while the raw packet mapping is used. // TODO: Perhaps make DNS message validation to support name compression. Or it throws // a warning for a valid DNS message with name compression while the binary packet mapping // is used. const char* response_end = response + len; DNSHeader header; const char* cur = header.read(response, response_end); Loading Loading
DnsTlsDispatcher.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -146,7 +146,7 @@ DnsTlsTransport::Response DnsTlsDispatcher::query(const std::list<DnsTlsServer>& DnsTlsTransport::Response DnsTlsDispatcher::query(const DnsTlsServer& server, unsigned mark, const Slice query, const Slice ans, int* resplen, bool* connectTriggered) { uint32_t connectCounter; int connectCounter; const Key key = std::make_pair(mark, server); Transport* xport; { Loading
DnsTlsTransport.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ std::future<DnsTlsTransport::Result> DnsTlsTransport::query(const netdutils::Sli return std::move(record->result); } uint32_t DnsTlsTransport::getConnectCounter() const { int DnsTlsTransport::getConnectCounter() const { std::lock_guard guard(mLock); return mConnectCounter; } Loading
DnsTlsTransport.h +2 −2 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ class DnsTlsTransport : public IDnsTlsSocketObserver { // on networks where it doesn't actually work. static bool validate(const DnsTlsServer& server, unsigned netid, uint32_t mark); uint32_t getConnectCounter() const EXCLUDES(mLock); int getConnectCounter() const EXCLUDES(mLock); // Implement IDnsTlsSocketObserver void onResponse(std::vector<uint8_t> response) override; Loading Loading @@ -89,7 +89,7 @@ class DnsTlsTransport : public IDnsTlsSocketObserver { bool sendQuery(const DnsTlsQueryMap::Query q) REQUIRES(mLock); // The number of times an attempt to connect the nameserver. uint32_t mConnectCounter GUARDED_BY(mLock) = 0; int mConnectCounter GUARDED_BY(mLock) = 0; }; } // end of namespace net Loading
resolv_tls_unit_test.cpp +16 −17 Original line number Diff line number Diff line Loading @@ -148,7 +148,7 @@ TEST_F(TransportTest, Query) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Fake Socket that echoes the observed query ID as the response body. Loading Loading @@ -189,7 +189,7 @@ TEST_F(TransportTest, IdReuse) { // after each use. EXPECT_EQ(0, (r.response[2] << 8) | r.response[3]); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // These queries might be handled in serial or parallel as they race the Loading @@ -209,7 +209,7 @@ TEST_F(TransportTest, RacingQueries_10000) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // A server that waits until sDelay queries are queued before responding. Loading Loading @@ -275,7 +275,7 @@ TEST_F(TransportTest, ParallelColliding) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ParallelColliding_Max) { Loading @@ -295,7 +295,7 @@ TEST_F(TransportTest, ParallelColliding_Max) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(QUERY, r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ParallelUnique) { Loading @@ -315,7 +315,7 @@ TEST_F(TransportTest, ParallelUnique) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ParallelUnique_Max) { Loading @@ -337,7 +337,7 @@ TEST_F(TransportTest, ParallelUnique_Max) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, IdExhaustion) { Loading Loading @@ -365,7 +365,7 @@ TEST_F(TransportTest, IdExhaustion) { EXPECT_EQ(std::future_status::timeout, result.wait_for(std::chrono::duration<int>::zero())); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Responses can come back from the server in any order. This should have no Loading @@ -387,7 +387,7 @@ TEST_F(TransportTest, ReverseOrder) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } TEST_F(TransportTest, ReverseOrder_Max) { Loading @@ -407,7 +407,7 @@ TEST_F(TransportTest, ReverseOrder_Max) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); EXPECT_EQ(queries[i], r.response); } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Returning null from the factory indicates a connection failure. Loading @@ -430,7 +430,7 @@ TEST_F(TransportTest, ConnectFail) { EXPECT_EQ(DnsTlsTransport::Response::network_error, r.code); EXPECT_TRUE(r.response.empty()); EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Simulate a socket that connects but then immediately receives a server Loading Loading @@ -458,7 +458,7 @@ TEST_F(TransportTest, CloseRetryFail) { EXPECT_TRUE(r.response.empty()); // Reconnections are triggered since DnsTlsQueryMap is not empty. EXPECT_EQ(transport.getConnectCounter(), static_cast<uint32_t>(DnsTlsQueryMap::kMaxTries)); EXPECT_EQ(transport.getConnectCounter(), DnsTlsQueryMap::kMaxTries); } // Simulate a server that occasionally closes the connection and silently Loading Loading @@ -553,7 +553,7 @@ TEST_F(TransportTest, SilentDrop) { } // Reconnections are triggered since DnsTlsQueryMap is not empty. EXPECT_EQ(transport.getConnectCounter(), static_cast<uint32_t>(DnsTlsQueryMap::kMaxTries)); EXPECT_EQ(transport.getConnectCounter(), DnsTlsQueryMap::kMaxTries); } TEST_F(TransportTest, PartialDrop) { Loading Loading @@ -590,7 +590,7 @@ TEST_F(TransportTest, ConnectCounter) { DnsTlsTransport transport(SERVER1, MARK, &factory); // Connecting on demand. EXPECT_EQ(transport.getConnectCounter(), 0U); EXPECT_EQ(transport.getConnectCounter(), 0); const int num_queries = 10; std::vector<std::future<DnsTlsTransport::Result>> results; Loading @@ -604,8 +604,7 @@ TEST_F(TransportTest, ConnectCounter) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); } EXPECT_EQ(transport.getConnectCounter(), static_cast<uint32_t>(num_queries / FakeSocketLimited::sLimit)); EXPECT_EQ(transport.getConnectCounter(), num_queries / FakeSocketLimited::sLimit); } // Simulate a malfunctioning server that injects extra miscellaneous Loading Loading @@ -649,7 +648,7 @@ TEST_F(TransportTest, IgnoringGarbage) { EXPECT_EQ(DnsTlsTransport::Response::success, r.code); // Don't check the response because this server is malfunctioning. } EXPECT_EQ(transport.getConnectCounter(), 1U); EXPECT_EQ(transport.getConnectCounter(), 1); } // Dispatcher tests Loading
tests/dns_responder/dns_responder.cpp +79 −18 Original line number Diff line number Diff line Loading @@ -623,6 +623,15 @@ void DNSResponder::clearQueries() { queries_.clear(); } bool DNSResponder::hasOptPseudoRR(DNSHeader* header) const { if (header->additionals.empty()) return false; // OPT RR may be placed anywhere within the additional section. See RFC 6891 section 6.1.1. auto found = std::find_if(header->additionals.begin(), header->additionals.end(), [](const auto& a) { return a.rtype == ns_type::ns_t_opt; }); return found != header->additionals.end(); } void DNSResponder::requestHandler() { epoll_event evs[EPOLL_MAX_EVENTS]; while (true) { Loading Loading @@ -713,15 +722,7 @@ bool DNSResponder::handleDNSRequest(const char* buffer, ssize_t len, int protoco // Make the response. The query has been read into |header| which is used to build and return // the response as well. switch (mapping_type_) { case MappingType::DNS_HEADER: return makeResponseFromDnsHeader(&header, response, response_len); case MappingType::BINARY_PACKET: return makeResponseFromBinaryPacket(&header, response, response_len); case MappingType::ADDRESS_OR_HOSTNAME: default: return makeResponse(&header, response, response_len); } return makeResponse(&header, protocol, response, response_len); } bool DNSResponder::addAnswerRecords(const DNSQuestion& question, Loading Loading @@ -841,7 +842,66 @@ bool DNSResponder::makeErrorResponse(DNSHeader* header, ns_rcode rcode, char* re return writePacket(header, response, response_len); } bool DNSResponder::makeResponse(DNSHeader* header, char* response, size_t* response_len) const { bool DNSResponder::makeTruncatedResponse(DNSHeader* header, char* response, size_t* response_len) const { // Build a minimal response for non-EDNS response over UDP. Truncate all stub RRs in answer, // authority and additional section. EDNS response truncation has not supported here yet // because the EDNS response must have an OPT record. See RFC 6891 section 7. header->answers.clear(); header->authorities.clear(); header->additionals.clear(); header->qr = true; header->tr = true; return writePacket(header, response, response_len); } bool DNSResponder::makeResponse(DNSHeader* header, int protocol, char* response, size_t* response_len) const { char buffer[4096]; size_t buffer_len = sizeof(buffer); bool ret; switch (mapping_type_) { case MappingType::DNS_HEADER: ret = makeResponseFromDnsHeader(header, buffer, &buffer_len); break; case MappingType::BINARY_PACKET: ret = makeResponseFromBinaryPacket(header, buffer, &buffer_len); break; case MappingType::ADDRESS_OR_HOSTNAME: default: ret = makeResponseFromAddressOrHostname(header, buffer, &buffer_len); } if (!ret) return false; // Return truncated response if the built non-EDNS response size which is larger than 512 bytes // will be responded over UDP. The truncated response implementation here just simply set up // the TC bit and truncate all stub RRs in answer, authority and additional section. It is // because the resolver will retry DNS query over TCP and use the full TCP response. See also // RFC 1035 section 4.2.1 for UDP response truncation and RFC 6891 section 4.3 for EDNS larger // response size capability. // TODO: Perhaps keep the stub RRs as possible. // TODO: Perhaps truncate the EDNS based response over UDP. See also RFC 6891 section 4.3, // section 6.2.5 and section 7. if (protocol == IPPROTO_UDP && buffer_len > kMaximumUdpSize && !hasOptPseudoRR(header) /* non-EDNS */) { LOG(INFO) << "Return truncated response because original response length " << buffer_len << " is larger than " << kMaximumUdpSize << " bytes."; return makeTruncatedResponse(header, response, response_len); } if (buffer_len > *response_len) { LOG(ERROR) << "buffer overflow on line " << __LINE__; return false; } memcpy(response, buffer, buffer_len); *response_len = buffer_len; return true; } bool DNSResponder::makeResponseFromAddressOrHostname(DNSHeader* header, char* response, size_t* response_len) const { for (const DNSQuestion& question : header->questions) { if (question.qclass != ns_class::ns_c_in && question.qclass != ns_class::ns_c_any) { LOG(INFO) << "unsupported question class " << question.qclass; Loading Loading @@ -894,9 +954,9 @@ bool DNSResponder::makeResponseFromDnsHeader(DNSHeader* header, char* response, LOG(INFO) << "no mapping found for " << name << " " << dnstype2str(qtype) << ", couldn't build a response from DNSHeader mapping"; // Note that do nothing as makeResponse() if no mapping is found. It just changes the QR // flag from query (0) to response (1) in the query. Then, send the modified query back as // a response. // Note that do nothing as makeResponseFromAddressOrHostname() if no mapping is found. It // just changes the QR flag from query (0) to response (1) in the query. Then, send the // modified query back as a response. header->qr = true; } return writePacket(header, response, response_len); Loading Loading @@ -932,9 +992,9 @@ bool DNSResponder::makeResponseFromBinaryPacket(DNSHeader* header, char* respons // TODO: handle correctly. See also TODO in addAnswerRecords(). // TODO: Perhaps dump packet content to indicate which query failed. LOG(INFO) << "no mapping found, couldn't build a response from BinaryPacket mapping"; // Note that do nothing as makeResponse() if no mapping is found. It just changes the QR // flag from query (0) to response (1) in the query. Then, send the modified query back as // a response. // Note that do nothing as makeResponseFromAddressOrHostname() if no mapping is found. It // just changes the QR flag from query (0) to response (1) in the query. Then, send the // modified query back as a response. header->qr = true; return writePacket(header, response, response_len); } Loading Loading @@ -1049,8 +1109,9 @@ void DNSResponder::handleQuery(int protocol) { LOG(ERROR) << method_str << " failed for " << host_str; } // Test that the response is actually a correct DNS message. // TODO: Make DNS message test to support name compression. Or it throws a warning for // a valid DNS message with name compression while the raw packet mapping is used. // TODO: Perhaps make DNS message validation to support name compression. Or it throws // a warning for a valid DNS message with name compression while the binary packet mapping // is used. const char* response_end = response + len; DNSHeader header; const char* cur = header.read(response, response_end); Loading