shill: openvpn option initialization.
This implements most of openvpn command line option initialization. The
remaining items that are needed for the basic autotest are covered by tracker
issues.
BUG=chromium-os:26992
TEST=unit tests
Change-Id: I7edc320b431e95535f14198c2025d5d50cd102ca
Reviewed-on: https://gerrit.chromium.org/gerrit/16960
Reviewed-by: Sam Leffler <sleffler@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Darin Petkov <petkov@chromium.org>
diff --git a/openvpn_driver.cc b/openvpn_driver.cc
index d4d2d6d..e50335d 100644
--- a/openvpn_driver.cc
+++ b/openvpn_driver.cc
@@ -4,11 +4,18 @@
#include "shill/openvpn_driver.h"
+#include <base/logging.h>
+#include <chromeos/dbus/service_constants.h>
+
#include "shill/error.h"
+using std::string;
+using std::vector;
+
namespace shill {
-OpenVPNDriver::OpenVPNDriver() {}
+OpenVPNDriver::OpenVPNDriver(const KeyValueStore &args)
+ : args_(args) {}
OpenVPNDriver::~OpenVPNDriver() {}
@@ -16,4 +23,136 @@
error->Populate(Error::kNotSupported);
}
+void OpenVPNDriver::InitOptions(vector<string> *options, Error *error) {
+ string vpnhost;
+ if (args_.ContainsString(flimflam::kProviderHostProperty)) {
+ vpnhost = args_.GetString(flimflam::kProviderHostProperty);
+ }
+ if (vpnhost.empty()) {
+ Error::PopulateAndLog(
+ error, Error::kInvalidArguments, "VPN host not specified.");
+ return;
+ }
+ options->push_back("--client");
+ options->push_back("--tls-client");
+ options->push_back("--remote");
+ options->push_back(vpnhost);
+ options->push_back("--nobind");
+ options->push_back("--persist-key");
+ options->push_back("--persist-tun");
+
+ // TODO(petkov): Add "--dev <interface_name>". For OpenVPN, the interface will
+ // be the tunnel device (crosbug.com/26841).
+ options->push_back("--dev-type");
+ options->push_back("tun");
+ options->push_back("--syslog");
+
+ // TODO(petkov): Enable verbosity based on shill logging options too.
+ AppendValueOption("OpenVPN.Verb", "--verb", options);
+
+ AppendValueOption("VPN.MTU", "--mtu", options);
+ AppendValueOption(flimflam::kOpenVPNProtoProperty, "--proto", options);
+ AppendValueOption(flimflam::kOpenVPNPortProperty, "--port", options);
+ AppendValueOption("OpenVPN.TLSAuth", "--tls-auth", options);
+
+ // TODO(petkov): Implement this.
+ LOG_IF(ERROR, args_.ContainsString(flimflam::kOpenVPNTLSAuthContentsProperty))
+ << "Support for --tls-auth not implemented yet.";
+
+ AppendValueOption(
+ flimflam::kOpenVPNTLSRemoteProperty, "--tls-remote", options);
+ AppendValueOption(flimflam::kOpenVPNCipherProperty, "--cipher", options);
+ AppendValueOption(flimflam::kOpenVPNAuthProperty, "--auth", options);
+ AppendFlag(flimflam::kOpenVPNAuthNoCacheProperty, "--auth-nocache", options);
+ AppendValueOption(
+ flimflam::kOpenVPNAuthRetryProperty, "--auth-retry", options);
+ AppendFlag(flimflam::kOpenVPNCompLZOProperty, "--comp-lzo", options);
+ AppendFlag(flimflam::kOpenVPNCompNoAdaptProperty, "--comp-noadapt", options);
+ AppendFlag(
+ flimflam::kOpenVPNPushPeerInfoProperty, "--push-peer-info", options);
+ AppendValueOption(flimflam::kOpenVPNRenegSecProperty, "--reneg-sec", options);
+ AppendValueOption(flimflam::kOpenVPNShaperProperty, "--shaper", options);
+ AppendValueOption(flimflam::kOpenVPNServerPollTimeoutProperty,
+ "--server-poll-timeout", options);
+
+ // TODO(petkov): Implement this.
+ LOG_IF(ERROR, args_.ContainsString(flimflam::kOpenVPNCaCertNSSProperty))
+ << "Support for NSS CA not implemented yet.";
+
+ // Client-side ping support.
+ AppendValueOption("OpenVPN.Ping", "--ping", options);
+ AppendValueOption("OpenVPN.PingExit", "--ping-exit", options);
+ AppendValueOption("OpenVPN.PingRestart", "--ping-restart", options);
+
+ AppendValueOption(flimflam::kOpenVPNCaCertProperty, "--ca", options);
+ AppendValueOption("OpenVPN.Cert", "--cert", options);
+ AppendValueOption(
+ flimflam::kOpenVPNNsCertTypeProperty, "--ns-cert-type", options);
+ AppendValueOption("OpenVPN.Key", "--key", options);
+
+ // TODO(petkov): Implement this.
+ LOG_IF(ERROR, args_.ContainsString(flimflam::kOpenVPNClientCertIdProperty))
+ << "Support for PKCS#11 (--pkcs11-id and --pkcs11-providers) "
+ << "not implemented yet.";
+
+ // TLS suport.
+ string remote_cert_tls;
+ if (args_.ContainsString(flimflam::kOpenVPNRemoteCertTLSProperty)) {
+ remote_cert_tls = args_.GetString(flimflam::kOpenVPNRemoteCertTLSProperty);
+ }
+ if (remote_cert_tls.empty()) {
+ remote_cert_tls = "server";
+ }
+ if (remote_cert_tls != "none") {
+ options->push_back("--remote-cert-tls");
+ options->push_back(remote_cert_tls);
+ }
+
+ // This is an undocumented command line argument that works like a .cfg file
+ // entry. TODO(sleffler): Maybe roll this into --tls-auth?
+ AppendValueOption(
+ flimflam::kOpenVPNKeyDirectionProperty, "--key-direction", options);
+ // TODO(sleffler): Support more than one eku parameter.
+ AppendValueOption(
+ flimflam::kOpenVPNRemoteCertEKUProperty, "--remote-cert-eku", options);
+ AppendValueOption(
+ flimflam::kOpenVPNRemoteCertKUProperty, "--remote-cert-ku", options);
+
+ // TODO(petkov): Setup management control channel and add the approprate
+ // options (crosbug.com/26994).
+
+ // TODO(petkov): Setup openvpn-script options and DBus info required to send
+ // back Layer 3 configuration (crosbug.com/26993).
+
+ // Disable openvpn handling since we do route+ifconfig work.
+ options->push_back("--route-noexec");
+ options->push_back("--ifconfig-noexec");
+
+ // Drop root privileges on connection and enable callback scripts to send
+ // notify messages.
+ options->push_back("--user");
+ options->push_back("openvpn");
+ options->push_back("--group");
+ options->push_back("openvpn");
+}
+
+void OpenVPNDriver::AppendValueOption(
+ const string &property, const string &option, vector<string> *options) {
+ string value;
+ if (args_.ContainsString(property)) {
+ value = args_.GetString(property);
+ }
+ if (!value.empty()) {
+ options->push_back(option);
+ options->push_back(value);
+ }
+}
+
+void OpenVPNDriver::AppendFlag(
+ const string &property, const string &option, vector<string> *options) {
+ if (args_.ContainsString(property)) {
+ options->push_back(option);
+ }
+}
+
} // namespace shill
diff --git a/openvpn_driver.h b/openvpn_driver.h
index ad6926f..ea4b4c9 100644
--- a/openvpn_driver.h
+++ b/openvpn_driver.h
@@ -5,6 +5,12 @@
#ifndef SHILL_OPENVPN_DRIVER_
#define SHILL_OPENVPN_DRIVER_
+#include <string>
+#include <vector>
+
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
+
+#include "shill/key_value_store.h"
#include "shill/vpn_driver.h"
namespace shill {
@@ -13,13 +19,30 @@
class OpenVPNDriver : public VPNDriver {
public:
- OpenVPNDriver();
+ explicit OpenVPNDriver(const KeyValueStore &args);
virtual ~OpenVPNDriver();
// Inherited from VPNDriver.
virtual void Connect(Error *error);
private:
+ friend class OpenVPNDriverTest;
+ FRIEND_TEST(OpenVPNDriverTest, AppendFlag);
+ FRIEND_TEST(OpenVPNDriverTest, AppendValueOption);
+ FRIEND_TEST(OpenVPNDriverTest, InitOptions);
+ FRIEND_TEST(OpenVPNDriverTest, InitOptionsNoHost);
+
+ void InitOptions(std::vector<std::string> *options, Error *error);
+
+ void AppendValueOption(const std::string &property,
+ const std::string &option,
+ std::vector<std::string> *options);
+ void AppendFlag(const std::string &property,
+ const std::string &option,
+ std::vector<std::string> *options);
+
+ KeyValueStore args_;
+
DISALLOW_COPY_AND_ASSIGN(OpenVPNDriver);
};
diff --git a/openvpn_driver_unittest.cc b/openvpn_driver_unittest.cc
index 08064c1..e757461 100644
--- a/openvpn_driver_unittest.cc
+++ b/openvpn_driver_unittest.cc
@@ -4,25 +4,109 @@
#include "shill/openvpn_driver.h"
+#include <chromeos/dbus/service_constants.h>
#include <gtest/gtest.h>
#include "shill/error.h"
+using std::string;
+using std::vector;
+
namespace shill {
class OpenVPNDriverTest : public testing::Test {
public:
- OpenVPNDriverTest() {}
+ OpenVPNDriverTest()
+ : driver_(args_) {}
+
virtual ~OpenVPNDriverTest() {}
protected:
+ static const char kOption[];
+ static const char kProperty[];
+ static const char kValue[];
+ static const char kOption2[];
+ static const char kProperty2[];
+ static const char kValue2[];
+
+ void SetArgs() {
+ driver_.args_ = args_;
+ }
+
+ KeyValueStore args_;
OpenVPNDriver driver_;
};
+const char OpenVPNDriverTest::kOption[] = "--openvpn-option";
+const char OpenVPNDriverTest::kProperty[] = "OpenVPN.SomeProperty";
+const char OpenVPNDriverTest::kValue[] = "some-property-value";
+const char OpenVPNDriverTest::kOption2[] = "--openvpn-option2";
+const char OpenVPNDriverTest::kProperty2[] = "OpenVPN.SomeProperty2";
+const char OpenVPNDriverTest::kValue2[] = "some-property-value2";
+
TEST_F(OpenVPNDriverTest, Connect) {
Error error;
driver_.Connect(&error);
EXPECT_EQ(Error::kNotSupported, error.type());
}
+TEST_F(OpenVPNDriverTest, InitOptionsNoHost) {
+ Error error;
+ vector<string> options;
+ driver_.InitOptions(&options, &error);
+ EXPECT_EQ(Error::kInvalidArguments, error.type());
+ EXPECT_TRUE(options.empty());
+}
+
+TEST_F(OpenVPNDriverTest, InitOptions) {
+ static const char kHost[] = "192.168.2.254";
+ args_.SetString(flimflam::kProviderHostProperty, kHost);
+ SetArgs();
+ Error error;
+ vector<string> options;
+ driver_.InitOptions(&options, &error);
+ EXPECT_TRUE(error.IsSuccess());
+ EXPECT_EQ("--client", options[0]);
+ EXPECT_EQ("--remote", options[2]);
+ EXPECT_EQ(kHost, options[3]);
+ EXPECT_EQ("openvpn", options.back());
+}
+
+TEST_F(OpenVPNDriverTest, AppendValueOption) {
+ vector<string> options;
+ driver_.AppendValueOption("OpenVPN.UnknownProperty", kOption, &options);
+ EXPECT_TRUE(options.empty());
+
+ args_.SetString(kProperty, "");
+ SetArgs();
+ driver_.AppendValueOption(kProperty, kOption, &options);
+ EXPECT_TRUE(options.empty());
+
+ args_.SetString(kProperty, kValue);
+ args_.SetString(kProperty2, kValue2);
+ SetArgs();
+ driver_.AppendValueOption(kProperty, kOption, &options);
+ driver_.AppendValueOption(kProperty2, kOption2, &options);
+ EXPECT_EQ(4, options.size());
+ EXPECT_EQ(kOption, options[0]);
+ EXPECT_EQ(kValue, options[1]);
+ EXPECT_EQ(kOption2, options[2]);
+ EXPECT_EQ(kValue2, options[3]);
+}
+
+TEST_F(OpenVPNDriverTest, AppendFlag) {
+ vector<string> options;
+ driver_.AppendValueOption("OpenVPN.UnknownProperty", kOption, &options);
+ EXPECT_TRUE(options.empty());
+
+ args_.SetString(kProperty, "");
+ args_.SetString(kProperty2, kValue2);
+ SetArgs();
+ driver_.AppendFlag(kProperty, kOption, &options);
+ driver_.AppendFlag(kProperty2, kOption2, &options);
+ EXPECT_EQ(2, options.size());
+ EXPECT_EQ(kOption, options[0]);
+ EXPECT_EQ(kOption2, options[1]);
+}
+
} // namespace shill
diff --git a/vpn_provider.cc b/vpn_provider.cc
index 39fa0e5..951e165 100644
--- a/vpn_provider.cc
+++ b/vpn_provider.cc
@@ -41,7 +41,7 @@
const string &type = args.GetString(flimflam::kProviderTypeProperty);
scoped_ptr<VPNDriver> driver;
if (type == flimflam::kProviderOpenVpn) {
- driver.reset(new OpenVPNDriver());
+ driver.reset(new OpenVPNDriver(args));
} else {
Error::PopulateAndLog(
error, Error::kNotSupported, "Unsupported VPN type: " + type);