vpn-manager: accept a hostname for remote host

Change-Id: Iefe53207cf8df8bfbe32c3b69409348e23ac1bb2

BUG=chromium-os:13472
TEST=connect-vpn with remote host name instead of ip address

Review URL: http://codereview.chromium.org/6731015
diff --git a/ipsec_manager.cc b/ipsec_manager.cc
index 287d62b..73e3966 100644
--- a/ipsec_manager.cc
+++ b/ipsec_manager.cc
@@ -53,6 +53,7 @@
 IpsecManager::IpsecManager()
     : ServiceManager(kIpsecServiceName),
       force_local_address_(NULL),
+      force_remote_address_(NULL),
       output_fd_(-1),
       ike_version_(0),
       ipsec_group_(0),
@@ -64,16 +65,16 @@
 }
 
 bool IpsecManager::Initialize(int ike_version,
-                              const std::string& remote_address,
+                              const std::string& remote_host,
                               const std::string& psk_file,
                               const std::string& server_ca_file,
                               const std::string& client_key_file,
                               const std::string& client_cert_file) {
-  if (remote_address.empty()) {
-    LOG(ERROR) << "Missing remote address to IPsec layer";
+  if (remote_host.empty()) {
+    LOG(ERROR) << "Missing remote host to IPsec layer";
     return false;
   }
-  remote_address_ = remote_address;
+  remote_host_ = remote_host;
 
   if (psk_file.empty()) {
     if (server_ca_file.empty() && client_key_file.empty() &&
@@ -128,21 +129,54 @@
   return true;
 }
 
-bool IpsecManager::GetLocalAddressForRemote(
-    const std::string& remote_address_text,
+bool IpsecManager::ConvertSockAddrToIPString(
+    const struct sockaddr& socket_address,
+    std::string* output) {
+  char str[INET6_ADDRSTRLEN] = { 0 };
+  switch (socket_address.sa_family) {
+    case AF_INET:
+      if (!inet_ntop(AF_INET, &reinterpret_cast<const sockaddr_in*>(
+              &socket_address)->sin_addr, str, INET6_ADDRSTRLEN)) {
+        LOG(ERROR) << "inet_ntop failed";
+        return false;
+      }
+      break;
+    case AF_INET6:
+      if (!inet_ntop(AF_INET6, &reinterpret_cast<const sockaddr_in6*>(
+              &socket_address)->sin6_addr, str, INET6_ADDRSTRLEN)) {
+        LOG(ERROR) << "inet_ntop failed";
+        return false;
+      }
+      break;
+    default:
+      LOG(ERROR) << "Unknown address family";
+      return false;
+  }
+  *output = str;
+  return true;
+}
+
+bool IpsecManager::GetAddressesFromRemoteHost(
+    const std::string& remote_host,
+    std::string* remote_address_text,
     std::string* local_address_text) {
   static const char kService[] = "80";
   if (force_local_address_ != NULL) {
     *local_address_text = force_local_address_;
+    *remote_address_text = force_remote_address_;
     return true;
   }
   struct addrinfo *remote_address;
-  int s = getaddrinfo(remote_address_text.c_str(), kService, NULL,
+  int s = getaddrinfo(remote_host.c_str(), kService, NULL,
                       &remote_address);
   if (s != 0) {
     LOG(ERROR) << "getaddrinfo failed: " << gai_strerror(s);
     return false;
   }
+  if (!ConvertSockAddrToIPString(*remote_address->ai_addr,
+                                 remote_address_text)) {
+    return false;
+  }
   int sock = HANDLE_EINTR(socket(AF_INET, SOCK_DGRAM, 0));
   if (sock < 0) {
     LOG(ERROR) << "Unable to create socket";
@@ -157,34 +191,14 @@
   bool result = false;
   struct sockaddr local_address;
   socklen_t addr_len = sizeof(local_address);
-  char str[INET6_ADDRSTRLEN] = { 0 };
   if (getsockname(sock, &local_address, &addr_len) != 0) {
     int saved_errno = errno;
     LOG(ERROR) << "getsockname failed on socket connecting to "
                << remote_address_text << ": " << saved_errno;
     goto error_label;
   }
-  // convert local_address to local_address_text.
-  switch (local_address.sa_family) {
-    case AF_INET:
-      if (!inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(
-              &local_address)->sin_addr, str, INET6_ADDRSTRLEN)) {
-        LOG(ERROR) << "inet_ntop failed on " << remote_address_text;
-        goto error_label;
-      }
-      break;
-    case AF_INET6:
-      if (!inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(
-              &local_address)->sin6_addr, str, INET6_ADDRSTRLEN)) {
-        LOG(ERROR) << "inet_ntop failed on " << remote_address_text;
-        goto error_label;
-      }
-      break;
-    default:
-      LOG(ERROR) << "Unknown address family converting " << remote_address_text;
-      goto error_label;
-  }
-  *local_address_text = str;
+  if (!ConvertSockAddrToIPString(local_address, local_address_text))
+    goto error_label;
   LOG(INFO) << "Remote address " << remote_address_text << " has local address "
             << *local_address_text;
   result = true;
@@ -203,14 +217,16 @@
     return false;
   }
   std::string local_address;
-  if (!GetLocalAddressForRemote(remote_address_, &local_address)) {
+  std::string remote_address;
+  if (!GetAddressesFromRemoteHost(remote_host_, &remote_address,
+                                  &local_address)) {
     LOG(ERROR) << "Local IP address could not be determined for PSK mode";
     return false;
   }
   TrimWhitespaceASCII(psk, TRIM_TRAILING, &psk);
   *formatted =
       StringPrintf("%s %s : PSK \"%s\"\n", local_address.c_str(),
-                   remote_address_.c_str(), psk.c_str());
+                   remote_address.c_str(), psk.c_str());
   return true;
 }
 
@@ -276,7 +292,7 @@
   AppendStringSetting(&config, "left", "%defaultroute");
   AppendStringSetting(&config, "leftprotoport", FLAGS_leftprotoport);
   AppendStringSetting(&config, "leftupdown", IPSEC_UPDOWN);
-  AppendStringSetting(&config, "right", remote_address_);
+  AppendStringSetting(&config, "right", remote_host_);
   AppendStringSetting(&config, "rightprotoport", FLAGS_rightprotoport);
   AppendStringSetting(&config, "type", FLAGS_type);
   AppendStringSetting(&config, "auto", "start");
diff --git a/ipsec_manager.h b/ipsec_manager.h
index 9497177..7334405 100644
--- a/ipsec_manager.h
+++ b/ipsec_manager.h
@@ -25,12 +25,12 @@
   IpsecManager();
 
   // Initialize the object to control IKE version |ike_version| daemon,
-  // connecting to the give |remote_address|, with given paths to
+  // connecting to the give |remote_hostname|, with given paths to
   // pre-shared key file |psk_file|, server certificate authority file
   // |server_ca_file|, client key file |client_key_file|, and client
   // certificate file |client_cert_file|.
   bool Initialize(int ike_version,
-                  const std::string& remote_address,
+                  const std::string& remote_hostname,
                   const std::string& psk_file,
                   const std::string& server_ca_file,
                   const std::string& client_key_file,
@@ -54,14 +54,17 @@
   FRIEND_TEST(IpsecManagerTest, PollNothingIfRunning);
   FRIEND_TEST(IpsecManagerTestIkeV1Psk, FormatPsk);
   FRIEND_TEST(IpsecManagerTestIkeV1Psk, FormatStarterConfigFile);
-  FRIEND_TEST(IpsecManagerTestIkeV1Psk, GetLocalAddressForRemote);
+  FRIEND_TEST(IpsecManagerTestIkeV1Psk, GetAddressesFromRemoteHost);
   FRIEND_TEST(IpsecManagerTestIkeV1Psk, Start);
   FRIEND_TEST(IpsecManagerTestIkeV1Psk, StartStarterAlreadyRunning);
   FRIEND_TEST(IpsecManagerTestIkeV1Psk, StartStarterNotYetRunning);
   FRIEND_TEST(IpsecManagerTestIkeV1Psk, WriteConfigFiles);
 
-  bool GetLocalAddressForRemote(const std::string& remote_address_text,
-                                std::string* local_address_text);
+  bool ConvertSockAddrToIPString(const struct sockaddr& socket_address,
+                                 std::string* output);
+  bool GetAddressesFromRemoteHost(const std::string& remote_hostname,
+                                  std::string* remote_address_text,
+                                  std::string* local_address_text);
   bool FormatPsk(const FilePath& input_file, std::string* formatted);
   void KillCurrentlyRunning();
   bool WriteConfigFiles();
@@ -70,8 +73,10 @@
   bool StartStarter();
   bool SetIpsecGroup(const FilePath& file_path);
 
-  // for testing, always return this value from GetLocalAddressForRemote.
+  // for testing, always return these values from
+  // GetAddressesFromRemoteHostname.
   const char* force_local_address_;
+  const char* force_remote_address_;
   // ipsec daemon stderr pipe file descriptor.
   int output_fd_;
   // IKE key exchange version to use.
@@ -91,8 +96,8 @@
   std::string ipsec_prefix_;
   // File containing starter process's process id.
   std::string starter_pid_file_;
-  // Remote IP of IPsec connection.
-  std::string remote_address_;
+  // Remote hostname of IPsec connection.
+  std::string remote_host_;
   // File containing the IPsec pre-shared key.
   std::string psk_file_;
   // File containing the server certificate authority.
diff --git a/ipsec_manager_test.cc b/ipsec_manager_test.cc
index 37701f2..0e67a9c 100644
--- a/ipsec_manager_test.cc
+++ b/ipsec_manager_test.cc
@@ -32,7 +32,7 @@
     file_util::CreateDirectory(test_path_);
     stateful_container_ = test_path_.Append("etc");
     file_util::CreateDirectory(stateful_container_);
-    remote_ = "1.2.3.4";
+    remote_ = "vpnserver";
     ServiceManager::temp_path_ = new FilePath(test_path_);
     psk_file_ = test_path_.Append("psk").value();
     server_ca_file_ = test_path_.Append("server.ca").value();
@@ -52,6 +52,7 @@
     ipsec_.ipsec_run_path_ = ipsec_run_path_;
     ipsec_.ipsec_up_file_ = ipsec_up_file_;
     ipsec_.force_local_address_ = "5.6.7.8";
+    ipsec_.force_remote_address_ = "1.2.3.4";
   }
 
   void SetStartStarterExpectations(bool already_running);
@@ -183,11 +184,15 @@
 TEST_F(IpsecManagerTestIkeV1Psk, Initialize) {
 }
 
-TEST_F(IpsecManagerTestIkeV1Psk, GetLocalAddressForRemote) {
+TEST_F(IpsecManagerTestIkeV1Psk, GetAddressesFromRemoteHost) {
   ipsec_.force_local_address_ = NULL;
   std::string local_address;
-  EXPECT_TRUE(ipsec_.GetLocalAddressForRemote("127.0.0.1", &local_address));
+  std::string remote_address;
+  EXPECT_TRUE(ipsec_.GetAddressesFromRemoteHost("localhost",
+                                                &remote_address,
+                                                &local_address));
   EXPECT_EQ("127.0.0.1", local_address);
+  EXPECT_EQ("127.0.0.1", remote_address);
 }
 
 TEST_F(IpsecManagerTestIkeV1Psk, FormatPsk) {
@@ -230,7 +235,7 @@
       "\tleft=%defaultroute\n"
       "\tleftprotoport=17/1701\n"
       "\tleftupdown=/usr/libexec/l2tpipsec_vpn/pluto_updown\n"
-      "\tright=1.2.3.4\n"
+      "\tright=vpnserver\n"
       "\trightprotoport=17/1701\n"
       "\ttype=transport\n"
       "\tauto=start\n";
diff --git a/l2tp_manager.cc b/l2tp_manager.cc
index 7d0e3fa..6b1794d 100644
--- a/l2tp_manager.cc
+++ b/l2tp_manager.cc
@@ -37,8 +37,8 @@
       l2tpd_(new ProcessImpl) {
 }
 
-bool L2tpManager::Initialize(const std::string& remote_address) {
-  remote_address_ = remote_address;
+bool L2tpManager::Initialize(const std::string& remote_host) {
+  remote_host_ = remote_host;
   if (FLAGS_user.empty()) {
     LOG(ERROR) << "l2tp layer requires user name";
     return false;
@@ -66,7 +66,7 @@
     const std::string& ppp_config_path) {
   std::string l2tpd_config;
   l2tpd_config.append(StringPrintf("[lac %s]\n", kL2tpConnectionName));
-  AddString(&l2tpd_config, "lns", remote_address_);
+  AddString(&l2tpd_config, "lns", remote_host_);
   AddBool(&l2tpd_config, "require chap", FLAGS_require_chap);
   AddBool(&l2tpd_config, "refuse pap", FLAGS_refuse_pap);
   AddBool(&l2tpd_config, "require authentication",
diff --git a/l2tp_manager.h b/l2tp_manager.h
index bb86228..b6602f3 100644
--- a/l2tp_manager.h
+++ b/l2tp_manager.h
@@ -26,10 +26,10 @@
  public:
   L2tpManager();
 
-  // Initialize the object using |remote_address|.  Returns false if
+  // Initialize the object using |remote_host|.  Returns false if
   // an illegal set of parameters has been given.  Has no side effects
   // other than setting up the object.
-  bool Initialize(const std::string& remote_address);
+  bool Initialize(const std::string& remote_host);
 
   virtual bool Start();
   virtual void Stop();
@@ -65,8 +65,8 @@
   int output_fd_;
   // Start time of the l2tp daemon.
   base::TimeTicks start_ticks_;
-  // Remote address for L2TP connection.
-  std::string remote_address_;
+  // Remote host for L2TP connection.
+  std::string remote_host_;
   // Last partial line read from output_fd_.
   std::string partial_output_line_;
   // Path to a file whose existence indicates the ppp device is up.
diff --git a/l2tp_manager_test.cc b/l2tp_manager_test.cc
index a0b115d..90baed3 100644
--- a/l2tp_manager_test.cc
+++ b/l2tp_manager_test.cc
@@ -28,7 +28,7 @@
     ServiceManager::temp_path_ = new FilePath(test_path_);
     file_util::Delete(test_path_, true);
     file_util::CreateDirectory(test_path_);
-    remote_ = "1.2.3.4";
+    remote_hostname_ = "vpnserver";
     control_path_ = test_path_.Append("control");
     pppd_config_path_ = test_path_.Append("pppd.config");
     ppp_interface_path_ = test_path_.Append("ppp0");
@@ -38,11 +38,11 @@
     l2tp_.ppp_interface_path_ = ppp_interface_path_;
     FLAGS_pppd_plugin = "";
     FLAGS_user = "me";
-    EXPECT_TRUE(l2tp_.Initialize(remote_));
+    EXPECT_TRUE(l2tp_.Initialize(remote_hostname_));
   }
 
  protected:
-  std::string remote_;
+  std::string remote_hostname_;
   FilePath test_path_;
   FilePath control_path_;
   FilePath pppd_config_path_;
@@ -54,7 +54,7 @@
 TEST_F(L2tpManagerTest, FormatL2tpdConfiguration) {
   static const char kBaseExpected[] =
       "[lac managed]\n"
-      "lns = 1.2.3.4\n"
+      "lns = vpnserver\n"
       "require chap = yes\n"
       "refuse pap = yes\n"
       "require authentication = yes\n"
diff --git a/l2tpipsec_vpn.cc b/l2tpipsec_vpn.cc
index 24a57a7..d9264dc 100644
--- a/l2tpipsec_vpn.cc
+++ b/l2tpipsec_vpn.cc
@@ -22,7 +22,7 @@
 DEFINE_string(client_cert_file, "", "File with IPsec client certificate");
 DEFINE_string(client_key_file, "", "File with IPsec client private key");
 DEFINE_string(psk_file, "", "File with IPsec pre-shared key");
-DEFINE_string(remote_address, "", "VPN server address");
+DEFINE_string(remote_host, "", "VPN server hostname");
 DEFINE_string(server_ca_file, "", "File with IPsec server CA");
 #pragma GCC diagnostic error "-Wstrict-aliasing"
 
@@ -111,14 +111,14 @@
   ServiceManager::InitializeDirectories(&temp_dir);
 
   if (!ipsec.Initialize(1,
-                        FLAGS_remote_address,
+                        FLAGS_remote_host,
                         FLAGS_psk_file,
                         FLAGS_server_ca_file,
                         FLAGS_client_key_file,
                         FLAGS_client_cert_file)) {
     return 1;
   }
-  if (!l2tp.Initialize(FLAGS_remote_address)) {
+  if (!l2tp.Initialize(FLAGS_remote_host)) {
     return 1;
   }
   ServiceManager::SetLayerOrder(&ipsec, &l2tp);