// // 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_