blob: c923c13ee4fa3a5da959220a942c45e522d49352 [file] [log] [blame] [edit]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHILL_VPN_OPENVPN_MANAGEMENT_SERVER_H_
#define SHILL_VPN_OPENVPN_MANAGEMENT_SERVER_H_
#include <memory>
#include <string>
#include <vector>
#include <base/containers/span.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include <net-base/socket.h>
#include "shill/mockable.h"
namespace shill {
class OpenVPNDriver;
class OpenVPNManagementServer {
public:
static constexpr char kStateAuth[] = "AUTH";
static constexpr char kStateConnected[] = "CONNECTED";
static constexpr char kStateReconnecting[] = "RECONNECTING";
static constexpr char kStateResolve[] = "RESOLVE";
explicit OpenVPNManagementServer(OpenVPNDriver* driver);
OpenVPNManagementServer(const OpenVPNManagementServer&) = delete;
OpenVPNManagementServer& operator=(const OpenVPNManagementServer&) = delete;
virtual ~OpenVPNManagementServer();
// Returns false on failure. On success, returns true and appends management
// interface openvpn options to |options|.
virtual bool Start(std::vector<std::vector<std::string>>* options);
virtual void Stop();
// Releases openvpn's hold if it's waiting for a hold release (i.e., if
// |hold_waiting_| is true). Otherwise, sets |hold_release_| to true
// indicating that the hold can be released as soon as openvpn requests.
virtual void ReleaseHold();
// Holds openvpn so that it doesn't connect or reconnect automatically (i.e.,
// sets |hold_release_| to false). Note that this method neither drops an
// existing connection, nor sends any commands to the openvpn client.
virtual void Hold();
// Restarts openvpn causing a disconnect followed by a reconnect attempt.
virtual void Restart();
// OpenVPN client state.
const std::string& state() const { return state_; }
// If Start() was called and no Stop() after that.
mockable bool IsStarted() const { return socket_ != nullptr; }
private:
friend class OpenVPNDriverTest;
friend class OpenVPNManagementServerFuzzer;
friend class OpenVPNManagementServerTest;
FRIEND_TEST(OpenVPNManagementServerTest, EscapeToQuote);
FRIEND_TEST(OpenVPNManagementServerTest, Hold);
FRIEND_TEST(OpenVPNManagementServerTest, OnInputStop);
FRIEND_TEST(OpenVPNManagementServerTest, OnSocketConnected);
FRIEND_TEST(OpenVPNManagementServerTest, OnReadyAcceptFail);
FRIEND_TEST(OpenVPNManagementServerTest, PerformAuthentication);
FRIEND_TEST(OpenVPNManagementServerTest, PerformAuthenticationNoCreds);
FRIEND_TEST(OpenVPNManagementServerTest, PerformStaticChallengeNoCreds);
FRIEND_TEST(OpenVPNManagementServerTest, PerformStaticChallengeOTP);
FRIEND_TEST(OpenVPNManagementServerTest, PerformStaticChallengeToken);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessFailedPasswordMessage);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessHoldMessage);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessInfoMessage);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuth);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuthSC);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageTPMToken);
FRIEND_TEST(OpenVPNManagementServerTest, ProcessNeedPasswordMessageUnknown);
FRIEND_TEST(OpenVPNManagementServerTest, Send);
FRIEND_TEST(OpenVPNManagementServerTest, SendHoldRelease);
FRIEND_TEST(OpenVPNManagementServerTest, SendPassword);
FRIEND_TEST(OpenVPNManagementServerTest, SendPasswordWithSpecialCharacters);
FRIEND_TEST(OpenVPNManagementServerTest, SendState);
FRIEND_TEST(OpenVPNManagementServerTest, SendUsername);
FRIEND_TEST(OpenVPNManagementServerTest, SendUsernameWithSpecialCharacters);
FRIEND_TEST(OpenVPNManagementServerTest, Start);
FRIEND_TEST(OpenVPNManagementServerTest, Stop);
FRIEND_TEST(OpenVPNManagementServerTest, SupplyTPMToken);
FRIEND_TEST(OpenVPNManagementServerTest, SupplyTPMTokenNoPin);
// Called when |socket_| is ready to accept a connection.
void OnAcceptReady();
// Called when |connected_socket_| is ready to read.
void OnInputReady();
void OnInput(base::span<const uint8_t> data);
void Send(std::string_view data);
void SendState(std::string_view state);
void SendUsername(std::string_view tag, std::string_view username);
void SendPassword(std::string_view tag, std::string_view password);
void SendHoldRelease();
void SendSignal(std::string_view signal);
void SendStatus();
void ProcessMessage(std::string_view message);
bool ProcessInfoMessage(std::string_view message);
bool ProcessNeedPasswordMessage(std::string_view message);
bool ProcessFailedPasswordMessage(std::string_view message);
bool ProcessAuthTokenMessage(std::string_view message);
bool ProcessStateMessage(std::string_view message);
bool ProcessHoldMessage(std::string_view message);
bool ProcessSuccessMessage(std::string_view message);
bool ProcessStatusMessage(std::string_view message);
void PerformStaticChallenge(std::string_view tag);
void PerformAuthentication(std::string_view tag);
void SupplyTPMToken(std::string_view tag);
// Returns the first substring in |message| enclosed by the |start| and |end|
// substrings. Note that the first |end| substring after the position of
// |start| is matched.
static std::string_view ParseSubstring(std::string_view message,
std::string_view start,
std::string_view end);
// Password messages come in two forms:
//
// >PASSWORD:Need 'AUTH_TYPE' ...
// >PASSWORD:Verification Failed: 'AUTH_TYPE' ['REASON_STRING']
//
// ParsePasswordTag parses AUTH_TYPE out of a password |message| and returns
// it. ParsePasswordFailedReason parses REASON_STRING, if any, out of a
// password |message| and returns it.
static std::string_view ParsePasswordTag(std::string_view message);
static std::string_view ParsePasswordFailedReason(std::string_view message);
// Escapes |str| per OpenVPN's command parsing rules assuming |str| will be
// sent over the management interface quoted (i.e., whitespace is not
// escaped).
static std::string EscapeToQuote(std::string_view str);
OpenVPNDriver* driver_;
std::unique_ptr<net_base::SocketFactory> socket_factory_ =
std::make_unique<net_base::SocketFactory>();
std::unique_ptr<net_base::Socket> socket_;
std::unique_ptr<net_base::Socket> connected_socket_;
std::string state_;
bool hold_waiting_;
bool hold_release_;
};
} // namespace shill
#endif // SHILL_VPN_OPENVPN_MANAGEMENT_SERVER_H_