mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 04:02:15 +02:00
wintun: support for privilege separation
This allows to run openvpn under normal user account, in which case ring buffers registration is performed by a separate privileged process. Signed-off-by: Lev Stipakov <lev@openvpn.net>
This commit is contained in:
parent
6f266be3d8
commit
48f2b5100b
108
openvpn/common/event.hpp
Normal file
108
openvpn/common/event.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
#ifndef OPENVPN_WIN_EVENT_H
|
||||
#define OPENVPN_WIN_EVENT_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <openvpn/buffer/bufhex.hpp>
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
#include <openvpn/win/scoped_handle.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Win {
|
||||
|
||||
// Wrap a standard Windows Event object
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
Event()
|
||||
{
|
||||
event.reset(::CreateEvent(NULL, TRUE, FALSE, NULL));
|
||||
if (!event.defined())
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_THROW_EXCEPTION("Win::Event: cannot create Windows event: " << err.message());
|
||||
}
|
||||
}
|
||||
|
||||
std::string duplicate_local()
|
||||
{
|
||||
HANDLE new_handle;
|
||||
if (!::DuplicateHandle(GetCurrentProcess(),
|
||||
event(),
|
||||
GetCurrentProcess(),
|
||||
&new_handle,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_THROW_EXCEPTION("Win::Event: DuplicateHandle failed: " << err.message());
|
||||
}
|
||||
return BufHex::render(new_handle);
|
||||
}
|
||||
|
||||
void signal_event()
|
||||
{
|
||||
if (event.defined())
|
||||
{
|
||||
::SetEvent(event());
|
||||
event.close();
|
||||
}
|
||||
}
|
||||
|
||||
void release_event()
|
||||
{
|
||||
event.close();
|
||||
}
|
||||
|
||||
HANDLE operator()() const
|
||||
{
|
||||
return event();
|
||||
}
|
||||
|
||||
void reset(HANDLE h)
|
||||
{
|
||||
event.reset(h);
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedHANDLE event;
|
||||
};
|
||||
|
||||
// Windows event object that automatically signals in the destructor
|
||||
struct DestroyEvent : public Event
|
||||
{
|
||||
~DestroyEvent()
|
||||
{
|
||||
signal_event();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -31,7 +31,7 @@ namespace openvpn {
|
||||
|
||||
// TunPersistTemplate adds persistence capabilities onto TunWrapTemplate,
|
||||
// in order to implement logic for the persist-tun directive.
|
||||
template <typename SCOPED_OBJ>
|
||||
template <typename SCOPED_OBJ, typename STATE=TunProp::State::Ptr>
|
||||
class TunPersistTemplate : public TunWrapTemplate<SCOPED_OBJ>
|
||||
{
|
||||
public:
|
||||
@ -47,7 +47,7 @@ namespace openvpn {
|
||||
}
|
||||
|
||||
// Current persisted state
|
||||
const TunProp::State::Ptr& state() const
|
||||
const STATE& state() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
@ -124,7 +124,7 @@ namespace openvpn {
|
||||
|
||||
// Possibly save tunnel fd/handle, state, and options.
|
||||
bool persist_tun_state(const typename SCOPED_OBJ::base_type obj,
|
||||
const TunProp::State::Ptr& state)
|
||||
const STATE& state)
|
||||
{
|
||||
if (!enable_persistence_ || !use_persisted_tun_)
|
||||
{
|
||||
@ -151,7 +151,7 @@ namespace openvpn {
|
||||
|
||||
const bool enable_persistence_;
|
||||
TunBuilderBase * const tb_;
|
||||
TunProp::State::Ptr state_;
|
||||
STATE state_;
|
||||
std::string options_;
|
||||
|
||||
TunBuilderCapture::Ptr copt_;
|
||||
|
@ -34,7 +34,17 @@ namespace openvpn {
|
||||
// These types manage the underlying TAP driver HANDLE
|
||||
typedef openvpn_io::windows::stream_handle TAPStream;
|
||||
typedef ScopedAsioStream<TAPStream> ScopedTAPStream;
|
||||
typedef TunPersistTemplate<ScopedTAPStream> TunPersist;
|
||||
struct TunPersistState {
|
||||
TunProp::State::Ptr state;
|
||||
RingBuffer::Ptr ring_buffer;
|
||||
|
||||
void reset()
|
||||
{
|
||||
state.reset();
|
||||
ring_buffer.reset();
|
||||
}
|
||||
};
|
||||
typedef TunPersistTemplate<ScopedTAPStream, TunPersistState> TunPersist;
|
||||
|
||||
class ClientConfig : public TunClientFactory
|
||||
{
|
||||
|
@ -33,8 +33,11 @@
|
||||
|
||||
#include <openvpn/common/destruct.hpp>
|
||||
#include <openvpn/common/stop.hpp>
|
||||
#include <openvpn/common/event.hpp>
|
||||
#include <openvpn/tun/builder/capture.hpp>
|
||||
|
||||
#include <openvpn/tun/win/ringbuffer.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
struct SetupBase : public DestructorBase
|
||||
@ -46,7 +49,8 @@ namespace openvpn {
|
||||
virtual HANDLE establish(const TunBuilderCapture& pull,
|
||||
const std::wstring& openvpn_app_path,
|
||||
Stop* stop,
|
||||
std::ostream& os) = 0;
|
||||
std::ostream& os,
|
||||
RingBuffer::Ptr rings) = 0;
|
||||
|
||||
virtual bool l2_ready(const TunBuilderCapture& pull) = 0;
|
||||
|
||||
|
@ -104,7 +104,7 @@ namespace openvpn {
|
||||
// Check if persisted tun session matches properties of to-be-created session
|
||||
if (tun_persist->use_persisted_tun(server_addr, config->tun_prop, opt))
|
||||
{
|
||||
state = tun_persist->state();
|
||||
state = tun_persist->state().state;
|
||||
OPENVPN_LOG("TunPersist: reused tun context");
|
||||
}
|
||||
else
|
||||
@ -135,14 +135,14 @@ namespace openvpn {
|
||||
{
|
||||
std::ostringstream os;
|
||||
auto os_print = Cleanup([&os](){ OPENVPN_LOG_STRING(os.str()); });
|
||||
th = tun_setup->establish(*po, Win::module_name(), config->stop, os);
|
||||
th = tun_setup->establish(*po, Win::module_name(), config->stop, os, NULL);
|
||||
}
|
||||
|
||||
// create ASIO wrapper for HANDLE
|
||||
TAPStream* ts = new TAPStream(io_context, th);
|
||||
|
||||
// persist tun settings state
|
||||
if (tun_persist->persist_tun_state(ts, state))
|
||||
if (tun_persist->persist_tun_state(ts, { state, nullptr }))
|
||||
OPENVPN_LOG("TunPersist: saving tun context:" << std::endl << tun_persist->options());
|
||||
|
||||
// setup handler for external tun close
|
||||
|
@ -68,7 +68,8 @@ namespace openvpn {
|
||||
virtual HANDLE establish(const TunBuilderCapture& pull,
|
||||
const std::wstring& openvpn_app_path,
|
||||
Stop* stop,
|
||||
std::ostream& os) override // defined by SetupBase
|
||||
std::ostream& os,
|
||||
RingBuffer::Ptr ring_buffer) override // defined by SetupBase
|
||||
{
|
||||
// close out old remove cmds, if they exist
|
||||
destroy(os);
|
||||
@ -123,6 +124,9 @@ namespace openvpn {
|
||||
if (pull.layer() == Layer::OSI_LAYER_2)
|
||||
l2_state.reset(new L2State(tap, openvpn_app_path));
|
||||
|
||||
if (ring_buffer)
|
||||
register_rings(th(), ring_buffer);
|
||||
|
||||
return th.release();
|
||||
}
|
||||
|
||||
@ -250,6 +254,31 @@ namespace openvpn {
|
||||
int indices[2] = {0, 0};
|
||||
};
|
||||
|
||||
void register_rings(HANDLE handle, RingBuffer::Ptr ring_buffer)
|
||||
{
|
||||
TUN_REGISTER_RINGS rings;
|
||||
|
||||
ZeroMemory(&rings, sizeof(rings));
|
||||
|
||||
rings.receive.ring = ring_buffer->receive_ring();
|
||||
rings.receive.tail_moved = ring_buffer->receive_ring_tail_moved();
|
||||
rings.receive.ring_size = sizeof(rings.receive.ring->data);
|
||||
|
||||
rings.send.ring = ring_buffer->send_ring();
|
||||
rings.send.tail_moved = ring_buffer->send_ring_tail_moved();
|
||||
rings.send.ring_size = sizeof(rings.send.ring->data);
|
||||
|
||||
{
|
||||
Win::Impersonate imp(true);
|
||||
|
||||
if (!DeviceIoControl(handle, TUN_IOCTL_REGISTER_RINGS, &rings, sizeof(rings), NULL, NULL, NULL, NULL))
|
||||
{
|
||||
const Win::LastError err;
|
||||
throw ErrorCode(Error::TUN_REGISTER_RINGS_ERROR, true, "Error registering ring buffers: " + err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
// Configure TAP adapter on Vista and higher
|
||||
void adapter_config(HANDLE th,
|
||||
|
@ -6,15 +6,6 @@
|
||||
#include <openvpn/tun/win/client/clientconfig.hpp>
|
||||
#include <openvpn/win/modname.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 {
|
||||
|
||||
@ -30,53 +21,78 @@ namespace openvpn {
|
||||
config(config_arg),
|
||||
parent(parent_arg),
|
||||
state(new TunProp::State()),
|
||||
ring_send_tail_moved_event(io_context_arg),
|
||||
frame(config_arg->frame)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Inherited via TunClient
|
||||
void tun_start(const OptionList& opt, TransportClient& transcli, CryptoDCSettings&) override
|
||||
{
|
||||
halt = false;
|
||||
if (config->tun_persist)
|
||||
tun_persist = config->tun_persist; // long-term persistent
|
||||
else
|
||||
tun_persist.reset(new TunPersist(false, false, nullptr)); // short-term
|
||||
|
||||
try {
|
||||
|
||||
const IP::Addr server_addr = transcli.server_endpoint_addr();
|
||||
|
||||
// notify parent
|
||||
parent.tun_pre_tun_config();
|
||||
// Check if persisted tun session matches properties of to-be-created session
|
||||
if (tun_persist->use_persisted_tun(server_addr, config->tun_prop, opt))
|
||||
{
|
||||
state = tun_persist->state().state;
|
||||
ring_buffer = tun_persist->state().ring_buffer;
|
||||
OPENVPN_LOG("TunPersist: reused tun context");
|
||||
}
|
||||
else
|
||||
{
|
||||
// notify parent
|
||||
parent.tun_pre_tun_config();
|
||||
|
||||
// parse pushed options
|
||||
TunBuilderCapture::Ptr po(new TunBuilderCapture());
|
||||
TunProp::configure_builder(po.get(),
|
||||
state.get(),
|
||||
config->stats.get(),
|
||||
server_addr,
|
||||
config->tun_prop,
|
||||
opt,
|
||||
nullptr,
|
||||
false);
|
||||
OPENVPN_LOG("CAPTURED OPTIONS:" << std::endl << po->to_string());
|
||||
// close old TAP handle if persisted
|
||||
tun_persist->close();
|
||||
|
||||
// create new tun setup object
|
||||
tun_setup = config->new_setup_obj(io_context);
|
||||
// parse pushed options
|
||||
TunBuilderCapture::Ptr po(new TunBuilderCapture());
|
||||
TunProp::configure_builder(po.get(),
|
||||
state.get(),
|
||||
config->stats.get(),
|
||||
server_addr,
|
||||
config->tun_prop,
|
||||
opt,
|
||||
nullptr,
|
||||
false);
|
||||
OPENVPN_LOG("CAPTURED OPTIONS:" << std::endl << po->to_string());
|
||||
|
||||
// open/config TAP
|
||||
{
|
||||
std::ostringstream os;
|
||||
auto os_print = Cleanup([&os]() { OPENVPN_LOG_STRING(os.str()); });
|
||||
driver_handle = tun_setup->establish(*po, Win::module_name(), config->stop, os);
|
||||
}
|
||||
// create new tun setup object
|
||||
tun_setup = config->new_setup_obj(io_context);
|
||||
|
||||
// assert ownership over TAP device handle
|
||||
tun_setup->confirm();
|
||||
ring_buffer.reset(new RingBuffer(io_context));
|
||||
|
||||
register_rings();
|
||||
// open/config TAP
|
||||
HANDLE th;
|
||||
{
|
||||
std::ostringstream os;
|
||||
auto os_print = Cleanup([&os]() { OPENVPN_LOG_STRING(os.str()); });
|
||||
th = tun_setup->establish(*po, Win::module_name(), config->stop, os, ring_buffer);
|
||||
}
|
||||
|
||||
// create ASIO wrapper for HANDLE
|
||||
TAPStream* ts = new TAPStream(io_context, th);
|
||||
|
||||
// persist tun settings state
|
||||
if (tun_persist->persist_tun_state(ts, { state, ring_buffer }))
|
||||
OPENVPN_LOG("TunPersist: saving tun context:" << std::endl << tun_persist->options());
|
||||
|
||||
openvpn_io::post([self=Ptr(this)](){
|
||||
// enable tun_setup destructor
|
||||
tun_persist->add_destructor(tun_setup);
|
||||
|
||||
// assert ownership over TAP device handle
|
||||
tun_setup->confirm();
|
||||
}
|
||||
|
||||
openvpn_io::post([self = Ptr(this)](){
|
||||
self->read();
|
||||
});
|
||||
|
||||
@ -98,11 +114,8 @@ namespace openvpn {
|
||||
if (!halt)
|
||||
{
|
||||
halt = true;
|
||||
unregister_rings();
|
||||
|
||||
std::ostringstream os;
|
||||
auto os_print = Cleanup([&os]() { OPENVPN_LOG_STRING(os.str()); });
|
||||
tun_setup->destroy(os);
|
||||
tun_persist.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +126,9 @@ namespace openvpn {
|
||||
|
||||
bool tun_send(BufferAllocated& buf) override
|
||||
{
|
||||
ULONG head = rings.receive.ring->head;
|
||||
TUN_RING* receive_ring = ring_buffer->receive_ring();
|
||||
|
||||
ULONG head = receive_ring->head;
|
||||
if (head > WINTUN_RING_CAPACITY)
|
||||
{
|
||||
if (head == 0xFFFFFFFF)
|
||||
@ -121,7 +136,7 @@ namespace openvpn {
|
||||
return false;
|
||||
}
|
||||
|
||||
ULONG tail = rings.receive.ring->tail;
|
||||
ULONG tail = receive_ring->tail;
|
||||
if (tail >= WINTUN_RING_CAPACITY)
|
||||
return false;
|
||||
|
||||
@ -134,15 +149,15 @@ namespace openvpn {
|
||||
}
|
||||
|
||||
// copy packet size and data into ring
|
||||
TUN_PACKET* packet = (TUN_PACKET*)& rings.receive.ring->data[tail];
|
||||
TUN_PACKET* packet = (TUN_PACKET*)& receive_ring->data[tail];
|
||||
packet->size = buf.size();
|
||||
std::memcpy(packet->data, buf.data(), buf.size());
|
||||
|
||||
// move ring tail
|
||||
tail = wrap(tail + aligned_packet_size);
|
||||
rings.receive.ring->tail = tail;
|
||||
if (rings.receive.ring->alertable != 0)
|
||||
SetEvent(rings.receive.tail_moved);
|
||||
receive_ring->tail = tail;
|
||||
if (receive_ring->alertable != 0)
|
||||
SetEvent(ring_buffer->receive_ring_tail_moved());
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -187,17 +202,19 @@ namespace openvpn {
|
||||
private:
|
||||
void read()
|
||||
{
|
||||
TUN_RING* send_ring = ring_buffer->send_ring();
|
||||
|
||||
if (halt)
|
||||
return;
|
||||
|
||||
ULONG head = rings.send.ring->head;
|
||||
ULONG head = send_ring->head;
|
||||
if (head >= WINTUN_RING_CAPACITY)
|
||||
{
|
||||
parent.tun_error(Error::TUN_ERROR, "ring head exceeds ring capacity");
|
||||
return;
|
||||
}
|
||||
|
||||
ULONG tail = rings.send.ring->tail;
|
||||
ULONG tail = send_ring->tail;
|
||||
if (tail >= WINTUN_RING_CAPACITY)
|
||||
{
|
||||
parent.tun_error(Error::TUN_ERROR, "ring tail exceeds ring capacity");
|
||||
@ -207,7 +224,7 @@ namespace openvpn {
|
||||
// tail has moved?
|
||||
if (head == tail)
|
||||
{
|
||||
ring_send_tail_moved_event.async_wait([self=Ptr(this)](const openvpn_io::error_code& error) {
|
||||
ring_buffer->send_tail_moved_asio_event().async_wait([self=Ptr(this)](const openvpn_io::error_code& error) {
|
||||
if (!error)
|
||||
self->read();
|
||||
else
|
||||
@ -227,7 +244,7 @@ namespace openvpn {
|
||||
return;
|
||||
}
|
||||
|
||||
TUN_PACKET* packet = (TUN_PACKET*)& rings.send.ring->data[head];
|
||||
TUN_PACKET* packet = (TUN_PACKET*)&send_ring->data[head];
|
||||
if (packet->size > WINTUN_MAX_PACKET_SIZE)
|
||||
{
|
||||
parent.tun_error(Error::TUN_ERROR, "packet too big in send ring");
|
||||
@ -246,7 +263,7 @@ namespace openvpn {
|
||||
buf.write(packet->data, packet->size);
|
||||
|
||||
head = wrap(head + aligned_packet_size);
|
||||
rings.send.ring->head = head;
|
||||
send_ring->head = head;
|
||||
|
||||
parent.tun_recv(buf);
|
||||
|
||||
@ -258,65 +275,6 @@ namespace openvpn {
|
||||
}
|
||||
}
|
||||
|
||||
void register_rings()
|
||||
{
|
||||
ZeroMemory(&rings, sizeof(rings));
|
||||
|
||||
rings.receive.ring = new TUN_RING();
|
||||
ZeroMemory(rings.receive.ring, sizeof(rings.receive.ring));
|
||||
rings.receive.tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
rings.receive.ring_size = sizeof(rings.receive.ring->data);
|
||||
|
||||
rings.send.ring = new TUN_RING();
|
||||
ZeroMemory(rings.send.ring, sizeof(rings.send.ring));
|
||||
rings.send.tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
rings.send.ring_size = sizeof(rings.send.ring->data);
|
||||
|
||||
ring_send_tail_moved_event.assign(rings.send.tail_moved);
|
||||
|
||||
{
|
||||
Win::Impersonate imp(true);
|
||||
|
||||
if (!DeviceIoControl(driver_handle, TUN_IOCTL_REGISTER_RINGS, &rings, sizeof(rings), NULL, NULL, NULL, NULL))
|
||||
{
|
||||
const Win::LastError err;
|
||||
throw ErrorCode(Error::TUN_REGISTER_RINGS_ERROR, true, "Error registering ring buffers: " + err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unregister_rings()
|
||||
{
|
||||
// delete ring buffers
|
||||
delete rings.send.ring;
|
||||
rings.send.ring = nullptr;
|
||||
|
||||
delete rings.receive.ring;
|
||||
rings.receive.ring = nullptr;
|
||||
|
||||
// close event handles
|
||||
CloseHandle(rings.receive.tail_moved);
|
||||
|
||||
CloseHandle(driver_handle);
|
||||
}
|
||||
|
||||
struct TUN_RING {
|
||||
volatile ULONG head;
|
||||
volatile ULONG tail;
|
||||
volatile 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;
|
||||
};
|
||||
|
||||
struct TUN_PACKET_HEADER
|
||||
{
|
||||
uint32_t size;
|
||||
@ -328,7 +286,6 @@ namespace openvpn {
|
||||
UCHAR data[WINTUN_MAX_PACKET_SIZE];
|
||||
};
|
||||
|
||||
|
||||
ULONG packet_align(ULONG size)
|
||||
{
|
||||
return (size + (WINTUN_PACKET_ALIGN - 1)) & ~(WINTUN_PACKET_ALIGN - 1);
|
||||
@ -340,22 +297,24 @@ namespace openvpn {
|
||||
}
|
||||
|
||||
openvpn_io::io_context& io_context;
|
||||
TunPersist::Ptr tun_persist; // contains the TAP device HANDLE
|
||||
ClientConfig::Ptr config;
|
||||
TunClientParent& parent;
|
||||
TunProp::State::Ptr state;
|
||||
TunWin::SetupBase::Ptr tun_setup;
|
||||
|
||||
TUN_REGISTER_RINGS rings = {};
|
||||
TUN_RING* receive_ring = nullptr;
|
||||
TUN_RING* send_ring = nullptr;
|
||||
|
||||
BufferAllocated buf;
|
||||
|
||||
Frame::Ptr frame;
|
||||
|
||||
bool halt;
|
||||
bool halt = false;
|
||||
|
||||
HANDLE driver_handle = NULL;
|
||||
ScopedHANDLE driver_handle;
|
||||
|
||||
openvpn_io::windows::object_handle ring_send_tail_moved_event;
|
||||
RingBuffer::Ptr ring_buffer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
158
openvpn/tun/win/ringbuffer.hpp
Normal file
158
openvpn/tun/win/ringbuffer.hpp
Normal file
@ -0,0 +1,158 @@
|
||||
// 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 <openvpn/buffer/bufhex.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/win/scoped_handle.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 {
|
||||
volatile ULONG head;
|
||||
volatile ULONG tail;
|
||||
volatile 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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_;
|
||||
Win::Event receive_ring_tail_moved_;
|
||||
AsioEvent send_tail_moved_asio_event_;
|
||||
|
||||
TUN_RING* send_ring_ = nullptr;
|
||||
TUN_RING* receive_ring_ = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
@ -87,10 +87,17 @@ namespace openvpn {
|
||||
{
|
||||
if (defined())
|
||||
{
|
||||
const BOOL ret = ::CloseHandle(handle);
|
||||
//OPENVPN_LOG("**** SH CLOSE hand=" << handle << " ret=" << ret);
|
||||
handle = nullptr;
|
||||
return ret != 0;
|
||||
__try
|
||||
{
|
||||
const BOOL ret = ::CloseHandle(handle);
|
||||
//OPENVPN_LOG("**** SH CLOSE hand=" << handle << " ret=" << ret);
|
||||
handle = nullptr;
|
||||
return ret != 0;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
return true;
|
||||
|
@ -10,6 +10,9 @@ Global
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
DebugAgent|ARM = DebugAgent|ARM
|
||||
DebugAgent|x64 = DebugAgent|x64
|
||||
DebugAgent|x86 = DebugAgent|x86
|
||||
DebugOpenSSL|ARM = DebugOpenSSL|ARM
|
||||
DebugOpenSSL|x64 = DebugOpenSSL|x64
|
||||
DebugOpenSSL|x86 = DebugOpenSSL|x86
|
||||
@ -25,6 +28,10 @@ Global
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.Debug|x64.Build.0 = Debug|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugAgent|ARM.ActiveCfg = DebugAgent|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugAgent|x64.ActiveCfg = DebugAgent|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugAgent|x64.Build.0 = DebugAgent|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugAgent|x86.ActiveCfg = DebugAgent|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugOpenSSL|ARM.ActiveCfg = DebugOpenSSL|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugOpenSSL|x64.ActiveCfg = DebugOpenSSL|x64
|
||||
{1F891260-2039-494F-9777-EC5166AF31BC}.DebugOpenSSL|x64.Build.0 = DebugOpenSSL|x64
|
||||
|
@ -1,6 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="DebugAgent|x64">
|
||||
<Configuration>DebugAgent</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="DebugOpenSSL|x64">
|
||||
<Configuration>DebugOpenSSL</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
@ -121,6 +125,7 @@
|
||||
<ClInclude Include="..\openvpn\common\endian.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\enumdir.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\environ.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\event.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\exception.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\extern.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\ffs.hpp" />
|
||||
@ -425,6 +430,7 @@
|
||||
<ClInclude Include="..\openvpn\tun\win\client\tuncli.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\client\tunsetup.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\nrpt.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\ringbuffer.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\tunutil.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\wfp.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\winproxy.hpp" />
|
||||
@ -456,6 +462,12 @@
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugAgent|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugOpenSSL|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
@ -502,6 +514,26 @@
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugAgent|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;_WIN32_WINNT=0x0600;USE_ASIO;ASIO_STANDALONE;USE_MBEDTLS;HAVE_LZ4;TAP_WIN_COMPONENT_ID=tap0901;OPENVPN_COMMAND_AGENT;HAVE_JSONCPP;OVPNAGENT_DISABLE_PATH_CHECK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(O3)\deps\amd64\mbedtls\include;$(O3)\deps\amd64\tap-windows\src;$(O3)\deps\amd64\asio\asio\include;$(O3)\deps\amd64\lz4\lib;$(O3)\common;$(O3)\core;$(O3)\deps\amd64\jsoncpp\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(O3)\deps\amd64\mbedtls\library;$(O3)\deps\amd64\lz4\lib;$(O3)\deps\amd64\jsoncpp\dist;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>lz4.lib;mbedtls.lib;fwpuclnt.lib;ws2_32.lib;crypt32.lib;iphlpapi.lib;winmm.lib;advapi32.lib;wininet.lib;shell32.lib;ole32.lib;rpcrt4.lib;Wtsapi32.lib;setupapi.lib;jsoncpp.lib</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugOpenSSL|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
|
@ -429,6 +429,8 @@
|
||||
<ClInclude Include="..\openvpn\ip\ping6.hpp" />
|
||||
<ClInclude Include="..\openvpn\ip\csum.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\client\clientconfig.hpp" />
|
||||
<ClInclude Include="..\openvpn\tun\win\ringbuffer.hpp" />
|
||||
<ClInclude Include="..\openvpn\common\event.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\test\ovpncli\cli.cpp" />
|
||||
|
Loading…
Reference in New Issue
Block a user