From: Dima Volodin Date: Tue, 13 Dec 2011 13:49:26 +0000 (-0500) Subject: [1386] EDNS fallback on FORMERR X-Git-Tag: perftcpdns_before_epoll~5^2~10^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e3c35e75141468ab84fc07ea16d6665ef3fab784;p=thirdparty%2Fkea.git [1386] EDNS fallback on FORMERR --- diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc index 8a91982076..25ec9558c4 100644 --- a/src/lib/asiodns/io_fetch.cc +++ b/src/lib/asiodns/io_fetch.cc @@ -175,12 +175,12 @@ struct IOFetchData { /// IOFetch Constructor - just initialize the private data IOFetch::IOFetch(Protocol protocol, IOService& service, - const isc::dns::Question& question, const IOAddress& address, uint16_t port, - OutputBufferPtr& buff, Callback* cb, int wait) + const isc::dns::Question& question, const IOAddress& address, + uint16_t port, OutputBufferPtr& buff, Callback* cb, int wait, bool edns) { MessagePtr query_msg(new Message(Message::RENDER)); initIOFetch(query_msg, protocol, service, question, address, port, buff, - cb, wait); + cb, wait, edns); } IOFetch::IOFetch(Protocol protocol, IOService& service, @@ -214,7 +214,7 @@ void IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& service, const isc::dns::Question& question, const IOAddress& address, uint16_t port, - OutputBufferPtr& buff, Callback* cb, int wait) + OutputBufferPtr& buff, Callback* cb, int wait, bool edns) { data_ = boost::shared_ptr(new IOFetchData( protocol, service, address, port, buff, cb, wait)); @@ -224,9 +224,13 @@ IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& servic query_msg->setRcode(Rcode::NOERROR()); query_msg->setHeaderFlag(Message::HEADERFLAG_RD); query_msg->addQuestion(question); - EDNSPtr edns_query(new EDNS()); - edns_query->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE); - query_msg->setEDNS(edns_query); + + if (edns) { + EDNSPtr edns_query(new EDNS()); + edns_query->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE); + query_msg->setEDNS(edns_query); + } + MessageRenderer renderer(*data_->msgbuf); query_msg->toWire(renderer); } diff --git a/src/lib/asiodns/io_fetch.h b/src/lib/asiodns/io_fetch.h index 9626ffe979..5383bd465a 100644 --- a/src/lib/asiodns/io_fetch.h +++ b/src/lib/asiodns/io_fetch.h @@ -131,11 +131,14 @@ public: /// and deleting it if necessary. /// \param wait Timeout for the fetch (in ms). The default value of /// -1 indicates no timeout. + /// \param edns true if the request should be EDNS. The default value is + /// true. IOFetch(Protocol protocol, isc::asiolink::IOService& service, const isc::dns::Question& question, const isc::asiolink::IOAddress& address, uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb, - int wait = -1); + int wait = -1, + bool edns = true); /// \brief Constructor /// This constructor has one parameter "query_message", which @@ -206,7 +209,8 @@ private: void initIOFetch(isc::dns::MessagePtr& query_message, Protocol protocol, isc::asiolink::IOService& service, const isc::dns::Question& question, const isc::asiolink::IOAddress& address, uint16_t port, - isc::util::OutputBufferPtr& buff, Callback* cb, int wait); + isc::util::OutputBufferPtr& buff, Callback* cb, int wait, + bool edns = true); /// \brief Log I/O Failure /// diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc index 1855f7ae9b..e6881c495e 100644 --- a/src/lib/resolve/recursive_query.cc +++ b/src/lib/resolve/recursive_query.cc @@ -229,6 +229,9 @@ private: // case of a TCP packet being returned with the TC bit set. IOFetch::Protocol protocol_; + // EDNS flag + bool edns_; + // To prevent both unreasonably long cname chains and cname loops, // we simply keep a counter of the number of CNAMEs we have // followed so far (and error if it exceeds RESOLVER_MAX_CNAME_CHAIN @@ -358,17 +361,19 @@ private: IOFetch query(protocol_, io_, question_, current_ns_address.getAddress(), 53, buffer_, this, - query_timeout_); + query_timeout_, edns_); io_.get_io_service().post(query); } } // 'general' send, ask the NSAS to give us an address. - void send(IOFetch::Protocol protocol = IOFetch::UDP) { + void send(IOFetch::Protocol protocol = IOFetch::UDP, bool edns = true) { protocol_ = protocol; // Store protocol being used for this + edns_ = edns; if (test_server_.second != 0) { // Send query to test server - LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM) + LOG_DEBUG(isc::resolve::logger, + RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM) .arg(questionText(question_)).arg(test_server_.first); gettimeofday(¤t_ns_qsent_time, NULL); ++outstanding_events_; @@ -381,8 +386,9 @@ private: } else { // Ask the NSAS for an address for the current zone, // the callback will call the actual sendTo() - LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP) - .arg(cur_zone_); + LOG_DEBUG(isc::resolve::logger, + RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP) + .arg(cur_zone_); // Can we have multiple calls to nsas_out? Let's assume not // for now @@ -544,10 +550,30 @@ private: } // Was a TCP query so we have received a packet over TCP with the - // TC bit set: report an error by dropping down to the common + // TC bit set: report an error by going to the common // error code. + goto SERVFAIL; + + case isc::resolve::ResponseClassifier::RCODE: + // see if it's a FORMERR and a potential EDNS problem + if (incoming.getRcode() == Rcode::FORMERR()) { + if (protocol_ == IOFetch::UDP && edns_) { + // try EDNS over TCP + send(IOFetch::TCP, true); + return (false); + } else if (protocol_ == IOFetch::TCP && edns_) { + // try UDP, no EDNS + send(IOFetch::UDP, false); + return (false); + } + // TC should take care of non-EDNS over UDP, fall through to + // SERVFAIL if we get FORMERR instead + } + goto SERVFAIL; + default: +SERVFAIL: // Some error in received packet it. Report it and return SERVFAIL // to the caller. if (logger.isDebugEnabled()) {