summaryrefslogtreecommitdiff
path: root/src/openvpnserv/interactive.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpnserv/interactive.c')
-rw-r--r--src/openvpnserv/interactive.c252
1 files changed, 189 insertions, 63 deletions
diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c
index aecbd84..207cc4a 100644
--- a/src/openvpnserv/interactive.c
+++ b/src/openvpnserv/interactive.c
@@ -24,7 +24,6 @@
#include "service.h"
-#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <userenv.h>
@@ -44,13 +43,14 @@
#include "openvpn-msg.h"
#include "validate.h"
#include "block_dns.h"
+#include "ring_buffer.h"
#define IO_TIMEOUT 2000 /*ms*/
-#define ERROR_OPENVPN_STARTUP 0x20000000
-#define ERROR_STARTUP_DATA 0x20000001
-#define ERROR_MESSAGE_DATA 0x20000002
-#define ERROR_MESSAGE_TYPE 0x20000003
+#define ERROR_OPENVPN_STARTUP 0x20000000
+#define ERROR_STARTUP_DATA 0x20000001
+#define ERROR_MESSAGE_DATA 0x20000002
+#define ERROR_MESSAGE_TYPE 0x20000003
static SERVICE_STATUS_HANDLE service;
static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
@@ -59,6 +59,7 @@ static settings_t settings;
static HANDLE rdns_semaphore = NULL;
#define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */
+#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
openvpn_service_t interactive_service = {
interactive,
@@ -101,6 +102,14 @@ typedef struct {
int metric_v6;
} block_dns_data_t;
+typedef struct {
+ HANDLE send_ring_handle;
+ HANDLE receive_ring_handle;
+ HANDLE send_tail_moved;
+ HANDLE receive_tail_moved;
+ HANDLE device;
+} ring_buffer_handles_t;
+
static DWORD
AddListItem(list_item_t **pfirst, LPVOID data)
@@ -155,6 +164,26 @@ CloseHandleEx(LPHANDLE handle)
return INVALID_HANDLE_VALUE;
}
+static HANDLE
+OvpnUnmapViewOfFile(LPHANDLE handle)
+{
+ if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
+ {
+ UnmapViewOfFile(*handle);
+ *handle = INVALID_HANDLE_VALUE;
+ }
+ return INVALID_HANDLE_VALUE;
+}
+
+static void
+CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles)
+{
+ CloseHandleEx(&ring_buffer_handles->device);
+ CloseHandleEx(&ring_buffer_handles->receive_tail_moved);
+ CloseHandleEx(&ring_buffer_handles->send_tail_moved);
+ OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle);
+ OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle);
+}
static HANDLE
InitOverlapped(LPOVERLAPPED overlapped)
@@ -188,7 +217,7 @@ typedef enum {
static DWORD
AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
{
- int i;
+ DWORD i;
BOOL success;
HANDLE io_event;
DWORD res, bytes = 0;
@@ -277,10 +306,9 @@ ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
* Same format as error messages (3 line string) with error = 0 in
* 0x%08x format, PID on line 2 and a description "Process ID" on line 3
*/
- swprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg);
- buf[_countof(buf) - 1] = '\0';
+ openvpn_swprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg);
- WritePipeAsync(pipe, buf, wcslen(buf) * 2, count, events);
+ WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
}
static VOID
@@ -308,7 +336,7 @@ ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events
L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
(LPWSTR) &result, 0, (va_list *) args);
- WritePipeAsync(pipe, result, wcslen(result) * 2, count, events);
+ WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
#ifdef UNICODE
MsgToEventLog(MSG_FLAGS_ERROR, result);
#else
@@ -332,31 +360,6 @@ ReturnLastError(HANDLE pipe, LPCWSTR func)
ReturnError(pipe, GetLastError(), func, 1, &exit_event);
}
-
-static VOID
-ReturnOpenvpnOutput(HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE events)
-{
- WCHAR *wide_output = NULL;
- CHAR output[512];
- DWORD size;
-
- ReadFile(ovpn_output, output, sizeof(output), &size, NULL);
- if (size == 0)
- {
- return;
- }
-
- wide_output = malloc((size) * sizeof(WCHAR));
- if (wide_output)
- {
- MultiByteToWideChar(CP_UTF8, 0, output, size, wide_output, size);
- wide_output[size - 1] = 0;
- }
-
- ReturnError(pipe, ERROR_OPENVPN_STARTUP, wide_output, count, events);
- free(wide_output);
-}
-
/*
* Validate options against a white list. Also check the config_file is
* inside the config_dir. The white list is defined in validate.c
@@ -381,10 +384,9 @@ ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *
if (!argv)
{
- swprintf(errmsg, capacity,
- L"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
- GetLastError());
- errmsg[capacity-1] = L'\0';
+ openvpn_swprintf(errmsg, capacity,
+ L"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
+ GetLastError());
goto out;
}
@@ -404,9 +406,8 @@ ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *
if (!CheckOption(workdir, 2, argv_tmp, &settings))
{
- swprintf(errmsg, capacity, msg1, argv[0], workdir,
- settings.ovpn_admin_group);
- errmsg[capacity-1] = L'\0';
+ openvpn_swprintf(errmsg, capacity, msg1, argv[0], workdir,
+ settings.ovpn_admin_group);
}
goto out;
}
@@ -422,15 +423,14 @@ ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *
{
if (wcscmp(L"--config", argv[i]) == 0 && argc-i > 1)
{
- swprintf(errmsg, capacity, msg1, argv[i+1], workdir,
- settings.ovpn_admin_group);
+ openvpn_swprintf(errmsg, capacity, msg1, argv[i+1], workdir,
+ settings.ovpn_admin_group);
}
else
{
- swprintf(errmsg, capacity, msg2, argv[i],
- settings.ovpn_admin_group);
+ openvpn_swprintf(errmsg, capacity, msg2, argv[i],
+ settings.ovpn_admin_group);
}
- errmsg[capacity-1] = L'\0';
goto out;
}
}
@@ -449,9 +449,9 @@ out:
static BOOL
GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
{
- size_t len;
+ size_t size, len;
WCHAR *data = NULL;
- DWORD size, bytes, read;
+ DWORD bytes, read;
bytes = PeekNamedPipeAsync(pipe, 1, &exit_event);
if (bytes == 0)
@@ -516,7 +516,7 @@ GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
return TRUE;
err:
- sud->directory = NULL; /* caller must not free() */
+ sud->directory = NULL; /* caller must not free() */
free(data);
return FALSE;
}
@@ -930,7 +930,7 @@ static DWORD WINAPI
RegisterDNS(LPVOID unused)
{
DWORD err;
- DWORD i;
+ size_t i;
DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */
/* path of ipconfig command */
@@ -945,17 +945,15 @@ RegisterDNS(LPVOID unused)
{ ipcfg, L"ipconfig /flushdns", timeout },
{ ipcfg, L"ipconfig /registerdns", timeout },
};
- int ncmds = sizeof(cmds) / sizeof(cmds[0]);
HANDLE wait_handles[2] = {rdns_semaphore, exit_event};
- swprintf(ipcfg, _countof(ipcfg), L"%s\\%s", get_win_sys_path(), L"ipconfig.exe");
- ipcfg[_countof(ipcfg) - 1] = L'\0';
+ openvpn_swprintf(ipcfg, MAX_PATH, L"%s\\%s", get_win_sys_path(), L"ipconfig.exe");
if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
{
/* Semaphore locked */
- for (i = 0; i < ncmds; ++i)
+ for (i = 0; i < _countof(cmds); ++i)
{
ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
}
@@ -1038,7 +1036,7 @@ netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_nam
const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s";
/* max cmdline length in wchars -- include room for worst case and some */
- int ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1;
+ size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1;
cmdline = malloc(ncmdline*sizeof(wchar_t));
if (!cmdline)
{
@@ -1202,8 +1200,118 @@ HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
return err;
}
+static DWORD
+OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle)
+{
+ DWORD err = ERROR_SUCCESS;
+
+ if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ err = GetLastError();
+ MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle"));
+ return err;
+ }
+
+ return err;
+}
+
+static DWORD
+DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring)
+{
+ DWORD err = ERROR_SUCCESS;
+
+ err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle);
+ if (err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+ *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring));
+ if (*ring == NULL)
+ {
+ err = GetLastError();
+ MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory"));
+ return err;
+ }
+
+ return err;
+}
+
+static DWORD
+HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc,
+ ring_buffer_handles_t *ring_buffer_handles)
+{
+ DWORD err = 0;
+ struct tun_ring *send_ring;
+ struct tun_ring *receive_ring;
+
+ CloseRingBufferHandles(ring_buffer_handles);
+
+ err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device);
+ if (err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+
+ err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring);
+ if (err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+
+ err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring);
+ if (err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+
+ err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved);
+ if (err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+
+ err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved);
+ if (err != ERROR_SUCCESS)
+ {
+ return err;
+ }
+
+ if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring,
+ ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved))
+ {
+ err = GetLastError();
+ MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers"));
+ }
+
+ return err;
+}
+
+static DWORD
+HandleMTUMessage(const set_mtu_message_t *mtu)
+{
+ DWORD err = 0;
+ MIB_IPINTERFACE_ROW ipiface;
+ InitializeIpInterfaceEntry(&ipiface);
+ ipiface.Family = mtu->family;
+ ipiface.InterfaceIndex = mtu->iface.index;
+ err = GetIpInterfaceEntry(&ipiface);
+ if (err != NO_ERROR)
+ {
+ return err;
+ }
+ if (mtu->family == AF_INET)
+ {
+ ipiface.SitePrefixLength = 0;
+ }
+ ipiface.NlMtu = mtu->mtu;
+
+ err = SetIpInterfaceEntry(&ipiface);
+ return err;
+}
+
static VOID
-HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
+HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles,
+ DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
{
DWORD read;
union {
@@ -1214,6 +1322,8 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists
block_dns_message_t block_dns;
dns_cfg_message_t dns;
enable_dhcp_message_t dhcp;
+ register_ring_buffers_message_t rrb;
+ set_mtu_message_t mtu;
} msg;
ack_message_t ack = {
.header = {
@@ -1281,6 +1391,20 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists
}
break;
+ case msg_register_ring_buffers:
+ if (msg.header.size == sizeof(msg.rrb))
+ {
+ ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles);
+ }
+ break;
+
+ case msg_set_mtu:
+ if (msg.header.size == sizeof(msg.mtu))
+ {
+ ack.error_number = HandleMTUMessage(&msg.mtu);
+ }
+ break;
+
default:
ack.error_number = ERROR_MESSAGE_TYPE;
MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type);
@@ -1322,7 +1446,7 @@ Undo(undo_lists_t *lists)
break;
case block_dns:
- interface_data = (block_dns_data_t*)(item->data);
+ interface_data = (block_dns_data_t *)(item->data);
delete_block_dns_filters(interface_data->engine);
if (interface_data->metric_v4 >= 0)
{
@@ -1364,6 +1488,7 @@ RunOpenvpn(LPVOID p)
WCHAR *cmdline = NULL;
size_t cmdline_size;
undo_lists_t undo_lists;
+ ring_buffer_handles_t ring_buffer_handles;
WCHAR errmsg[512] = L"";
SECURITY_ATTRIBUTES inheritable = {
@@ -1385,6 +1510,7 @@ RunOpenvpn(LPVOID p)
ZeroMemory(&startup_info, sizeof(startup_info));
ZeroMemory(&undo_lists, sizeof(undo_lists));
ZeroMemory(&proc_info, sizeof(proc_info));
+ ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles));
if (!GetStartupData(pipe, &sud))
{
@@ -1611,7 +1737,7 @@ RunOpenvpn(LPVOID p)
{
DWORD written;
WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL);
- WriteFile(stdin_write, input, strlen(input), &written, NULL);
+ WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
free(input);
}
@@ -1623,7 +1749,7 @@ RunOpenvpn(LPVOID p)
break;
}
- HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists);
+ HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists);
}
WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT);
@@ -1635,9 +1761,8 @@ RunOpenvpn(LPVOID p)
else if (exit_code != 0)
{
WCHAR buf[256];
- swprintf(buf, _countof(buf),
- L"OpenVPN exited with error: exit code = %lu", exit_code);
- buf[_countof(buf) - 1] = L'\0';
+ openvpn_swprintf(buf, _countof(buf),
+ L"OpenVPN exited with error: exit code = %lu", exit_code);
ReturnError(pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event);
}
Undo(&undo_lists);
@@ -1651,6 +1776,7 @@ out:
free(cmdline);
DestroyEnvironmentBlock(user_env);
FreeStartupData(&sud);
+ CloseRingBufferHandles(&ring_buffer_handles);
CloseHandleEx(&proc_info.hProcess);
CloseHandleEx(&proc_info.hThread);
CloseHandleEx(&stdin_read);