| // 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. |
| |
| #include "shill/vpn/wireguard_driver.h" |
| |
| #include <map> |
| #include <memory> |
| #include <utility> |
| |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/files/file_util.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <gtest/gtest.h> |
| |
| #include "shill/fake_store.h" |
| #include "shill/metrics.h" |
| #include "shill/mock_control.h" |
| #include "shill/mock_device_info.h" |
| #include "shill/mock_manager.h" |
| #include "shill/mock_metrics.h" |
| #include "shill/mock_process_manager.h" |
| #include "shill/property_store.h" |
| #include "shill/test_event_dispatcher.h" |
| #include "shill/vpn/fake_vpn_util.h" |
| #include "shill/vpn/mock_vpn_driver.h" |
| |
| namespace shill { |
| |
| using testing::_; |
| using testing::DoAll; |
| using testing::HasSubstr; |
| using testing::Mock; |
| using testing::NiceMock; |
| using testing::Not; |
| using testing::Return; |
| using testing::SaveArg; |
| |
| // Expose necessary private members of WireGuardDriver for testing. |
| class WireGuardDriverTestPeer { |
| public: |
| explicit WireGuardDriverTestPeer(WireGuardDriver* driver) : driver_(driver) { |
| // Creates a temp directory for storing the config file. |
| CHECK(scoped_temp_dir_.CreateUniqueTempDir()); |
| driver_->config_directory_ = scoped_temp_dir_.GetPath(); |
| |
| driver->vpn_util_ = std::make_unique<FakeVPNUtil>(); |
| } |
| |
| const Stringmaps& peers() { return driver_->peers_; } |
| |
| private: |
| std::unique_ptr<WireGuardDriver> driver_; |
| base::ScopedTempDir scoped_temp_dir_; |
| }; |
| |
| // This function should exist outside the anonymous namespace, otherwise it |
| // cannot be found by the gmock framework. |
| bool operator==(const IPConfig::Route& lhs, const IPConfig::Route& rhs) { |
| return lhs.host == rhs.host && lhs.prefix == rhs.prefix && |
| lhs.gateway == rhs.gateway; |
| } |
| |
| namespace { |
| |
| constexpr pid_t kWireGuardPid = 12345; |
| constexpr pid_t kWireGuardToolsPid = 12346; |
| const char kIfName[] = "wg0"; |
| constexpr int kIfIndex = 123; |
| |
| // Randomly generated key for testing. |
| constexpr char kPrivateKey1[] = "gOL/kVF88Mdr7rVM2Fz91UgyAW4L8iYogU/M+9hlKmM="; |
| constexpr char kPrivateKey2[] = "wARBVZOPBWo7OoyHLfv2mDgFxYJ3S6uc9lIOpRiGqVI="; |
| |
| // Consistent with the properties set in |
| // WireGuardDriverTest::InitializePropertyStore(). |
| const char kExpectedConfigFileContents[] = R"([Interface] |
| PrivateKey=gOL/kVF88Mdr7rVM2Fz91UgyAW4L8iYogU/M+9hlKmM= |
| FwMark=0x4500 |
| |
| [Peer] |
| PublicKey=public-key-1 |
| PresharedKey=preshared-key-1 |
| Endpoint=10.0.1.1:12345 |
| AllowedIPs=192.168.1.2/32,192.168.2.0/24 |
| PersistentKeepalive=10 |
| |
| [Peer] |
| PublicKey=public-key-2 |
| Endpoint=10.0.1.2:12345 |
| AllowedIPs=192.168.1.2/32,192.168.3.0/24 |
| )"; |
| |
| class WireGuardDriverTest : public testing::Test { |
| public: |
| WireGuardDriverTest() |
| : manager_(&control_, &dispatcher_, &metrics_), device_info_(&manager_) { |
| ResetDriver(); |
| manager_.set_mock_device_info(&device_info_); |
| SetFakeKeyGenerator(); |
| } |
| |
| protected: |
| // Useful in storage-related tests. |
| void ResetDriver() { |
| driver_ = new WireGuardDriver(&manager_, &process_manager_); |
| driver_test_peer_.reset(new WireGuardDriverTestPeer(driver_)); |
| property_store_.reset(new PropertyStore()); |
| driver_->InitPropertyStore(property_store_.get()); |
| } |
| |
| void InitializePropertyStore() { |
| Error err; |
| property_store_->SetStringProperty(kWireGuardPrivateKey, kPrivateKey1, |
| &err); |
| property_store_->SetStringmapsProperty( |
| kWireGuardPeers, |
| { |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPresharedKey, "preshared-key-1"}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, "public-key-2"}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| }, |
| &err); |
| } |
| |
| // Whenever the driver asks for calculating a public key, just echoes the |
| // input back. |
| // TODO(jiejiang): Consider returning a different key to avoid missing the |
| // failure that keys are misused. |
| void SetFakeKeyGenerator() { |
| EXPECT_CALL(process_manager_, StartProcessInMinijailWithPipes( |
| _, base::FilePath("/usr/bin/wg"), |
| std::vector<std::string>{"pubkey"}, _, |
| "vpn", "vpn", 0, true, true, _, _)) |
| .WillRepeatedly([](const base::Location&, const base::FilePath&, |
| const std::vector<std::string>&, |
| const std::map<std::string, std::string>&, |
| const std::string&, const std::string&, uint64_t, |
| bool, bool, const base::Callback<void(int)>&, |
| struct std_file_descriptors std_fds) { |
| CHECK(std_fds.stdin_fd); |
| CHECK(std_fds.stdout_fd); |
| int echo_pipe[2]; |
| CHECK_EQ(pipe(echo_pipe), 0); |
| *std_fds.stdin_fd = echo_pipe[1]; |
| *std_fds.stdout_fd = echo_pipe[0]; |
| return 0; |
| }); |
| } |
| |
| void InvokeConnectAsyncKernel() { |
| driver_->ConnectAsync(&driver_event_handler_); |
| EXPECT_CALL(device_info_, CreateWireGuardInterface(kIfName, _, _)) |
| .WillOnce([this](const std::string&, |
| DeviceInfo::LinkReadyCallback link_ready_cb, |
| base::OnceClosure failure_cb) { |
| this->link_ready_callback_ = std::move(link_ready_cb); |
| this->create_kernel_link_failed_callback_ = std::move(failure_cb); |
| return true; |
| }); |
| dispatcher_.DispatchPendingEvents(); |
| } |
| |
| void InvokeConnectAsyncUserspace() { |
| driver_->ConnectAsync(&driver_event_handler_); |
| EXPECT_CALL(device_info_, CreateWireGuardInterface(kIfName, _, _)) |
| .WillOnce([this](const std::string&, |
| DeviceInfo::LinkReadyCallback link_ready_cb, |
| base::OnceClosure failure_cb) { |
| this->link_ready_callback_ = std::move(link_ready_cb); |
| this->create_kernel_link_failed_callback_ = std::move(failure_cb); |
| return true; |
| }); |
| EXPECT_CALL(device_info_, AddVirtualInterfaceReadyCallback(kIfName, _)) |
| .WillOnce([this](const std::string&, DeviceInfo::LinkReadyCallback cb) { |
| this->link_ready_callback_ = std::move(cb); |
| }); |
| EXPECT_CALL( |
| process_manager_, |
| StartProcessInMinijail(_, _, _, _, "vpn", "vpn", |
| CAP_TO_MASK(CAP_NET_ADMIN), true, true, _)) |
| .WillOnce(DoAll(SaveArg<9>(&wireguard_exit_callback_), |
| Return(kWireGuardPid))); |
| dispatcher_.DispatchPendingEvents(); |
| std::move(create_kernel_link_failed_callback_).Run(); |
| } |
| |
| void InvokeLinkReady() { |
| // wireguard-tools should be invoked on interface ready. |
| std::vector<std::string> args; |
| EXPECT_CALL(process_manager_, |
| StartProcessInMinijail(_, base::FilePath("/usr/bin/wg"), _, _, |
| "vpn", "vpn", CAP_TO_MASK(CAP_NET_ADMIN), |
| true, true, _)) |
| .WillOnce(DoAll(SaveArg<2>(&args), |
| SaveArg<9>(&wireguard_tools_exit_callback_), |
| Return(kWireGuardToolsPid))); |
| std::move(link_ready_callback_).Run(kIfName, kIfIndex); |
| |
| EXPECT_EQ(args[0], "setconf"); |
| EXPECT_EQ(args[1], kIfName); |
| config_file_path_ = base::FilePath(args[2]); |
| EXPECT_TRUE(base::PathExists(config_file_path_)); |
| } |
| |
| void ExpectCallMetrics(Metrics::VpnWireGuardKeyPairSource key_pair_source, |
| int peers_num, |
| Metrics::VpnWireGuardAllowedIPsType allowed_ips_type) { |
| EXPECT_CALL(metrics_, SendEnumToUMA(Metrics::kMetricVpnDriver, |
| Metrics::kVpnDriverWireGuard, _)); |
| EXPECT_CALL(metrics_, |
| SendEnumToUMA(Metrics::kMetricVpnWireGuardKeyPairSource, |
| key_pair_source, _)); |
| EXPECT_CALL(metrics_, SendToUMA(Metrics::kMetricVpnWireGuardPeersNum, |
| peers_num, _, _, _)); |
| EXPECT_CALL(metrics_, |
| SendEnumToUMA(Metrics::kMetricVpnWireGuardAllowedIPsType, |
| allowed_ips_type, _)); |
| } |
| |
| MockControl control_; |
| EventDispatcherForTest dispatcher_; |
| MockMetrics metrics_; |
| MockProcessManager process_manager_; |
| MockManager manager_; |
| NiceMock<MockDeviceInfo> device_info_; |
| FakeStore fake_store_; |
| std::unique_ptr<PropertyStore> property_store_; |
| MockVPNDriverEventHandler driver_event_handler_; |
| WireGuardDriver* driver_; // owned by driver_test_peer_ |
| std::unique_ptr<WireGuardDriverTestPeer> driver_test_peer_; |
| |
| base::RepeatingCallback<void(int)> wireguard_exit_callback_; |
| base::RepeatingCallback<void(int)> wireguard_tools_exit_callback_; |
| DeviceInfo::LinkReadyCallback link_ready_callback_; |
| base::OnceClosure create_kernel_link_failed_callback_; |
| base::FilePath config_file_path_; |
| }; |
| |
| TEST_F(WireGuardDriverTest, ConnectFlowKernel) { |
| InitializePropertyStore(); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| |
| // Configuration done. |
| EXPECT_CALL(driver_event_handler_, OnDriverConnected(kIfName, kIfIndex)); |
| wireguard_tools_exit_callback_.Run(0); |
| |
| // Checks config file content. |
| std::string contents; |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_EQ(contents, kExpectedConfigFileContents); |
| |
| // Checks IPProperties. |
| const auto& ip_properties = driver_->GetIPProperties(); |
| EXPECT_THAT(ip_properties.routes, |
| testing::UnorderedElementsAre( |
| // We do not dedup so this entry appears twice. |
| IPConfig::Route("192.168.1.2", 32, "0.0.0.0"), |
| IPConfig::Route("192.168.1.2", 32, "0.0.0.0"), |
| IPConfig::Route("192.168.2.0", 24, "0.0.0.0"), |
| IPConfig::Route("192.168.3.0", 24, "0.0.0.0"))); |
| |
| // Disconnect. |
| EXPECT_CALL(device_info_, DeleteInterface(kIfIndex)); |
| driver_->Disconnect(); |
| |
| // Checks that the config file has been deleted. |
| EXPECT_FALSE(base::PathExists(config_file_path_)); |
| } |
| |
| TEST_F(WireGuardDriverTest, ConnectFlowUserspace) { |
| InitializePropertyStore(); |
| InvokeConnectAsyncUserspace(); |
| InvokeLinkReady(); |
| |
| // Configuration done. |
| EXPECT_CALL(driver_event_handler_, OnDriverConnected(kIfName, kIfIndex)); |
| wireguard_tools_exit_callback_.Run(0); |
| |
| // Checks config file content. |
| std::string contents; |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_EQ(contents, kExpectedConfigFileContents); |
| |
| // Skips checks for IPProperties. See ConnectFlowKernel. |
| |
| // Disconnect. |
| EXPECT_CALL(process_manager_, StopProcess(kWireGuardPid)); |
| driver_->Disconnect(); |
| |
| // Checks that the config file has been deleted. |
| EXPECT_FALSE(base::PathExists(config_file_path_)); |
| } |
| |
| TEST_F(WireGuardDriverTest, WireGuardToolsFailed) { |
| InitializePropertyStore(); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| |
| // Configuration failed. |
| EXPECT_CALL(driver_event_handler_, OnDriverFailure(_, _)); |
| wireguard_tools_exit_callback_.Run(1); |
| |
| // Checks that the config file has been deleted. |
| EXPECT_FALSE(base::PathExists(config_file_path_)); |
| } |
| |
| TEST_F(WireGuardDriverTest, PropertyStoreAndConfigFile) { |
| std::string contents; |
| Error err; |
| InitializePropertyStore(); |
| |
| // Save & load should not lose any information. |
| const std::string kStorageId = "wireguard-test"; |
| driver_->Save(&fake_store_, kStorageId, /*save_credentials=*/true); |
| ResetDriver(); |
| driver_->Load(&fake_store_, kStorageId); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_EQ(contents, kExpectedConfigFileContents); |
| ExpectCallMetrics(Metrics::kVpnWireGuardKeyPairSourceUserInput, 2, |
| Metrics::kVpnWireGuardAllowedIPsTypeNoDefaultRoute); |
| wireguard_tools_exit_callback_.Run(0); |
| Mock::VerifyAndClearExpectations(&metrics_); |
| driver_->Disconnect(); |
| |
| // Checks reading properties. Private keys and preshared keys should not be |
| // readable. |
| KeyValueStore provider; |
| EXPECT_TRUE(property_store_->GetKeyValueStoreProperty(kProviderProperty, |
| &provider, &err)); |
| EXPECT_FALSE(provider.Contains<std::string>(kWireGuardPrivateKey)); |
| EXPECT_TRUE(provider.Contains<std::string>(kWireGuardPublicKey)); |
| EXPECT_EQ(provider.Get<Stringmaps>(kWireGuardPeers), |
| (Stringmaps{ |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, "public-key-2"}, |
| {kWireGuardPeerPersistentKeepalive, ""}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| })); |
| |
| // Setting peers without touching PresharedKey property should leave it |
| // unchanged. |
| property_store_->SetStringmapsProperty( |
| kWireGuardPeers, |
| { |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, "public-key-2"}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| }, |
| &err); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_EQ(contents, kExpectedConfigFileContents); |
| driver_->Disconnect(); |
| |
| // Setting peers with an empty PublicKey property should be rejected and the |
| // current peers will not be modified. |
| property_store_->SetStringmapsProperty( |
| kWireGuardPeers, |
| { |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, ""}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| }, |
| &err); |
| EXPECT_TRUE(err.IsFailure()); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_EQ(contents, kExpectedConfigFileContents); |
| driver_->Disconnect(); |
| |
| // Setting peers with a duplicated PublicKey property should be rejected and |
| // the current peers will not be modified. |
| property_store_->SetStringmapsProperty( |
| kWireGuardPeers, |
| { |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| }, |
| &err); |
| EXPECT_TRUE(err.IsFailure()); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_EQ(contents, kExpectedConfigFileContents); |
| driver_->Disconnect(); |
| |
| // Setting peers with an empty PresharedKey property should clear the |
| // PresharedKey of that peer. |
| property_store_->SetStringmapsProperty( |
| kWireGuardPeers, |
| { |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPresharedKey, ""}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, "public-key-2"}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| }, |
| &err); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| CHECK(base::ReadFileToString(config_file_path_, &contents)); |
| EXPECT_THAT(contents, Not(HasSubstr("PresharedKey="))); |
| |
| // Clears the private key, changes the number of peers, and add 0.0.0.0/0 as |
| // its allowed ips. The reported metrics should be changed. |
| property_store_->SetStringProperty(kWireGuardPrivateKey, "", &err); |
| property_store_->SetStringmapsProperty( |
| kWireGuardPeers, |
| { |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPresharedKey, ""}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "0.0.0.0/0"}}, |
| }, |
| &err); |
| driver_->Save(&fake_store_, kStorageId, /*save_credentials=*/true); |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| ExpectCallMetrics(Metrics::kVpnWireGuardKeyPairSourceSoftwareGenerated, 1, |
| Metrics::kVpnWireGuardAllowedIPsTypeHasDefaultRoute); |
| wireguard_tools_exit_callback_.Run(0); |
| Mock::VerifyAndClearExpectations(&metrics_); |
| } |
| |
| TEST_F(WireGuardDriverTest, UnloadCredentials) { |
| InitializePropertyStore(); |
| driver_->UnloadCredentials(); |
| const auto args = driver_->const_args(); |
| EXPECT_FALSE(args->Contains<std::string>(kWireGuardPrivateKey)); |
| EXPECT_EQ(driver_test_peer_->peers(), |
| (Stringmaps{ |
| {{kWireGuardPeerPublicKey, "public-key-1"}, |
| {kWireGuardPeerPresharedKey, ""}, |
| {kWireGuardPeerPersistentKeepalive, "10"}, |
| {kWireGuardPeerEndpoint, "10.0.1.1:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.2.0/24"}}, |
| {{kWireGuardPeerPublicKey, "public-key-2"}, |
| {kWireGuardPeerPresharedKey, ""}, |
| {kWireGuardPeerEndpoint, "10.0.1.2:12345"}, |
| {kWireGuardPeerAllowedIPs, "192.168.1.2/32,192.168.3.0/24"}}, |
| })); |
| } |
| |
| TEST_F(WireGuardDriverTest, KeyPairGeneration) { |
| Error err; |
| const std::string kStorageId = "wireguard-test"; |
| |
| auto assert_pubkey_is = [&](const std::string& key) { |
| KeyValueStore provider; |
| ASSERT_TRUE(property_store_->GetKeyValueStoreProperty(kProviderProperty, |
| &provider, &err)); |
| ASSERT_EQ(provider.Get<std::string>(kWireGuardPublicKey), key); |
| }; |
| auto assert_pubkey_not_empty = [&]() { |
| KeyValueStore provider; |
| ASSERT_TRUE(property_store_->GetKeyValueStoreProperty(kProviderProperty, |
| &provider, &err)); |
| ASSERT_FALSE(provider.Get<std::string>(kWireGuardPublicKey).empty()); |
| }; |
| |
| driver_->Save(&fake_store_, kStorageId, /*save_credentials=*/true); |
| assert_pubkey_not_empty(); |
| |
| ResetDriver(); |
| driver_->Load(&fake_store_, kStorageId); |
| assert_pubkey_not_empty(); |
| |
| property_store_->SetStringProperty(kWireGuardPrivateKey, kPrivateKey1, &err); |
| driver_->Save(&fake_store_, kStorageId, /*save_credentials=*/true); |
| assert_pubkey_is(kPrivateKey1); |
| |
| property_store_->SetStringProperty(kWireGuardPrivateKey, "", &err); |
| driver_->Save(&fake_store_, kStorageId, /*save_credentials=*/true); |
| assert_pubkey_not_empty(); |
| |
| property_store_->SetStringProperty(kWireGuardPrivateKey, kPrivateKey2, &err); |
| driver_->Save(&fake_store_, kStorageId, /*save_credentials=*/true); |
| assert_pubkey_is(kPrivateKey2); |
| } |
| |
| TEST_F(WireGuardDriverTest, SpawnWireGuardProcessFailed) { |
| driver_->ConnectAsync(&driver_event_handler_); |
| EXPECT_CALL(device_info_, CreateWireGuardInterface(kIfName, _, _)) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(process_manager_, |
| StartProcessInMinijail(_, _, _, _, _, _, _, _, _, _)) |
| .WillOnce(Return(-1)); |
| EXPECT_CALL(driver_event_handler_, OnDriverFailure(_, _)); |
| dispatcher_.DispatchPendingEvents(); |
| } |
| |
| TEST_F(WireGuardDriverTest, WireGuardProcessExitedUnexpectedly) { |
| InvokeConnectAsyncUserspace(); |
| EXPECT_CALL(driver_event_handler_, OnDriverFailure(_, _)); |
| wireguard_exit_callback_.Run(1); |
| } |
| |
| // Checks interface cleanup on timeout. |
| TEST_F(WireGuardDriverTest, OnConnectTimeout) { |
| InitializePropertyStore(); |
| |
| // Link is not created. |
| InvokeConnectAsyncKernel(); |
| EXPECT_CALL(driver_event_handler_, OnDriverFailure(_, _)); |
| driver_->OnConnectTimeout(); |
| |
| // Link is created by kernel. |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| EXPECT_CALL(driver_event_handler_, OnDriverFailure(_, _)); |
| EXPECT_CALL(device_info_, DeleteInterface(kIfIndex)); |
| driver_->OnConnectTimeout(); |
| |
| // Link is created by userspace process. |
| InvokeConnectAsyncUserspace(); |
| InvokeLinkReady(); |
| EXPECT_CALL(driver_event_handler_, OnDriverFailure(_, _)); |
| EXPECT_CALL(process_manager_, StopProcess(kWireGuardPid)); |
| driver_->OnConnectTimeout(); |
| } |
| |
| // Checks interface cleanup on disconnect before connected. Different with |
| // OnConnectTimeout, disconnect will not trigger an OnDriverFailure callback. |
| TEST_F(WireGuardDriverTest, DisconnectBeforeConnected) { |
| InitializePropertyStore(); |
| |
| // Link is not created. |
| InvokeConnectAsyncKernel(); |
| driver_->Disconnect(); |
| |
| // Link is created by kernel. |
| InvokeConnectAsyncKernel(); |
| InvokeLinkReady(); |
| EXPECT_CALL(device_info_, DeleteInterface(kIfIndex)); |
| driver_->Disconnect(); |
| |
| // Link is created by userspace process. |
| InvokeConnectAsyncUserspace(); |
| InvokeLinkReady(); |
| EXPECT_CALL(process_manager_, StopProcess(kWireGuardPid)); |
| driver_->OnConnectTimeout(); |
| } |
| |
| } // namespace |
| } // namespace shill |