mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-02-11 00:00:08 +08:00
173 lines
5.7 KiB
C++
173 lines
5.7 KiB
C++
// OpenVPN -- An application to securely tunnel IP networks
|
|
// over a single port, with support for SSL/TLS-based
|
|
// session authentication and key exchange,
|
|
// packet encryption, packet authentication, and
|
|
// packet compression.
|
|
//
|
|
// Copyright (C) 2012-2017 OpenVPN Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
|
// as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program in the COPYING file.
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <Windows.h>
|
|
|
|
#include <string>
|
|
#include <type_traits>
|
|
|
|
#include <openvpn/buffer/bufhex.hpp>
|
|
#include <openvpn/common/rc.hpp>
|
|
#include <openvpn/win/scoped_handle.hpp>
|
|
#include <openvpn/win/event.hpp>
|
|
|
|
#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
|
|
#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
|
|
|
|
#define WINTUN_RING_CAPACITY 0x800000
|
|
#define WINTUN_RING_TRAILING_BYTES 0x10000
|
|
#define WINTUN_RING_FRAMING_SIZE 12
|
|
#define WINTUN_MAX_PACKET_SIZE 0xffff
|
|
#define WINTUN_PACKET_ALIGN 4
|
|
|
|
namespace openvpn
|
|
{
|
|
namespace TunWin
|
|
{
|
|
struct TUN_RING {
|
|
std::atomic_ulong head;
|
|
std::atomic_ulong tail;
|
|
std::atomic_long alertable;
|
|
UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES + WINTUN_RING_FRAMING_SIZE];
|
|
};
|
|
|
|
struct TUN_REGISTER_RINGS
|
|
{
|
|
struct
|
|
{
|
|
ULONG ring_size;
|
|
TUN_RING* ring;
|
|
HANDLE tail_moved;
|
|
} send, receive;
|
|
};
|
|
|
|
typedef openvpn_io::windows::object_handle AsioEvent;
|
|
|
|
class RingBuffer : public RC<thread_unsafe_refcount>
|
|
{
|
|
public:
|
|
typedef RCPtr<RingBuffer> Ptr;
|
|
|
|
RingBuffer(openvpn_io::io_context& io_context)
|
|
: send_ring_hmem(CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TUN_RING), NULL)),
|
|
receive_ring_hmem(CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TUN_RING), NULL)),
|
|
send_tail_moved_asio_event_(io_context)
|
|
{
|
|
// sanity checks
|
|
static_assert((sizeof(TUN_RING) - sizeof(TUN_RING::data)) == 12, "sizeof(TUN_RING) is expected to be 12");
|
|
#if !defined(ATOMIC_LONG_LOCK_FREE) || (ATOMIC_LONG_LOCK_FREE != 2)
|
|
#error Atomic long is expected to be always lock-free
|
|
#endif
|
|
|
|
send_ring_ = (TUN_RING*)MapViewOfFile(send_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
|
|
receive_ring_ = (TUN_RING*)MapViewOfFile(receive_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
|
|
send_tail_moved_asio_event_.assign(send_ring_tail_moved_());
|
|
}
|
|
|
|
RingBuffer(openvpn_io::io_context& io_context,
|
|
HANDLE client_process,
|
|
const std::string& send_ring_hmem_hex,
|
|
const std::string& receive_ring_hmem_hex,
|
|
const std::string& send_ring_tail_moved_hex,
|
|
const std::string& receive_ring_tail_moved_hex)
|
|
: send_tail_moved_asio_event_(io_context)
|
|
{
|
|
HANDLE remote_handle = BufHex::parse<HANDLE>(send_ring_hmem_hex, "send_ring_hmem");
|
|
HANDLE handle;
|
|
DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
send_ring_hmem.reset(handle);
|
|
|
|
remote_handle = BufHex::parse<HANDLE>(receive_ring_hmem_hex, "receive_ring_hmem");
|
|
DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
receive_ring_hmem.reset(handle);
|
|
|
|
remote_handle = BufHex::parse<HANDLE>(send_ring_tail_moved_hex, "send_ring_tail_moved");
|
|
DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
send_ring_tail_moved_.reset(handle);
|
|
|
|
remote_handle = BufHex::parse<HANDLE>(receive_ring_tail_moved_hex, "receive_ring_tail_moved");
|
|
DuplicateHandle(client_process, remote_handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
receive_ring_tail_moved_.reset(handle);
|
|
|
|
send_ring_ = (TUN_RING*)MapViewOfFile(send_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
|
|
receive_ring_ = (TUN_RING*)MapViewOfFile(receive_ring_hmem(), FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TUN_RING));
|
|
}
|
|
|
|
RingBuffer(RingBuffer const&) = delete;
|
|
RingBuffer& operator=(RingBuffer const&) = delete;
|
|
|
|
~RingBuffer()
|
|
{
|
|
UnmapViewOfFile(send_ring_);
|
|
UnmapViewOfFile(receive_ring_);
|
|
}
|
|
|
|
HANDLE send_ring_tail_moved()
|
|
{
|
|
return send_ring_tail_moved_();
|
|
}
|
|
|
|
HANDLE receive_ring_tail_moved()
|
|
{
|
|
return receive_ring_tail_moved_();
|
|
}
|
|
|
|
TUN_RING* send_ring()
|
|
{
|
|
return send_ring_;
|
|
}
|
|
|
|
TUN_RING* receive_ring()
|
|
{
|
|
return receive_ring_;
|
|
}
|
|
|
|
AsioEvent& send_tail_moved_asio_event()
|
|
{
|
|
return send_tail_moved_asio_event_;
|
|
}
|
|
|
|
#ifdef HAVE_JSON
|
|
void serialize(Json::Value& json)
|
|
{
|
|
json["send_ring_hmem"] = BufHex::render(send_ring_hmem());
|
|
json["receive_ring_hmem"] = BufHex::render(receive_ring_hmem());
|
|
json["send_ring_tail_moved"] = BufHex::render(send_ring_tail_moved());
|
|
json["receive_ring_tail_moved"] = BufHex::render(receive_ring_tail_moved());
|
|
}
|
|
#endif
|
|
|
|
protected:
|
|
Win::ScopedHANDLE send_ring_hmem;
|
|
Win::ScopedHANDLE receive_ring_hmem;
|
|
Win::Event send_ring_tail_moved_{FALSE};
|
|
Win::Event receive_ring_tail_moved_{FALSE};
|
|
AsioEvent send_tail_moved_asio_event_;
|
|
|
|
TUN_RING* send_ring_ = nullptr;
|
|
TUN_RING* receive_ring_ = nullptr;
|
|
};
|
|
}
|
|
}
|