299 lines
11 KiB
C++
299 lines
11 KiB
C++
//
|
|
// Copyright (C) 2012 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#ifndef SHILL_VPN_OPENVPN_DRIVER_H_
|
|
#define SHILL_VPN_OPENVPN_DRIVER_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <base/files/file_path.h>
|
|
#include <gtest/gtest_prod.h> // for FRIEND_TEST
|
|
|
|
#include "shill/ipconfig.h"
|
|
#include "shill/net/sockets.h"
|
|
#include "shill/refptr_types.h"
|
|
#include "shill/rpc_task.h"
|
|
#include "shill/service.h"
|
|
#include "shill/vpn/vpn_driver.h"
|
|
|
|
namespace base {
|
|
|
|
template<typename T>
|
|
class WeakPtr;
|
|
|
|
} // namespace base
|
|
|
|
namespace shill {
|
|
|
|
class CertificateFile;
|
|
class ControlInterface;
|
|
class DeviceInfo;
|
|
class Error;
|
|
class Metrics;
|
|
class OpenVPNManagementServer;
|
|
class ProcessManager;
|
|
|
|
class OpenVPNDriver : public VPNDriver,
|
|
public RPCTaskDelegate {
|
|
public:
|
|
enum ReconnectReason {
|
|
kReconnectReasonUnknown,
|
|
kReconnectReasonOffline,
|
|
kReconnectReasonTLSError,
|
|
};
|
|
|
|
OpenVPNDriver(ControlInterface* control,
|
|
EventDispatcher* dispatcher,
|
|
Metrics* metrics,
|
|
Manager* manager,
|
|
DeviceInfo* device_info,
|
|
ProcessManager* process_manager);
|
|
~OpenVPNDriver() override;
|
|
|
|
virtual void OnReconnecting(ReconnectReason reason);
|
|
|
|
// Resets the VPN state and deallocates all resources. If there's a service
|
|
// associated through Connect, sets its state to Service::kStateIdle and
|
|
// disassociates from the service.
|
|
virtual void IdleService();
|
|
|
|
// Resets the VPN state and deallocates all resources. If there's a service
|
|
// associated through Connect, sets its state to Service::kStateFailure, sets
|
|
// the failure reason to |failure|, sets its ErrorDetails property to
|
|
// |error_details|, and disassociates from the service.
|
|
virtual void FailService(Service::ConnectFailure failure,
|
|
const std::string& error_details);
|
|
|
|
// Append zero-valued, single-valued and double-valued options to the
|
|
// |options| array.
|
|
static void AppendOption(
|
|
const std::string& option,
|
|
std::vector<std::vector<std::string>>* options);
|
|
static void AppendOption(
|
|
const std::string& option,
|
|
const std::string& value,
|
|
std::vector<std::vector<std::string>>* options);
|
|
static void AppendOption(
|
|
const std::string& option,
|
|
const std::string& value0,
|
|
const std::string& value1,
|
|
std::vector<std::vector<std::string>>* options);
|
|
|
|
// Returns true if an option was appended.
|
|
bool AppendValueOption(const std::string& property,
|
|
const std::string& option,
|
|
std::vector<std::vector<std::string>>* options);
|
|
|
|
// If |property| exists, split its value up using |delimiter|. Each element
|
|
// will be a separate argument to |option|. Returns true if the option was
|
|
// appended to |options|.
|
|
bool AppendDelimitedValueOption(
|
|
const std::string& property,
|
|
const std::string& option,
|
|
char delimiter,
|
|
std::vector<std::vector<std::string>>* options);
|
|
|
|
// Returns true if a flag was appended.
|
|
bool AppendFlag(const std::string& property,
|
|
const std::string& option,
|
|
std::vector<std::vector<std::string>>* options);
|
|
|
|
virtual std::string GetServiceRpcIdentifier() const;
|
|
|
|
protected:
|
|
// Inherited from VPNDriver. |Connect| initiates the VPN connection by
|
|
// creating a tunnel device. When the device index becomes available, this
|
|
// instance is notified through |ClaimInterface| and resumes the connection
|
|
// process by setting up and spawning an external 'openvpn' process. IP
|
|
// configuration settings are passed back from the external process through
|
|
// the |Notify| RPC service method.
|
|
void Connect(const VPNServiceRefPtr& service, Error* error) override;
|
|
bool ClaimInterface(const std::string& link_name,
|
|
int interface_index) override;
|
|
void Disconnect() override;
|
|
std::string GetProviderType() const override;
|
|
void OnConnectionDisconnected() override;
|
|
void OnConnectTimeout() override;
|
|
|
|
private:
|
|
friend class OpenVPNDriverTest;
|
|
FRIEND_TEST(OpenVPNDriverTest, ClaimInterface);
|
|
FRIEND_TEST(OpenVPNDriverTest, Cleanup);
|
|
FRIEND_TEST(OpenVPNDriverTest, Connect);
|
|
FRIEND_TEST(OpenVPNDriverTest, ConnectTunnelFailure);
|
|
FRIEND_TEST(OpenVPNDriverTest, Disconnect);
|
|
FRIEND_TEST(OpenVPNDriverTest, GetEnvironment);
|
|
FRIEND_TEST(OpenVPNDriverTest, GetRouteOptionEntry);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitCAOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitCertificateVerifyOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitClientAuthOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitExtraCertOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitLoggingOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitOptionsHostWithPort);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitOptionsNoHost);
|
|
FRIEND_TEST(OpenVPNDriverTest, InitPKCS11Options);
|
|
FRIEND_TEST(OpenVPNDriverTest, Notify);
|
|
FRIEND_TEST(OpenVPNDriverTest, NotifyUMA);
|
|
FRIEND_TEST(OpenVPNDriverTest, NotifyFail);
|
|
FRIEND_TEST(OpenVPNDriverTest, OnDefaultServiceChanged);
|
|
FRIEND_TEST(OpenVPNDriverTest, OnOpenVPNDied);
|
|
FRIEND_TEST(OpenVPNDriverTest, OnOpenVPNExited);
|
|
FRIEND_TEST(OpenVPNDriverTest, ParseForeignOption);
|
|
FRIEND_TEST(OpenVPNDriverTest, ParseForeignOptions);
|
|
FRIEND_TEST(OpenVPNDriverTest, ParseIPConfiguration);
|
|
FRIEND_TEST(OpenVPNDriverTest, ParseRouteOption);
|
|
FRIEND_TEST(OpenVPNDriverTest, SetRoutes);
|
|
FRIEND_TEST(OpenVPNDriverTest, SpawnOpenVPN);
|
|
FRIEND_TEST(OpenVPNDriverTest, SplitPortFromHost);
|
|
FRIEND_TEST(OpenVPNDriverTest, WriteConfigFile);
|
|
|
|
// The map is a sorted container that allows us to iterate through the options
|
|
// in order.
|
|
typedef std::map<int, std::string> ForeignOptions;
|
|
typedef std::map<int, IPConfig::Route> RouteOptions;
|
|
|
|
static const char kDefaultCACertificates[];
|
|
|
|
static const char kOpenVPNPath[];
|
|
static const char kOpenVPNScript[];
|
|
static const Property kProperties[];
|
|
|
|
static const char kLSBReleaseFile[];
|
|
|
|
static const char kDefaultOpenVPNConfigurationDirectory[];
|
|
|
|
static const int kReconnectOfflineTimeoutSeconds;
|
|
static const int kReconnectTLSErrorTimeoutSeconds;
|
|
|
|
static void ParseForeignOptions(const ForeignOptions& options,
|
|
IPConfig::Properties* properties);
|
|
static void ParseForeignOption(const std::string& option,
|
|
std::vector<std::string>* domain_search,
|
|
std::vector<std::string>* dns_servers);
|
|
static IPConfig::Route* GetRouteOptionEntry(const std::string& prefix,
|
|
const std::string& key,
|
|
RouteOptions* routes);
|
|
static void ParseRouteOption(const std::string& key,
|
|
const std::string& value,
|
|
RouteOptions* routes);
|
|
static void SetRoutes(const RouteOptions& routes,
|
|
IPConfig::Properties* properties);
|
|
|
|
// If |host| is in the "name:port" format, sets up |name| and |port|
|
|
// appropriately and returns true. Otherwise, returns false.
|
|
static bool SplitPortFromHost(const std::string& host,
|
|
std::string* name,
|
|
std::string* port);
|
|
|
|
void InitOptions(
|
|
std::vector<std::vector<std::string>>* options, Error* error);
|
|
bool InitCAOptions(
|
|
std::vector<std::vector<std::string>>* options, Error* error);
|
|
void InitCertificateVerifyOptions(
|
|
std::vector<std::vector<std::string>>* options);
|
|
void InitClientAuthOptions(std::vector<std::vector<std::string>>* options);
|
|
bool InitExtraCertOptions(
|
|
std::vector<std::vector<std::string>>* options, Error* error);
|
|
void InitPKCS11Options(std::vector<std::vector<std::string>>* options);
|
|
bool InitManagementChannelOptions(
|
|
std::vector<std::vector<std::string>>* options, Error* error);
|
|
void InitLoggingOptions(std::vector<std::vector<std::string>>* options);
|
|
|
|
std::map<std::string, std::string> GetEnvironment();
|
|
void ParseIPConfiguration(
|
|
const std::map<std::string, std::string>& configuration,
|
|
IPConfig::Properties* properties) const;
|
|
|
|
bool SpawnOpenVPN();
|
|
|
|
// Implements the public IdleService and FailService methods. Resets the VPN
|
|
// state and deallocates all resources. If there's a service associated
|
|
// through Connect, sets its state |state|; if |state| is
|
|
// Service::kStateFailure, sets the failure reason to |failure| and its
|
|
// ErrorDetails property to |error_details|; disassociates from the service.
|
|
void Cleanup(Service::ConnectState state,
|
|
Service::ConnectFailure failure,
|
|
const std::string& error_details);
|
|
|
|
static int GetReconnectTimeoutSeconds(ReconnectReason reason);
|
|
|
|
// Join a list of options into a single string.
|
|
static std::string JoinOptions(
|
|
const std::vector<std::vector<std::string>>& options, char separator);
|
|
|
|
// Output an OpenVPN configuration.
|
|
bool WriteConfigFile(const std::vector<std::vector<std::string>>& options,
|
|
base::FilePath* config_file);
|
|
|
|
// Called when the openpvn process exits.
|
|
void OnOpenVPNDied(int exit_status);
|
|
|
|
// Standalone callback used to delete the tunnel interface when the
|
|
// openvpn process exits as we clean up. ("Exiting" is expected
|
|
// termination during cleanup, while "dying" is any unexpected
|
|
// termination.)
|
|
static void OnOpenVPNExited(const base::WeakPtr<DeviceInfo>& device_info,
|
|
int interface_index,
|
|
int exit_status);
|
|
|
|
// Inherit from VPNDriver to add custom properties.
|
|
KeyValueStore GetProvider(Error* error) override;
|
|
|
|
// Implements RPCTaskDelegate.
|
|
void GetLogin(std::string* user, std::string* password) override;
|
|
void Notify(const std::string& reason,
|
|
const std::map<std::string, std::string>& dict) override;
|
|
|
|
void OnDefaultServiceChanged(const ServiceRefPtr& service);
|
|
|
|
void ReportConnectionMetrics();
|
|
|
|
ControlInterface* control_;
|
|
Metrics* metrics_;
|
|
DeviceInfo* device_info_;
|
|
ProcessManager* process_manager_;
|
|
Sockets sockets_;
|
|
std::unique_ptr<OpenVPNManagementServer> management_server_;
|
|
std::unique_ptr<CertificateFile> certificate_file_;
|
|
std::unique_ptr<CertificateFile> extra_certificates_file_;
|
|
base::FilePath lsb_release_file_;
|
|
|
|
VPNServiceRefPtr service_;
|
|
std::unique_ptr<RPCTask> rpc_task_;
|
|
std::string tunnel_interface_;
|
|
VirtualDeviceRefPtr device_;
|
|
base::FilePath tls_auth_file_;
|
|
base::FilePath openvpn_config_directory_;
|
|
base::FilePath openvpn_config_file_;
|
|
IPConfig::Properties ip_properties_;
|
|
|
|
// The PID of the spawned openvpn process. May be 0 if no process has been
|
|
// spawned yet or the process has died.
|
|
int pid_;
|
|
|
|
// Default service watch callback tag.
|
|
int default_service_callback_tag_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(OpenVPNDriver);
|
|
};
|
|
|
|
} // namespace shill
|
|
|
|
#endif // SHILL_VPN_OPENVPN_DRIVER_H_
|