diff options
author | dcastagna@google.com <dcastagna@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-19 13:56:19 +0000 |
---|---|---|
committer | dcastagna@google.com <dcastagna@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-19 13:56:19 +0000 |
commit | 8220e5d17abd0280beccf0faead6a530ff8bb256 (patch) | |
tree | 35c4a3cb5a9fcc8665d10347c765be0687f018ec /net/tools/gdig | |
parent | a04b1f95522dcb9cb145288aa3e6c938990b7861 (diff) | |
download | chromium_src-8220e5d17abd0280beccf0faead6a530ff8bb256.zip chromium_src-8220e5d17abd0280beccf0faead6a530ff8bb256.tar.gz chromium_src-8220e5d17abd0280beccf0faead6a530ff8bb256.tar.bz2 |
Support for printing the dns configuration and hosts.
It is also possible to specify a nameserver and a timeout from the command line.
BUG=128212
TEST=build and run gdig with the parameters --print_config --print_hosts --nameserver=an_ip:a_port and --timeout=milliseconds
Review URL: https://chromiumcodereview.appspot.com/10572018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147437 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/tools/gdig')
-rw-r--r-- | net/tools/gdig/gdig.cc | 282 |
1 files changed, 208 insertions, 74 deletions
diff --git a/net/tools/gdig/gdig.cc b/net/tools/gdig/gdig.cc index eafc021..7d1c127 100644 --- a/net/tools/gdig/gdig.cc +++ b/net/tools/gdig/gdig.cc @@ -13,15 +13,18 @@ #include "base/message_loop.h" #include "base/string_number_conversions.h" #include "base/string_util.h" +#include "base/stringprintf.h" #include "base/time.h" #include "net/base/address_list.h" #include "net/base/host_cache.h" #include "net/base/host_resolver_impl.h" +#include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" #include "net/base/net_util.h" #include "net/dns/dns_client.h" #include "net/dns/dns_config_service.h" +#include "net/dns/dns_protocol.h" #include "net/tools/gdig/file_net_log.h" #if defined(OS_MACOSX) @@ -32,6 +35,64 @@ namespace net { namespace { +bool StringToIPEndPoint(const std::string& ip_address_and_port, + IPEndPoint* ip_end_point) { + DCHECK(ip_end_point); + + std::string ip; + int port; + if (!ParseHostAndPort(ip_address_and_port, &ip, &port)) + return false; + if (port == -1) + port = dns_protocol::kDefaultPort; + + net::IPAddressNumber ip_number; + if (!net::ParseIPLiteralToNumber(ip, &ip_number)) + return false; + + *ip_end_point = net::IPEndPoint(ip_number, port); + return true; +} + +// Convert DnsConfig to human readable text omitting the hosts member. +std::string DnsConfigToString(const DnsConfig& dns_config) { + std::string output; + output.append("search "); + for (size_t i = 0; i < dns_config.search.size(); ++i) { + output.append(dns_config.search[i] + " "); + } + output.append("\n"); + + for (size_t i = 0; i < dns_config.nameservers.size(); ++i) { + output.append("nameserver "); + output.append(dns_config.nameservers[i].ToString()).append("\n"); + } + + base::StringAppendF(&output, "options ndots:%d\n", dns_config.ndots); + base::StringAppendF(&output, "options timeout:%d\n", + static_cast<int>(dns_config.timeout.InMilliseconds())); + base::StringAppendF(&output, "options attempts:%d\n", dns_config.attempts); + if (dns_config.rotate) + output.append("options rotate\n"); + if (dns_config.edns0) + output.append("options edns0\n"); + return output; +} + +// Convert DnsConfig hosts member to a human readable text. +std::string DnsHostsToString(const DnsHosts& dns_hosts) { + std::string output; + for (DnsHosts::const_iterator i = dns_hosts.begin(); + i != dns_hosts.end(); + ++i) { + const DnsHostsKey& key = i->first; + std::string host_name = key.first; + output.append(IPEndPoint(i->second, -1).ToStringWithoutPort()); + output.append(" ").append(host_name).append("\n"); + } + return output; +} + class GDig { public: GDig(); @@ -41,6 +102,7 @@ class GDig { RESULT_NO_CONFIG = -2, RESULT_WRONG_USAGE = -1, RESULT_OK = 0, + RESULT_PENDING = 1, }; Result Main(int argc, const char* argv[]); @@ -49,13 +111,18 @@ class GDig { bool ParseCommandLine(int argc, const char* argv[]); void Start(); + void Finish(Result); - void OnDnsConfig(const DnsConfig& dns_config); + void OnDnsConfig(const DnsConfig& dns_config_const); void OnResolveComplete(int val); void OnTimeout(); - base::TimeDelta timeout_; + base::TimeDelta config_timeout_; std::string domain_name_; + bool print_config_; + bool print_hosts_; + net::IPEndPoint nameserver_; + base::TimeDelta timeout_; Result result_; AddressList addrlist_; @@ -67,15 +134,19 @@ class GDig { }; GDig::GDig() - : timeout_(base::TimeDelta::FromSeconds(5)), - result_(GDig::RESULT_OK) { + : config_timeout_(base::TimeDelta::FromSeconds(5)), + print_config_(false), + print_hosts_(false) { } GDig::Result GDig::Main(int argc, const char* argv[]) { if (!ParseCommandLine(argc, argv)) { fprintf(stderr, "usage: %s [--net_log[=<basic|no_bytes|all>]]" - " [--config_timeout=<seconds>] domain_name\n", + " [--print_config] [--print_hosts]" + " [--nameserver=<ip_address[:port]>]" + " [--timeout=<milliseconds>] [--config_timeout=<seconds>]" + " domain_name\n", argv[0]); return RESULT_WRONG_USAGE; } @@ -88,91 +159,27 @@ GDig::Result GDig::Main(int argc, const char* argv[]) { base::AtExitManager exit_manager; MessageLoopForIO loop; + result_ = RESULT_PENDING; Start(); - - MessageLoop::current()->Run(); + if (result_ == RESULT_PENDING) + MessageLoop::current()->Run(); // Destroy it while MessageLoopForIO is alive. dns_config_service_.reset(); return result_; } -void GDig::OnResolveComplete(int val) { - MessageLoop::current()->Quit(); - if (val != OK) { - fprintf(stderr, "Error trying to resolve hostname %s: %s\n", - domain_name_.c_str(), ErrorToString(val)); - result_ = RESULT_NO_RESOLVE; - } else { - for (size_t i = 0; i < addrlist_.size(); ++i) - printf("%s\n", addrlist_[i].ToStringWithoutPort().c_str()); - } -} - -void GDig::OnTimeout() { - MessageLoop::current()->Quit(); - fprintf(stderr, "Timed out waiting to load the dns config\n"); - result_ = RESULT_NO_CONFIG; -} - -void GDig::Start() { - dns_config_service_ = DnsConfigService::CreateSystemService(); - dns_config_service_->Read(base::Bind(&GDig::OnDnsConfig, - base::Unretained(this))); - - timeout_closure_.Reset(base::Bind(&GDig::OnTimeout, base::Unretained(this))); - - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - timeout_closure_.callback(), - timeout_); -} - -void GDig::OnDnsConfig(const DnsConfig& dns_config) { - timeout_closure_.Cancel(); - DCHECK(dns_config.IsValid()); - - scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL)); - dns_client->SetConfig(dns_config); - resolver_.reset( - new HostResolverImpl( - HostCache::CreateDefaultCache(), - PrioritizedDispatcher::Limits(NUM_PRIORITIES, 1), - HostResolverImpl::ProcTaskParams(NULL, 1), - scoped_ptr<DnsConfigService>(NULL), - dns_client.Pass(), - log_.get())); - - HostResolver::RequestInfo info(HostPortPair(domain_name_.c_str(), 80)); - - CompletionCallback callback = base::Bind(&GDig::OnResolveComplete, - base::Unretained(this)); - int ret = resolver_->Resolve( - info, &addrlist_, callback, NULL, - BoundNetLog::Make(log_.get(), net::NetLog::SOURCE_NONE)); - DCHECK(ret == ERR_IO_PENDING); -} - bool GDig::ParseCommandLine(int argc, const char* argv[]) { CommandLine::Init(argc, argv); const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); - if (parsed_command_line.GetArgs().size() != 1) - return false; - -#if defined(OS_WIN) - domain_name_ = WideToASCII(parsed_command_line.GetArgs()[0]); -#else - domain_name_ = parsed_command_line.GetArgs()[0]; -#endif - if (parsed_command_line.HasSwitch("config_timeout")) { int timeout_seconds = 0; bool parsed = base::StringToInt( parsed_command_line.GetSwitchValueASCII("config_timeout"), &timeout_seconds); if (parsed && timeout_seconds > 0) { - timeout_ = base::TimeDelta::FromSeconds(timeout_seconds); + config_timeout_ = base::TimeDelta::FromSeconds(timeout_seconds); } else { fprintf(stderr, "Invalid config_timeout parameter\n"); return false; @@ -199,7 +206,134 @@ bool GDig::ParseCommandLine(int argc, const char* argv[]) { log_.reset(new FileNetLog(stderr, level)); } - return true; + print_config_ = parsed_command_line.HasSwitch("print_config"); + print_hosts_ = parsed_command_line.HasSwitch("print_hosts"); + + if (parsed_command_line.HasSwitch("nameserver")) { + std::string nameserver = + parsed_command_line.GetSwitchValueASCII("nameserver"); + if (!StringToIPEndPoint(nameserver, &nameserver_)) { + fprintf(stderr, + "Cannot parse the namerserver string into an IPEndPoint\n"); + return false; + } + } + + if (parsed_command_line.HasSwitch("timeout")) { + int timeout_millis = 0; + bool parsed = base::StringToInt( + parsed_command_line.GetSwitchValueASCII("timeout"), + &timeout_millis); + if (parsed && timeout_millis > 0) { + timeout_ = base::TimeDelta::FromMilliseconds(timeout_millis); + } else { + fprintf(stderr, "Invalid timeout parameter\n"); + return false; + } + } + + if (parsed_command_line.GetArgs().size() == 1) { +#if defined(OS_WIN) + domain_name_ = WideToASCII(parsed_command_line.GetArgs()[0]); +#else + domain_name_ = parsed_command_line.GetArgs()[0]; +#endif + } else if (parsed_command_line.GetArgs().size() != 0) { + return false; + } + return print_config_ || print_hosts_ || domain_name_.length() > 0; +} + +void GDig::Start() { + if (nameserver_.address().size() > 0) { + DnsConfig dns_config; + dns_config.attempts = 1; + dns_config.nameservers.push_back(nameserver_); + OnDnsConfig(dns_config); + } else { + dns_config_service_ = DnsConfigService::CreateSystemService(); + dns_config_service_->Read(base::Bind(&GDig::OnDnsConfig, + base::Unretained(this))); + timeout_closure_.Reset(base::Bind(&GDig::OnTimeout, + base::Unretained(this))); + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + timeout_closure_.callback(), + config_timeout_); + } +} + +void GDig::Finish(Result result) { + DCHECK_NE(RESULT_PENDING, result); + result_ = result; + if (MessageLoop::current()) + MessageLoop::current()->Quit(); +} + +void GDig::OnDnsConfig(const DnsConfig& dns_config_const) { + timeout_closure_.Cancel(); + DCHECK(dns_config_const.IsValid()); + DnsConfig dns_config = dns_config_const; + + if (timeout_.InMilliseconds() > 0) + dns_config.timeout = timeout_; + if (print_config_) + printf("# Dns Configuration\n" + "%s", DnsConfigToString(dns_config).c_str()); + if (print_hosts_) + printf("# Host Database\n" + "%s", DnsHostsToString(dns_config.hosts).c_str()); + + // If the user didn't specify a name to resolve we can stop here. + if (domain_name_.length() == 0) { + Finish(RESULT_OK); + return; + } + + scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL)); + dns_client->SetConfig(dns_config); + resolver_.reset( + new HostResolverImpl( + HostCache::CreateDefaultCache(), + PrioritizedDispatcher::Limits(NUM_PRIORITIES, 1), + HostResolverImpl::ProcTaskParams(NULL, 1), + scoped_ptr<DnsConfigService>(NULL), + dns_client.Pass(), + log_.get())); + + HostResolver::RequestInfo info(HostPortPair(domain_name_.c_str(), 80)); + + CompletionCallback callback = base::Bind(&GDig::OnResolveComplete, + base::Unretained(this)); + int ret = resolver_->Resolve( + info, &addrlist_, callback, NULL, + BoundNetLog::Make(log_.get(), net::NetLog::SOURCE_NONE)); + switch (ret) { + case OK: + OnResolveComplete(ret); + break; + case ERR_IO_PENDING: break; + default: + Finish(RESULT_NO_RESOLVE); + fprintf(stderr, "Error calling resolve %s\n", ErrorToString(ret)); + } +} + +void GDig::OnResolveComplete(int val) { + if (val != OK) { + fprintf(stderr, "Error trying to resolve hostname %s: %s\n", + domain_name_.c_str(), ErrorToString(val)); + Finish(RESULT_NO_RESOLVE); + } else { + for (size_t i = 0; i < addrlist_.size(); ++i) + printf("%s\n", addrlist_[i].ToStringWithoutPort().c_str()); + Finish(RESULT_OK); + } +} + +void GDig::OnTimeout() { + fprintf(stderr, "Timed out waiting to load the dns config\n"); + Finish(RESULT_NO_CONFIG); } } // empty namespace |