/// 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,
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<IOFetchData>(new IOFetchData(
protocol, service, address, port, buff, cb, wait));
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);
}
/// 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
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
///
// 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
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_;
} 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
}
// 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()) {