blob: 166e79c32850939e8c4cbd14eed51f2b9c9255bc [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/openvpn_driver.h"
#include <base/logging.h>
#include <chromeos/dbus/service_constants.h>
#include "shill/error.h"
#include "shill/rpc_task.h"
using std::string;
using std::vector;
namespace shill {
namespace {
const char kOpenVPNScript[] = "/usr/lib/flimflam/scripts/openvpn-script";
} // namespace {}
OpenVPNDriver::OpenVPNDriver(ControlInterface *control,
const KeyValueStore &args)
: control_(control),
args_(args) {}
OpenVPNDriver::~OpenVPNDriver() {}
void OpenVPNDriver::Connect(Error *error) {
// TODO(petkov): Allocate rpc_task_.
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).
// Setup openvpn-script options and RPC information required to send back
// Layer 3 configuration.
options->push_back("--setenv");
options->push_back("CONNMAN_BUSNAME");
options->push_back(rpc_task_->GetRpcConnectionIdentifier());
options->push_back("--setenv");
options->push_back("CONNMAN_INTERFACE");
options->push_back(rpc_task_->GetRpcInterfaceIdentifier());
options->push_back("--setenv");
options->push_back("CONNMAN_PATH");
options->push_back(rpc_task_->GetRpcIdentifier());
options->push_back("--script-security");
options->push_back("2");
options->push_back("--up");
options->push_back(kOpenVPNScript);
options->push_back("--up-restart");
// 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