| // Copyright 2018 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. |
| |
| #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 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); |
| |
| // Appends remote option to the |options| array. |
| void AppendRemoteOption(const std::string& host, |
| 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, GetCommandLineArgs); |
| 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, InitOptionsHostWithExtraHosts); |
| FRIEND_TEST(OpenVPNDriverTest, InitOptionsHostWithPort); |
| FRIEND_TEST(OpenVPNDriverTest, InitOptionsNoHost); |
| FRIEND_TEST(OpenVPNDriverTest, InitOptionsNoPrimaryHost); |
| 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, ParseForeignOption); |
| FRIEND_TEST(OpenVPNDriverTest, ParseForeignOptions); |
| FRIEND_TEST(OpenVPNDriverTest, ParseIPConfiguration); |
| FRIEND_TEST(OpenVPNDriverTest, ParseRouteOption); |
| FRIEND_TEST(OpenVPNDriverTest, SetRoutes); |
| FRIEND_TEST(OpenVPNDriverTest, SpawnOpenVPN); |
| FRIEND_TEST(OpenVPNDriverTest, SpawnOpenVPNInMinijail); |
| FRIEND_TEST(OpenVPNDriverTest, SplitPortFromHost); |
| FRIEND_TEST(OpenVPNDriverTest, WriteConfigFile); |
| |
| // The map is a sorted container that allows us to iterate through the options |
| // in order. |
| using ForeignOptions = std::map<int, std::string>; |
| using RouteOptions = std::map<int, IPConfig::Route>; |
| |
| 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::vector<std::string> GetCommandLineArgs(); |
| 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); |
| |
| // 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 OnDefaultServiceStateChanged(const ServiceRefPtr& service) override; |
| |
| 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_; |
| |
| // Helps distinguish between a network->network transition (where the |
| // client simply reconnects), and a network->link_down->network transition |
| // (where the client should disconnect, wait for link up, then reconnect). |
| bool link_down_; |
| |
| DISALLOW_COPY_AND_ASSIGN(OpenVPNDriver); |
| }; |
| |
| } // namespace shill |
| |
| #endif // SHILL_VPN_OPENVPN_DRIVER_H_ |