#include "StdAfx.h" #include "dns_store.h" #include "global/util.h" #include "rpc/rpc_manager.h" #include "nslookup.h" ////////////////////////////////////////////////////////////////////////// domain_info::domain_info(nslookup& ns, const char* domain) : ns_(ns) { ACL_SAFE_STRNCPY(domain_, domain, sizeof(domain_)); } domain_info::~domain_info() { std::vector::iterator it = ip_list_.begin(); for (; it != ip_list_.end(); ++it) acl_myfree(*it); } void domain_info::add_ip(const char* ip, int ttl) { IP_INFO* info = (IP_INFO*) acl_mycalloc(1, sizeof(IP_INFO)); ACL_SAFE_STRNCPY(info->ip, ip, sizeof(info->ip)); info->ttl = ttl; ip_list_.push_back(info); } void domain_info::set_begin() { gettimeofday(&begin_, NULL); } void domain_info::set_end() { gettimeofday(&end_, NULL); } double domain_info::get_spent() const { return util::stamp_sub(&end_, &begin_); } ////////////////////////////////////////////////////////////////////////// nslookup::nslookup(const char* filepath, nslookup_callback* callback, const char* dns_ip, int dns_port, int timeout) : filepath_(filepath) , callback_(callback) , dns_ip_(dns_ip) , dns_port_(dns_port) , timeout_(timeout) , nresult_(0) , domain_list_(NULL) { } nslookup::~nslookup() { if (domain_list_) delete domain_list_; } ////////////////////////////////////////////////////////////////////////// // 主线程运行 void nslookup::rpc_onover() { callback_->nslookup_report(domain_list_->size(), domain_list_->size()); // 将结果存入数据库,同时将回调接口传入 dns_store* ds = new dns_store(domain_list_, *callback_); // 因为该变量已经被接管,所以此处需要置空以免被重复释放 domain_list_ = NULL; rpc_manager::get_instance().fork(ds); delete this; } void nslookup::rpc_wakeup(void*) { callback_->nslookup_report(domain_list_->size(), nresult_); } ////////////////////////////////////////////////////////////////////////// // 子线程运行 void nslookup::rpc_run() { if (load_file() == true) lookup_all(); } bool nslookup::load_file() { acl::ifstream in; if (in.open_read(filepath_) == false) { logger_error("open file(%s) failed: %s", filepath_.c_str(), acl::last_serror()); return false; } domain_list_ = new std::vector; acl::string line; while (in.eof() == false) { if (in.gets(line) == false) break; domain_info* di = new domain_info(*this, line.c_str()); domain_list_->push_back(di); } if (domain_list_->empty()) { logger_error("no ip in file %s", filepath_.c_str()); return false; } return true; } void nslookup::lookup_all() { if (domain_list_ == NULL || domain_list_->empty()) { logger_error("domain empty"); return; } ACL_AIO *aio; /* 创建非阻塞异步通信句柄 */ aio = acl_aio_create(ACL_EVENT_SELECT); // acl_aio_set_keep_read(aio, 0); // 创建 DNS 查询句柄 ACL_DNS* dns = acl_dns_create(aio, timeout_); acl_dns_add_dns(dns, dns_ip_.c_str(), dns_port_, 24); rpc_signal(NULL); time_t last_signal = time(NULL), t; // 添加目标 domain 地址 std::vector::iterator it = domain_list_->begin(); for (; it != domain_list_->end(); ++it) { (*it)->set_begin(); acl_dns_lookup(dns, (*it)->get_domain(), dns_result, *it); } while (1) { /* 异步事件循环过程 */ acl_aio_loop(aio); // 如果所有查询过程都完成,则退出异步事件循环过程 if (nresult_ >= domain_list_->size()) { logger("DNS lookup over: %d, %d", (int) domain_list_->size(), (int) nresult_); break; } t = time(NULL); if (t - last_signal >= 1) { last_signal = t; rpc_signal(NULL); } } /* 显示域名查询结果 */ acl_dns_close(dns); /* 销毁非阻塞句柄 */ acl_aio_free(aio); } void nslookup::dns_result(ACL_DNS_DB *dns_db, void *ctx, int errnum) { domain_info* info = (domain_info*) ctx; info->set_end(); if (dns_db == NULL) { logger("ERROR: %s, domain: %s, spent: %0.2f", acl_dns_serror(errnum), info->get_domain(), info->get_spent()); info->add_ip("0.0.0.0", 0); info->get_nslookup().nresult_++; return; } ACL_ITER iter; acl::string buf; buf.format("OK, domain: %s, spent: %0.2f, ip_list: ", info->get_domain(), info->get_spent()); // 遍历该域名的所有查询结果 const ACL_HOST_INFO *hi; acl_foreach(iter, dns_db) { hi = (const ACL_HOST_INFO*) iter.data; if (iter.i > 0) buf << ", "; buf.format_append("ip=%s, ttl=%d", hi->ip, hi->ttl); info->add_ip(hi->ip, hi->ttl); } logger("%s", buf.c_str()); info->get_nslookup().nresult_++; }