crosdns/vm_tools: Use penguin.linux.test hostname for container

This changes the hostname for the default Crostini container to be
penguin.linux.test. It also changes the hostnames for any container to be
<container>.<vm>.linux.test.

BUG=chromium:849134,chromium:825010
TEST=Unit tests pass, verified /etc/host and Chrome connection

Change-Id: Ibee8acf994036775fed92c12cd4ffeb92f691790
Reviewed-on: https://chromium-review.googlesource.com/1112570
Commit-Ready: Jeffrey Kardatzke <jkardatzke@google.com>
Tested-by: Jeffrey Kardatzke <jkardatzke@google.com>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
diff --git a/crosdns/hosts_modifier.cc b/crosdns/hosts_modifier.cc
index 9a1459a..1ff7501 100644
--- a/crosdns/hosts_modifier.cc
+++ b/crosdns/hosts_modifier.cc
@@ -19,8 +19,7 @@
 // are restarted we know what the base file was before we modified it.
 constexpr char kFileModificationDelimeter[] =
     "\n#####DYNAMIC-CROSDNS-ENTRIES#####\n";
-constexpr char kAllowedHostnameFull[] = "linuxhost";
-constexpr char kAllowedHostnameSuffix[] = "-local";
+constexpr char kAllowedHostnameSuffix[] = ".linux.test";
 constexpr uint32_t kAllowedIpSubnet = 0x64735c00;  // 100.115.92.0
 constexpr uint32_t kAllowedIpMask = 0xFFFFFF00;
 
@@ -33,26 +32,31 @@
   return true;
 }
 
-// Hostname must be either 'linuxhost' or *-localhost and use legal chars.
+// Hostname must be *.test and use legal chars.
 bool IsAllowedHostname(const std::string& hostname, std::string* err_out) {
   // Make sure this is a legal hostname. It must be comprised of alphanumeric
-  // characters or dashes. The dash may not be the first character. It must also
-  // either match 'linuxhost' or have the '-local' suffix.
-  if (hostname != kAllowedHostnameFull &&
-      !base::EndsWith(hostname, kAllowedHostnameSuffix,
+  // characters, dashes or dots. The dot or dash may not be the first character.
+  // It may not have consecutive dots. It must also have the '.test' suffix.
+  if (!base::EndsWith(hostname, kAllowedHostnameSuffix,
                       base::CompareCase::SENSITIVE)) {
     *err_out = "Attempt to add invalid hostname to mapping of: " + hostname;
     return false;
   }
-  if (hostname[0] == '-') {
-    *err_out = "First char in hostname may not be a dash: " + hostname;
+  if (hostname[0] == '-' || hostname[0] == '.') {
+    *err_out = "First char in hostname may not be a dot or dash: " + hostname;
     return false;
   }
+  bool last_was_dot = false;
   for (auto c : hostname) {
     if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c) && c != '-') {
+      if (c == '.' && !last_was_dot) {
+        last_was_dot = true;
+        continue;
+      }
       *err_out = "Invalid char in hostname: " + hostname;
       return false;
     }
+    last_was_dot = false;
   }
   return true;
 }
diff --git a/crosdns/hosts_modifier_unittest.cc b/crosdns/hosts_modifier_unittest.cc
index d84a6fc..409bc7c 100644
--- a/crosdns/hosts_modifier_unittest.cc
+++ b/crosdns/hosts_modifier_unittest.cc
@@ -82,12 +82,12 @@
   EXPECT_TRUE(hosts_modifier()->Init(hosts_file()));
   // Valid hostname for default container.
   EXPECT_TRUE(hosts_modifier()->SetHostnameIpMapping(
-      "linuxhost", "100.115.92.24", "", &err));
+      "penguin.linux.test", "100.115.92.24", "", &err));
   // Valid hostnames for vm/container.
   EXPECT_TRUE(hosts_modifier()->SetHostnameIpMapping(
-      "foo12-local", "100.115.92.22", "", &err));
+      "foo12.linux.test", "100.115.92.22", "", &err));
   EXPECT_TRUE(hosts_modifier()->SetHostnameIpMapping(
-      "penguin-termina-local", "100.115.92.253", "", &err));
+      "penguin.termina.linux.test", "100.115.92.253", "", &err));
   // Invalid hostnames.
   EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
       "google.com", "100.115.92.24", "", &err));
@@ -95,36 +95,44 @@
       "localhost", "100.115.92.24", "", &err));
   EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
       "-foo-local", "100.115.92.24", "", &err));
+  EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
+      "foo..linux.test", "100.115.92.24", "", &err));
+  EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
+      ".linux.test", "100.115.92.24", "", &err));
+  EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
+      "linux.test", "100.115.92.24", "", &err));
   EXPECT_FALSE(
       hosts_modifier()->SetHostnameIpMapping("", "100.115.92.24", "", &err));
   // Invalid IPs.
   EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
-      "linuxhost", "100.115.91.24", "", &err));
-  EXPECT_FALSE(
-      hosts_modifier()->SetHostnameIpMapping("linuxhost", "8.8.8.8", "", &err));
+      "penguin.linux.test", "100.115.91.24", "", &err));
+  EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping("penguin.linux.test",
+                                                      "8.8.8.8", "", &err));
   EXPECT_FALSE(hosts_modifier()->SetHostnameIpMapping(
-      "linuxhost", "101.115.92.24", "", &err));
+      "penguin.linux.test", "101.115.92.24", "", &err));
   // Verify the contents of the hosts file. We are assuming an ordered map is
   // used here (which it is in the code) to make analyzing the results easier.
   std::string extra_contents = kBaseFileContents;
   extra_contents += kFileModificationDelimeter;
-  extra_contents += "100.115.92.22 foo12-local\n";
-  extra_contents += "100.115.92.24 linuxhost\n";
-  extra_contents += "100.115.92.253 penguin-termina-local\n";
+  extra_contents += "100.115.92.22 foo12.linux.test\n";
+  extra_contents += "100.115.92.24 penguin.linux.test\n";
+  extra_contents += "100.115.92.253 penguin.termina.linux.test\n";
   EXPECT_EQ(extra_contents, ReadHostsContents());
 
   // Removing an invalid hostname should fail.
   EXPECT_FALSE(hosts_modifier()->RemoveHostnameIpMapping("bar-local", &err));
   EXPECT_FALSE(hosts_modifier()->RemoveHostnameIpMapping("google.com", &err));
   // Removing a valid hostname should succeed.
-  EXPECT_TRUE(hosts_modifier()->RemoveHostnameIpMapping("linuxhost", &err));
-  EXPECT_TRUE(hosts_modifier()->RemoveHostnameIpMapping("foo12-local", &err));
+  EXPECT_TRUE(
+      hosts_modifier()->RemoveHostnameIpMapping("penguin.linux.test", &err));
+  EXPECT_TRUE(
+      hosts_modifier()->RemoveHostnameIpMapping("foo12.linux.test", &err));
 
   // Verify the contents of the hosts file again, there should be one entry
   // left.
   extra_contents = kBaseFileContents;
   extra_contents += kFileModificationDelimeter;
-  extra_contents += "100.115.92.253 penguin-termina-local\n";
+  extra_contents += "100.115.92.253 penguin.termina.linux.test\n";
   EXPECT_EQ(extra_contents, ReadHostsContents());
 }
 
diff --git a/vm_tools/cicerone/service.cc b/vm_tools/cicerone/service.cc
index e8f0a80..00b4d75 100644
--- a/vm_tools/cicerone/service.cc
+++ b/vm_tools/cicerone/service.cc
@@ -40,7 +40,7 @@
 constexpr char kDefaultContainerName[] = "penguin";
 
 // Hostname for the default VM/container.
-constexpr char kDefaultContainerHostname[] = "linuxhost";
+constexpr char kDefaultContainerHostname[] = "penguin.linux.test";
 
 // Delimiter for the end of a URL scheme.
 constexpr char kUrlSchemeDelimiter[] = "://";
@@ -385,9 +385,10 @@
 
   if (owner_id == primary_owner_id_) {
     // Register this with the hostname resolver.
-    RegisterHostname(base::StringPrintf("%s-%s-local", container_name.c_str(),
-                                        vm_name.c_str()),
-                     string_ip);
+    RegisterHostname(
+        base::StringPrintf("%s.%s.linux.test", container_name.c_str(),
+                           vm_name.c_str()),
+        string_ip);
     if (vm_name == kDefaultVmName && container_name == kDefaultContainerName) {
       RegisterHostname(kDefaultContainerHostname, string_ip);
     }
@@ -430,8 +431,8 @@
     return;
   }
   // Unregister this with the hostname resolver.
-  UnregisterHostname(base::StringPrintf("%s-%s-local", container_name.c_str(),
-                                        vm_name.c_str()));
+  UnregisterHostname(base::StringPrintf(
+      "%s.%s.linux.test", container_name.c_str(), vm_name.c_str()));
   if (vm_name == kDefaultVmName && container_name == kDefaultContainerName) {
     UnregisterHostname(kDefaultContainerHostname);
   }
@@ -1496,7 +1497,7 @@
                  << container_name;
     if (owner_id == primary_owner_id_) {
       UnregisterHostname(base::StringPrintf(
-          "%s-%s-local", container_name.c_str(), vm_name.c_str()));
+          "%s.%s.linux.test", container_name.c_str(), vm_name.c_str()));
       if (vm_name == kDefaultVmName &&
           container_name == kDefaultContainerName) {
         UnregisterHostname(kDefaultContainerHostname);
diff --git a/vm_tools/concierge/service.cc b/vm_tools/concierge/service.cc
index b537b61..68f1c37 100644
--- a/vm_tools/concierge/service.cc
+++ b/vm_tools/concierge/service.cc
@@ -1397,7 +1397,7 @@
       request.cryptohome_id(), request.vm_name(), container_name));
   response.set_host_private_key(GetHostSshPrivateKey(request.cryptohome_id()));
   response.set_hostname(base::StringPrintf(
-      "%s-%s-local", container_name.c_str(), request.vm_name().c_str()));
+      "%s.%s.linux.test", container_name.c_str(), request.vm_name().c_str()));
   writer.AppendProtoAsArrayOfBytes(response);
   return dbus_response;
 }