#include "UnboundDomainNameResolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Swift { class UnboundDomainNameServiceQuery : public DomainNameServiceQuery { public: UnboundDomainNameServiceQuery(TimerFactory* timerFactory, const std::string& name) : timerFactory(timerFactory), name(name), ubContext(0) { } virtual ~UnboundDomainNameServiceQuery() { if (ubContext) { ub_ctx_delete(ubContext); } } static void unbound_service_callback(void* data, int err, struct ub_result* result) { UnboundDomainNameServiceQuery* query = static_cast(data); query->handleResult(err, result); } virtual void run() { int retval; /* create context */ ubContext = ub_ctx_create(); if(!ubContext) { SWIFT_LOG(debug) << "could not create unbound context" << std::endl; return; } ub_ctx_async(ubContext, true); retval = ub_resolve_async(ubContext, const_cast(name.c_str()), LDNS_RR_TYPE_SRV, 1 /* CLASS IN (internet) */, this, unbound_service_callback, NULL); if(retval != 0) { SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; } timer = timerFactory->createTimer(500); timer->onTick.connect(boost::bind(&UnboundDomainNameServiceQuery::processData, this)); timer->start(); } void processData() { if (ub_poll(ubContext)) { int ret = ub_process(ubContext); if(ret != 0) { SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; } } else { timer->start(); } } void handleResult(int err, struct ub_result* result) { std::vector serviceRecords; if(err != 0) { SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; } else { if(result->havedata) { ldns_pkt* replyPacket = 0; ldns_buffer* buffer = ldns_buffer_new(1024); if (buffer && ldns_wire2pkt(&replyPacket, static_cast(result->answer_packet), result->answer_len) == LDNS_STATUS_OK) { ldns_rr_list* rrList = ldns_pkt_answer(replyPacket); for (size_t n = 0; n < ldns_rr_list_rr_count(rrList); n++) { ldns_rr* rr = ldns_rr_list_rr(rrList, n); if ((ldns_rr_get_type(rr) != LDNS_RR_TYPE_SRV) || (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) || (ldns_rr_rd_count(rr) != 4)) { continue; } DomainNameServiceQuery::Result serviceRecord; serviceRecord.priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); serviceRecord.weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1)); serviceRecord.port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2)); ldns_buffer_rewind(buffer); if ((ldns_rdf2buffer_str_dname(buffer, ldns_rr_rdf(rr, 3)) != LDNS_STATUS_OK) || (ldns_buffer_position(buffer) < 2) || !ldns_buffer_reserve(buffer, 1)) { // either name invalid, empty or buffer to small continue; } char terminator = 0; ldns_buffer_write(buffer, &terminator, sizeof(terminator)); serviceRecord.hostname = std::string(reinterpret_cast(ldns_buffer_at(buffer, 0))); serviceRecords.push_back(serviceRecord); SWIFT_LOG(debug) << "hostname " << serviceRecord.hostname << " added" << std::endl; } } if (replyPacket) ldns_pkt_free(replyPacket); if (buffer) ldns_buffer_free(buffer); } } ub_resolve_free(result); onResult(serviceRecords); } private: TimerFactory* timerFactory; Timer::ref timer; std::string name; ub_ctx* ubContext; }; class UnboundDomainNameAddressQuery : public DomainNameAddressQuery { public: UnboundDomainNameAddressQuery(TimerFactory* timerFactory, const std::string& name) : timerFactory(timerFactory), name(name), ubContext(0) { } virtual ~UnboundDomainNameAddressQuery() { if (ubContext) { ub_ctx_delete(ubContext); } } static void unbound_address_callback(void* data, int err, struct ub_result* result) { UnboundDomainNameAddressQuery* query = static_cast(data); query->handleResult(err, result); } virtual void run() { int retval; /* create context */ ubContext = ub_ctx_create(); if(!ubContext) { SWIFT_LOG(debug) << "could not create unbound context" << std::endl; return; } ub_ctx_async(ubContext, true); retval = ub_resolve_async(ubContext, const_cast(name.c_str()), LDNS_RR_TYPE_A, 1 /* CLASS IN (internet) */, this, unbound_address_callback, NULL); if(retval != 0) { SWIFT_LOG(debug) << "resolve error: " << ub_strerror(retval) << std::endl; } timer = timerFactory->createTimer(500); timer->onTick.connect(boost::bind(&UnboundDomainNameAddressQuery::processData, this)); timer->start(); } void processData() { if (ub_poll(ubContext)) { int ret = ub_process(ubContext); if(ret != 0) { SWIFT_LOG(debug) << "resolve error: " << ub_strerror(ret) << std::endl; } } else { timer->start(); } } void handleResult(int err, struct ub_result* result) { std::vector addresses; boost::optional error; if(err != 0) { SWIFT_LOG(debug) << "resolve error: " << ub_strerror(err) << std::endl; error = DomainNameResolveError(); } else { if(result->havedata) { for(int i=0; result->data[i]; i++) { addresses.push_back(HostAddress(std::string(inet_ntoa(* (struct in_addr*)result->data[i])))); } } } ub_resolve_free(result); onResult(addresses, error); } private: TimerFactory* timerFactory; Timer::ref timer; std::string name; ub_ctx* ubContext; }; UnboundDomainNameResolver::UnboundDomainNameResolver(EventLoop* eventLoop, TimerFactory* timerFactory) : eventLoop(eventLoop), timerFactory(timerFactory) { } UnboundDomainNameResolver::~UnboundDomainNameResolver() { } boost::shared_ptr UnboundDomainNameResolver::createServiceQuery(const std::string& name) { return boost::make_shared(timerFactory, name); } boost::shared_ptr UnboundDomainNameResolver::createAddressQuery(const std::string& name) { return boost::make_shared(timerFactory, name); } }