summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorttuttle@chromium.org <ttuttle@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-12 05:08:06 +0000
committerttuttle@chromium.org <ttuttle@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-12 05:08:06 +0000
commite4e522d2a6bf3d977400f2eaba3682c32fcb65f9 (patch)
tree63272e4f63418325690eb6120b6f7882fe76acc7
parentd9a9d7a304657712b4d572fd0b58c24933c1bdec (diff)
downloadchromium_src-e4e522d2a6bf3d977400f2eaba3682c32fcb65f9.zip
chromium_src-e4e522d2a6bf3d977400f2eaba3682c32fcb65f9.tar.gz
chromium_src-e4e522d2a6bf3d977400f2eaba3682c32fcb65f9.tar.bz2
Add AsyncDNS.NameServersType histogram.
Add a histogram that records how many users are using Google Public DNS, other public resolver addresses, private resolver addresses, or a mix of the above for their DNS servers. BUG=350908 Review URL: https://codereview.chromium.org/187673005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@256435 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/dns/dns_config_service.cc86
-rw-r--r--net/dns/dns_config_service.h35
-rw-r--r--net/dns/dns_config_service_unittest.cc94
-rw-r--r--tools/metrics/histograms/histograms.xml26
4 files changed, 240 insertions, 1 deletions
diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc
index 6613182..bfa4b8d 100644
--- a/net/dns/dns_config_service.cc
+++ b/net/dns/dns_config_service.cc
@@ -8,9 +8,91 @@
#include "base/metrics/histogram.h"
#include "base/values.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/ip_pattern.h"
namespace net {
+NameServerClassifier::NameServerClassifier() {
+ // Google Public DNS addresses from:
+ // https://developers.google.com/speed/public-dns/docs/using
+ AddRule("8.8.8.8", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS);
+ AddRule("8.8.4.4", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS);
+ AddRule("2001:4860:4860:0:0:0:0:8888", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS),
+ AddRule("2001:4860:4860:0:0:0:0:8844", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS),
+
+ // Count localhost as private, since we don't know what upstream it uses:
+ AddRule("127.*.*.*", NAME_SERVERS_TYPE_PRIVATE);
+ AddRule("0:0:0:0:0:0:0:1", NAME_SERVERS_TYPE_PRIVATE);
+
+ // RFC 1918 private addresses:
+ AddRule("10.*.*.*", NAME_SERVERS_TYPE_PRIVATE);
+ AddRule("172.[16-31].*.*", NAME_SERVERS_TYPE_PRIVATE);
+ AddRule("192.168.*.*", NAME_SERVERS_TYPE_PRIVATE);
+
+ // IPv4 link-local addresses:
+ AddRule("169.254.*.*", NAME_SERVERS_TYPE_PRIVATE);
+
+ // IPv6 link-local addresses:
+ AddRule("fe80:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PRIVATE);
+
+ // Anything else counts as public:
+ AddRule("*.*.*.*", NAME_SERVERS_TYPE_PUBLIC);
+ AddRule("*:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PUBLIC);
+}
+
+NameServerClassifier::~NameServerClassifier() {}
+
+NameServerClassifier::NameServersType NameServerClassifier::GetNameServersType(
+ const std::vector<IPEndPoint>& nameservers) const {
+ NameServersType type = NAME_SERVERS_TYPE_NONE;
+ for (std::vector<IPEndPoint>::const_iterator it = nameservers.begin();
+ it != nameservers.end();
+ ++it) {
+ type = MergeNameServersTypes(type, GetNameServerType(it->address()));
+ }
+ return type;
+}
+
+struct NameServerClassifier::NameServerTypeRule {
+ NameServerTypeRule(const char* pattern_string, NameServersType type)
+ : type(type) {
+ bool parsed = pattern.ParsePattern(pattern_string);
+ DCHECK(parsed);
+ }
+
+ IPPattern pattern;
+ NameServersType type;
+};
+
+void NameServerClassifier::AddRule(const char* pattern_string,
+ NameServersType address_type) {
+ rules_.push_back(new NameServerTypeRule(pattern_string, address_type));
+}
+
+NameServerClassifier::NameServersType NameServerClassifier::GetNameServerType(
+ const IPAddressNumber& address) const {
+ for (ScopedVector<NameServerTypeRule>::const_iterator it = rules_.begin();
+ it != rules_.end();
+ ++it) {
+ if ((*it)->pattern.Match(address))
+ return (*it)->type;
+ }
+ NOTREACHED();
+ return NAME_SERVERS_TYPE_NONE;
+}
+
+NameServerClassifier::NameServersType
+NameServerClassifier::MergeNameServersTypes(NameServersType a,
+ NameServersType b) {
+ if (a == NAME_SERVERS_TYPE_NONE)
+ return b;
+ if (b == NAME_SERVERS_TYPE_NONE)
+ return a;
+ if (a == b)
+ return a;
+ return NAME_SERVERS_TYPE_MIXED;
+}
+
// Default values are taken from glibc resolv.h except timeout which is set to
// |kDnsTimeoutSeconds|.
DnsConfig::DnsConfig()
@@ -153,6 +235,10 @@ void DnsConfigService::OnConfigRead(const DnsConfig& config) {
base::TimeTicks::Now() - last_sent_empty_time_);
}
UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigChange", changed);
+ UMA_HISTOGRAM_ENUMERATION(
+ "AsyncDNS.NameServersType",
+ classifier_.GetNameServersType(dns_config_.nameservers),
+ NameServerClassifier::NAME_SERVERS_TYPE_MAX_VALUE);
have_config_ = true;
if (have_hosts_ || watch_failed_)
diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h
index 7386e60..bfb5785 100644
--- a/net/dns/dns_config_service.h
+++ b/net/dns/dns_config_service.h
@@ -11,6 +11,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -31,6 +32,37 @@ namespace net {
// TODO(szym): Remove code which reads timeout from system.
const unsigned kDnsTimeoutSeconds = 1;
+// Classifies nameserver address lists for histograms.
+class NET_EXPORT_PRIVATE NameServerClassifier {
+ public:
+ // This is used in a histogram (AsyncDNS.NameServersType); add new entries
+ // right before MAX_VALUE.
+ enum NameServersType {
+ NAME_SERVERS_TYPE_NONE,
+ NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS,
+ NAME_SERVERS_TYPE_PRIVATE,
+ NAME_SERVERS_TYPE_PUBLIC,
+ NAME_SERVERS_TYPE_MIXED,
+ NAME_SERVERS_TYPE_MAX_VALUE
+ };
+
+ NameServerClassifier();
+ ~NameServerClassifier();
+
+ NameServersType GetNameServersType(
+ const std::vector<net::IPEndPoint>& nameservers) const;
+
+ private:
+ struct NameServerTypeRule;
+
+ void AddRule(const char* pattern_string, NameServersType type);
+ NameServersType GetNameServerType(const IPAddressNumber& address) const;
+ static NameServersType MergeNameServersTypes(NameServersType a,
+ NameServersType b);
+
+ ScopedVector<NameServerTypeRule> rules_;
+};
+
// DnsConfig stores configuration of the system resolver.
struct NET_EXPORT_PRIVATE DnsConfig {
DnsConfig();
@@ -90,7 +122,6 @@ struct NET_EXPORT_PRIVATE DnsConfig {
bool use_local_ipv6;
};
-
// Service for reading system DNS settings, on demand or when signalled by
// internal watchers and NetworkChangeNotifier.
class NET_EXPORT_PRIVATE DnsConfigService
@@ -175,6 +206,8 @@ class NET_EXPORT_PRIVATE DnsConfigService
// Started in Invalidate*, cleared in On*Read.
base::OneShotTimer<DnsConfigService> timer_;
+ NameServerClassifier classifier_;
+
DISALLOW_COPY_AND_ASSIGN(DnsConfigService);
};
diff --git a/net/dns/dns_config_service_unittest.cc b/net/dns/dns_config_service_unittest.cc
index f420680..e71baef 100644
--- a/net/dns/dns_config_service_unittest.cc
+++ b/net/dns/dns_config_service_unittest.cc
@@ -9,13 +9,107 @@
#include "base/cancelable_callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_split.h"
#include "base/test/test_timeouts.h"
+#include "net/base/net_util.h"
+#include "net/dns/dns_protocol.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
+const NameServerClassifier::NameServersType kNone =
+ NameServerClassifier::NAME_SERVERS_TYPE_NONE;
+const NameServerClassifier::NameServersType kGoogle =
+ NameServerClassifier::NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS;
+const NameServerClassifier::NameServersType kPrivate =
+ NameServerClassifier::NAME_SERVERS_TYPE_PRIVATE;
+const NameServerClassifier::NameServersType kPublic =
+ NameServerClassifier::NAME_SERVERS_TYPE_PUBLIC;
+const NameServerClassifier::NameServersType kMixed =
+ NameServerClassifier::NAME_SERVERS_TYPE_MIXED;
+
+class NameServerClassifierTest : public testing::Test {
+ protected:
+ NameServerClassifier::NameServersType Classify(
+ const std::string& servers_string) {
+ std::vector<std::string> server_strings;
+ base::SplitString(servers_string, ' ', &server_strings);
+
+ std::vector<IPEndPoint> servers;
+ for (std::vector<std::string>::const_iterator it = server_strings.begin();
+ it != server_strings.end();
+ ++it) {
+ if (*it == "")
+ continue;
+
+ IPAddressNumber address;
+ bool parsed = ParseIPLiteralToNumber(*it, &address);
+ EXPECT_TRUE(parsed);
+ servers.push_back(IPEndPoint(address, dns_protocol::kDefaultPort));
+ }
+
+ return classifier_.GetNameServersType(servers);
+ }
+
+ private:
+ NameServerClassifier classifier_;
+};
+
+TEST_F(NameServerClassifierTest, None) {
+ EXPECT_EQ(kNone, Classify(""));
+}
+
+TEST_F(NameServerClassifierTest, Google) {
+ EXPECT_EQ(kGoogle, Classify("8.8.8.8"));
+ EXPECT_EQ(kGoogle, Classify("8.8.8.8 8.8.4.4"));
+ EXPECT_EQ(kGoogle, Classify("2001:4860:4860::8888"));
+ EXPECT_EQ(kGoogle, Classify("2001:4860:4860::8888 2001:4860:4860::8844"));
+ EXPECT_EQ(kGoogle, Classify("2001:4860:4860::8888 8.8.8.8"));
+
+ // Make sure nobody took any shortcuts on the IP matching:
+ EXPECT_EQ(kPublic, Classify("8.8.8.4"));
+ EXPECT_EQ(kPublic, Classify("8.8.4.8"));
+ EXPECT_EQ(kPublic, Classify("2001:4860:4860::8884"));
+ EXPECT_EQ(kPublic, Classify("2001:4860:4860::8848"));
+ EXPECT_EQ(kPublic, Classify("2001:4860:4860::1:8888"));
+ EXPECT_EQ(kPublic, Classify("2001:4860:4860:1::8888"));
+}
+
+TEST_F(NameServerClassifierTest, PrivateLocalhost) {
+ EXPECT_EQ(kPrivate, Classify("127.0.0.1"));
+ EXPECT_EQ(kPrivate, Classify("::1"));
+}
+
+TEST_F(NameServerClassifierTest, PrivateRfc1918) {
+ EXPECT_EQ(kPrivate, Classify("10.0.0.0 10.255.255.255"));
+ EXPECT_EQ(kPrivate, Classify("172.16.0.0 172.31.255.255"));
+ EXPECT_EQ(kPrivate, Classify("192.168.0.0 192.168.255.255"));
+ EXPECT_EQ(kPrivate, Classify("10.1.1.1 172.16.1.1 192.168.1.1"));
+}
+
+TEST_F(NameServerClassifierTest, PrivateIPv4LinkLocal) {
+ EXPECT_EQ(kPrivate, Classify("169.254.0.0 169.254.255.255"));
+}
+
+TEST_F(NameServerClassifierTest, PrivateIPv6LinkLocal) {
+ EXPECT_EQ(kPrivate,
+ Classify("fe80:: fe80:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+}
+
+TEST_F(NameServerClassifierTest, Public) {
+ EXPECT_EQ(kPublic, Classify("4.2.2.1"));
+ EXPECT_EQ(kPublic, Classify("4.2.2.1 4.2.2.2"));
+}
+
+TEST_F(NameServerClassifierTest, Mixed) {
+ EXPECT_EQ(kMixed, Classify("8.8.8.8 192.168.1.1"));
+ EXPECT_EQ(kMixed, Classify("8.8.8.8 4.2.2.1"));
+ EXPECT_EQ(kMixed, Classify("192.168.1.1 4.2.2.1"));
+ EXPECT_EQ(kMixed, Classify("8.8.8.8 192.168.1.1 4.2.2.1"));
+}
+
class DnsConfigServiceTest : public testing::Test {
public:
void OnConfigChanged(const DnsConfig& config) {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b9ba671..75db949 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -732,6 +732,13 @@ other types of suffix sets.
</summary>
</histogram>
+<histogram name="AsyncDNS.NameServersType" enum="AsyncDNSNameServersType">
+ <summary>
+ Type of nameservers in the DNS config, recorded each time the config is read
+ by the DNSConfigService.
+ </summary>
+</histogram>
+
<histogram name="AsyncDNS.ParseToAddressList" enum="AsyncDNSParseResult">
<summary>
Counts of results of parsing addresses out of DNS responses in successful
@@ -24796,6 +24803,25 @@ other types of suffix sets.
<int value="4" label="BAD_ADDRESS"/>
</enum>
+<enum name="AsyncDNSNameServersType" type="int">
+ <summary>Type of nameservers in the DNS config.</summary>
+ <int value="0" label="NONE">No nameservers configured.</int>
+ <int value="1" label="GOOGLE_PUBLIC_DNS">
+ All nameservers are Google Public DNS servers.
+ </int>
+ <int value="2" label="PUBLIC">
+ All nameservers have public IP addresses (and aren't Google Public DNS
+ servers).
+ </int>
+ <int value="3" label="PRIVATE">
+ All nameservers have private IP addresses (loopback, link-local, or RFC
+ 1918).
+ </int>
+ <int value="4" label="MIXED">
+ Nameservers are a mix of types (Google Public DNS, public, private).
+ </int>
+</enum>
+
<enum name="AsyncDNSParseResult" type="int">
<summary>Results of DnsResponse::ParseToAddressList.</summary>
<int value="0" label="SUCCESS"/>