blob: bbeb0c98654e83da1c98cd5ee9a0d7284782ec15 [file] [log] [blame]
// Copyright 2021 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_WIREGUARD_DRIVER_H_
#define SHILL_VPN_WIREGUARD_DRIVER_H_
#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/metrics.h"
#include "shill/vpn/vpn_driver.h"
#include "shill/vpn/vpn_util.h"
namespace shill {
class WireGuardDriver : public VPNDriver {
public:
WireGuardDriver(Manager* manager, ProcessManager* process_manager);
WireGuardDriver(const WireGuardDriver&) = delete;
WireGuardDriver& operator=(const WireGuardDriver&) = delete;
~WireGuardDriver();
// Inherited from VPNDriver. During ConnectAsync(), we will try to create the
// tunnel in the kernel at first. If that fails, then we will try to let the
// userspace program open the tunnel.
base::TimeDelta ConnectAsync(EventHandler* event_handler) override;
void Disconnect() override;
void OnConnectTimeout() override;
IPConfig::Properties GetIPProperties() const override;
std::string GetProviderType() const override;
// These functions (including GetProvider() below) are overridden for
// implementing the "WireGuard.Peers" property in both property store (as an
// array of dicts) and storage (as an an array of json-encoded strings), and
// its value is kept in |peers_| in this class. A special property in a peer
// is "PresharedKey": this property cannot be read via RPC, so we need some
// special handling during writing. Specifically, in a RPC call for setting
// "WireGuard.Peers", the preshared key of a peer will not be cleared if the
// client does not specify a value for it (i.e., the incoming request does not
// contain this key).
void InitPropertyStore(PropertyStore* store) override;
bool Load(const StoreInterface* storage,
const std::string& storage_id) override;
// Save() will also trigger the key-pair generation if the private key is
// empty. Given that Save() will always be called after any property changes
// by Manager::ConfigureService*(), this guarantees that there will always be
// a valid key pair in the service.
// TODO(b/177877860): May need to change this logic when hardware-backed keys
// come, especially when the service is switching between these two key types.
bool Save(StoreInterface* storage,
const std::string& storage_id,
bool save_credentials) override;
// Resets credential fields (PrivateKey and PresharedKey) from the service.
void UnloadCredentials() override;
static bool IsSupported();
protected:
KeyValueStore GetProvider(Error* error) override;
private:
// Friend class for testing.
friend class WireGuardDriverTestPeer;
static const VPNDriver::Property kProperties[];
void CreateKernelWireGuardInterface();
void StartUserspaceWireGuardTunnel();
// Spawns the userspace wireguard process, which will setup the tunnel
// interface and do the data tunneling. WireGuardProcessExited() will be
// invoked if that process exits unexpectedly.
bool SpawnWireGuard();
void WireGuardProcessExited(int exit_code);
// Generates a config file that will be used by wireguard-tools from the
// profile and write its content into a temporary file. Writes the path to the
// temporary file into |config_file_|;
bool GenerateConfigFile();
// Configures the interface via wireguard-tools when the interface is ready.
void ConfigureInterface(bool created_in_kernel,
const std::string& interface_name,
int interface_index);
void OnConfigurationDone(int exit_code);
// Fills in |ip_properties_| (especially, the address and routes fields)
// according to the properties in the profile.
bool PopulateIPProperties();
// Calls Cleanup(), and if there is a service associated through
// ConnectAsync(), notifies it of the failure.
void FailService(Service::ConnectFailure failure,
const std::string& error_details);
// Resets states and deallocate all resources.
void Cleanup();
bool UpdatePeers(const Stringmaps& new_peers, Error* error);
void ClearPeers(Error* error);
void ReportConnectionMetrics();
Stringmaps peers_;
EventHandler* event_handler_;
pid_t wireguard_pid_ = -1;
int interface_index_ = -1;
IPConfig::Properties ip_properties_;
base::FilePath config_file_;
// Indicates that whether we have an open wg interface in the kernel which is
// created via DeviceInfo now.
bool kernel_interface_open_ = false;
// This variable is set in Load() and Save(), and only used to check whether
// we need to re-calculate the public key in Save().
std::string saved_private_key_;
// |config_directory_| is a constant. Makes it a member variable for testing.
base::FilePath config_directory_;
// Indicates where the key pair associated with this service comes from.
// Currently only used in the UMA metrics.
Metrics::VpnWireGuardKeyPairSource key_pair_source_;
std::unique_ptr<VPNUtil> vpn_util_;
base::WeakPtrFactory<WireGuardDriver> weak_factory_{this};
};
} // namespace shill
#endif // SHILL_VPN_WIREGUARD_DRIVER_H_