api: upgrade
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
d61007297d
commit
d675646ab8
1127
api/adapter.c
1127
api/adapter.c
File diff suppressed because it is too large
Load Diff
@ -13,58 +13,96 @@
|
||||
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
|
||||
#define WINTUN_HWID L"Wintun"
|
||||
|
||||
void
|
||||
AdapterInit(void);
|
||||
|
||||
/**
|
||||
* Wintun adapter descriptor.
|
||||
*/
|
||||
typedef struct _WINTUN_ADAPTER
|
||||
{
|
||||
HDEVINFO DevInfo;
|
||||
SP_DEVINFO_DATA DevInfoData;
|
||||
GUID CfgInstanceID;
|
||||
WCHAR DevInstanceID[MAX_INSTANCE_ID];
|
||||
DWORD LuidIndex;
|
||||
DWORD IfType;
|
||||
DWORD IfIndex;
|
||||
WCHAR Pool[WINTUN_MAX_POOL];
|
||||
} WINTUN_ADAPTER;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_FREE_ADAPTER_FUNC
|
||||
*/
|
||||
void WINAPI
|
||||
WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
|
||||
WINTUN_FREE_ADAPTER_FUNC_IMPL WintunFreeAdapter;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_CREATE_ADAPTER_FUNC
|
||||
*/
|
||||
_Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI WintunCreateAdapter(
|
||||
_In_z_ const WCHAR *Pool,
|
||||
_In_z_ const WCHAR *Name,
|
||||
_In_opt_ const GUID *RequestedGUID,
|
||||
_Out_opt_ BOOL *RebootRequired);
|
||||
WINTUN_CREATE_ADAPTER_FUNC_IMPL WintunCreateAdapter;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_OPEN_ADAPTER_FUNC
|
||||
*/
|
||||
WINTUN_OPEN_ADAPTER_FUNC_IMPL WintunOpenAdapter;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_DELETE_ADAPTER_FUNC
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter(
|
||||
_In_ const WINTUN_ADAPTER *Adapter,
|
||||
_In_ BOOL ForceCloseSessions,
|
||||
_Out_opt_ BOOL *RebootRequired);
|
||||
WINTUN_DELETE_ADAPTER_FUNC_IMPL WintunDeleteAdapter;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_ENUM_ADAPTERS_FUNC
|
||||
*/
|
||||
WINTUN_ENUM_ADAPTERS_FUNC_IMPL WintunEnumAdapters;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL WINAPI
|
||||
WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
|
||||
WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL WintunDeletePoolDriver;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_GET_ADAPTER_LUID_FUNC
|
||||
*/
|
||||
WINTUN_GET_ADAPTER_LUID_FUNC_IMPL WintunGetAdapterLUID;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_GET_ADAPTER_NAME_FUNC
|
||||
*/
|
||||
WINTUN_GET_ADAPTER_NAME_FUNC_IMPL WintunGetAdapterName;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_SET_ADAPTER_NAME_FUNC
|
||||
*/
|
||||
WINTUN_SET_ADAPTER_NAME_FUNC_IMPL WintunSetAdapterName;
|
||||
|
||||
/**
|
||||
* @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC
|
||||
*/
|
||||
WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL WintunGetRunningDriverVersion;
|
||||
|
||||
/**
|
||||
* Returns a handle to the adapter device object.
|
||||
*
|
||||
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
|
||||
*
|
||||
* @return If the function succeeds, the return value is adapter device object handle. Must be released with
|
||||
* CloseHandle. If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error
|
||||
* @return If the function succeeds, the return value is adapter device object handle.
|
||||
* If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error
|
||||
* information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI
|
||||
AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
|
||||
_Return_type_success_(return != INVALID_HANDLE_VALUE)
|
||||
HANDLE WINAPI
|
||||
AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
|
||||
/**
|
||||
* Returns an adapter object based on a devnode instance ID.
|
||||
*
|
||||
* @param Pool Pool name of adapter object to be opened.
|
||||
*
|
||||
* @param DevInstanceID Instance ID of devnode for opening adapter.
|
||||
*
|
||||
* @return If the function succeeds, the return value is adapter object..
|
||||
* If the function fails, the return value is NULL. To get extended error
|
||||
* information, call GetLastError.
|
||||
*/
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
WINTUN_ADAPTER *
|
||||
AdapterOpenFromDevInstanceId(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR DevInstanceID);
|
||||
|
@ -53,15 +53,13 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="main.h" />
|
||||
<ClInclude Include="adapter.h" />
|
||||
<ClInclude Include="rundll32_i.c">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="logger.h" />
|
||||
<ClInclude Include="namespace.h" />
|
||||
<ClInclude Include="nci.h" />
|
||||
<ClInclude Include="ntdll.h" />
|
||||
<ClInclude Include="registry.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="rundll32.h" />
|
||||
<ClInclude Include="wintun.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
51
api/logger.c
51
api/logger.c
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
#include "adapter.h"
|
||||
#include "ntdll.h"
|
||||
#include <Windows.h>
|
||||
#include <winternl.h>
|
||||
@ -11,17 +12,16 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static BOOL CALLBACK
|
||||
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
|
||||
NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Level);
|
||||
UNREFERENCED_PARAMETER(LogLine);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINTUN_LOGGER_CALLBACK Logger = NopLogger;
|
||||
|
||||
void CALLBACK
|
||||
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger)
|
||||
_Use_decl_annotations_
|
||||
VOID WINAPI
|
||||
WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger)
|
||||
{
|
||||
if (!NewLogger)
|
||||
NewLogger = NopLogger;
|
||||
@ -29,14 +29,15 @@ WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger)
|
||||
}
|
||||
|
||||
static VOID
|
||||
StrTruncate(_Inout_count_(StrChars) WCHAR *Str, _In_ SIZE_T StrChars)
|
||||
StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars)
|
||||
{
|
||||
Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */
|
||||
Str[StrChars - 1] = 0;
|
||||
}
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine)
|
||||
_Use_decl_annotations_
|
||||
DWORD
|
||||
LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR LogLine)
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
if (Function)
|
||||
@ -52,12 +53,9 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c
|
||||
return LastError;
|
||||
}
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
LoggerLogV(
|
||||
_In_ WINTUN_LOGGER_LEVEL Level,
|
||||
_In_z_ const WCHAR *Function,
|
||||
_In_z_ _Printf_format_string_ const WCHAR *Format,
|
||||
_In_ va_list Args)
|
||||
_Use_decl_annotations_
|
||||
DWORD
|
||||
LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Function, LPCWSTR Format, va_list Args)
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
WCHAR LogLine[0x400];
|
||||
@ -71,16 +69,17 @@ LoggerLogV(
|
||||
return LastError;
|
||||
}
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix)
|
||||
_Use_decl_annotations_
|
||||
DWORD
|
||||
LoggerError(DWORD Error, LPCWSTR Function, LPCWSTR Prefix)
|
||||
{
|
||||
WCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
|
||||
LPWSTR SystemMessage = NULL, FormattedMessage = NULL;
|
||||
FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL,
|
||||
HRESULT_FROM_SETUPAPI(Error),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(void *)&SystemMessage,
|
||||
(VOID *)&SystemMessage,
|
||||
0,
|
||||
NULL);
|
||||
FormatMessageW(
|
||||
@ -89,7 +88,7 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
|
||||
SystemMessage ? L"%4: %1: %3(Code 0x%2!08X!)" : L"%4: %1: Code 0x%2!08X!",
|
||||
0,
|
||||
0,
|
||||
(void *)&FormattedMessage,
|
||||
(VOID *)&FormattedMessage,
|
||||
0,
|
||||
(va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage, (DWORD_PTR)Function });
|
||||
if (FormattedMessage)
|
||||
@ -99,12 +98,9 @@ LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *
|
||||
return Error;
|
||||
}
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
LoggerErrorV(
|
||||
_In_ DWORD Error,
|
||||
_In_z_ const WCHAR *Function,
|
||||
_In_z_ _Printf_format_string_ const WCHAR *Format,
|
||||
_In_ va_list Args)
|
||||
_Use_decl_annotations_
|
||||
DWORD
|
||||
LoggerErrorV(DWORD Error, LPCWSTR Function, LPCWSTR Format, va_list Args)
|
||||
{
|
||||
WCHAR Prefix[0x400];
|
||||
if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
|
||||
@ -112,13 +108,14 @@ LoggerErrorV(
|
||||
return LoggerError(Error, Function, Prefix);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path)
|
||||
LoggerGetRegistryKeyPath(HKEY Key, LPWSTR Path)
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
if (Key == NULL)
|
||||
{
|
||||
wcscpy_s(Path, MAX_REG_PATH, L"<null>");
|
||||
wcsncpy_s(Path, MAX_REG_PATH, L"<null>", _TRUNCATE);
|
||||
goto out;
|
||||
}
|
||||
if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)
|
||||
|
123
api/logger.h
123
api/logger.h
@ -9,6 +9,7 @@
|
||||
#include "main.h"
|
||||
#include "registry.h"
|
||||
#include <Windows.h>
|
||||
#include <intsafe.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
|
||||
@ -17,25 +18,23 @@ extern WINTUN_LOGGER_CALLBACK Logger;
|
||||
/**
|
||||
* @copydoc WINTUN_SET_LOGGER_FUNC
|
||||
*/
|
||||
void WINAPI
|
||||
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
|
||||
WINTUN_SET_LOGGER_FUNC_IMPL WintunSetLogger;
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine);
|
||||
_Post_equals_last_error_
|
||||
DWORD
|
||||
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR LogLine);
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
_Post_equals_last_error_
|
||||
DWORD
|
||||
LoggerLogV(
|
||||
_In_ WINTUN_LOGGER_LEVEL Level,
|
||||
_In_z_ const WCHAR *Function,
|
||||
_In_z_ _Printf_format_string_ const WCHAR *Format,
|
||||
_In_z_ LPCWSTR Function,
|
||||
_In_z_ _Printf_format_string_ LPCWSTR Format,
|
||||
_In_ va_list Args);
|
||||
|
||||
static inline _Post_equals_last_error_ DWORD
|
||||
LoggerLogFmt(
|
||||
_In_ WINTUN_LOGGER_LEVEL Level,
|
||||
_In_z_ const WCHAR *Function,
|
||||
_In_z_ _Printf_format_string_ const WCHAR *Format,
|
||||
...)
|
||||
_Post_equals_last_error_
|
||||
static inline DWORD
|
||||
LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
|
||||
{
|
||||
va_list Args;
|
||||
va_start(Args, Format);
|
||||
@ -44,18 +43,21 @@ LoggerLogFmt(
|
||||
return LastError;
|
||||
}
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix);
|
||||
_Post_equals_last_error_
|
||||
DWORD
|
||||
LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ LPCWSTR Prefix);
|
||||
|
||||
_Post_equals_last_error_ DWORD
|
||||
_Post_equals_last_error_
|
||||
DWORD
|
||||
LoggerErrorV(
|
||||
_In_ DWORD Error,
|
||||
_In_z_ const WCHAR *Function,
|
||||
_In_z_ _Printf_format_string_ const WCHAR *Format,
|
||||
_In_z_ LPCWSTR Function,
|
||||
_In_z_ _Printf_format_string_ LPCWSTR Format,
|
||||
_In_ va_list Args);
|
||||
|
||||
static inline _Post_equals_last_error_ DWORD
|
||||
LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...)
|
||||
_Post_equals_last_error_
|
||||
static inline DWORD
|
||||
LoggerErrorFmt(_In_ DWORD Error, _In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
|
||||
{
|
||||
va_list Args;
|
||||
va_start(Args, Format);
|
||||
@ -64,8 +66,9 @@ LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_fo
|
||||
return LastError;
|
||||
}
|
||||
|
||||
static inline _Post_equals_last_error_ DWORD
|
||||
LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, _In_ va_list Args)
|
||||
_Post_equals_last_error_
|
||||
static inline DWORD
|
||||
LoggerLastErrorV(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args)
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
LoggerErrorV(LastError, Function, Format, Args);
|
||||
@ -73,8 +76,9 @@ LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ con
|
||||
return LastError;
|
||||
}
|
||||
|
||||
static inline _Post_equals_last_error_ DWORD
|
||||
LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...)
|
||||
_Post_equals_last_error_
|
||||
static inline DWORD
|
||||
LoggerLastErrorFmt(_In_z_ LPCWSTR Function, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
|
||||
{
|
||||
va_list Args;
|
||||
va_start(Args, Format);
|
||||
@ -84,7 +88,7 @@ LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ c
|
||||
}
|
||||
|
||||
VOID
|
||||
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path);
|
||||
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path);
|
||||
|
||||
#define __L(x) L##x
|
||||
#define _L(x) __L(x)
|
||||
@ -94,10 +98,31 @@ LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path);
|
||||
|
||||
#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
|
||||
|
||||
static inline _Return_type_success_(return != NULL) _Ret_maybenull_
|
||||
_Post_writable_byte_size_(Size) void *LoggerAlloc(_In_z_ const WCHAR *Function, _In_ DWORD Flags, _In_ SIZE_T Size)
|
||||
_Must_inspect_result_
|
||||
DECLSPEC_ALLOCATOR
|
||||
static inline _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_(Size)
|
||||
VOID *
|
||||
LoggerAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T Size)
|
||||
{
|
||||
void *Data = HeapAlloc(ModuleHeap, Flags, Size);
|
||||
VOID *Data = HeapAlloc(ModuleHeap, Flags, Size);
|
||||
if (!Data)
|
||||
{
|
||||
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
}
|
||||
return Data;
|
||||
}
|
||||
_Must_inspect_result_
|
||||
DECLSPEC_ALLOCATOR
|
||||
static inline _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_(Size)
|
||||
VOID *
|
||||
LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID Mem, _In_ SIZE_T Size)
|
||||
{
|
||||
VOID *Data = Mem ? HeapReAlloc(ModuleHeap, Flags, Mem, Size) : HeapAlloc(ModuleHeap, Flags, Size);
|
||||
if (!Data)
|
||||
{
|
||||
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
|
||||
@ -106,10 +131,48 @@ static inline _Return_type_success_(return != NULL) _Ret_maybenull_
|
||||
return Data;
|
||||
}
|
||||
#define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size)
|
||||
#define ReAlloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), 0, Mem, Size)
|
||||
#define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size)
|
||||
#define ReZalloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Size)
|
||||
|
||||
static inline void
|
||||
Free(void *Ptr)
|
||||
_Must_inspect_result_
|
||||
DECLSPEC_ALLOCATOR
|
||||
static inline _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
|
||||
VOID *
|
||||
LoggerAllocArray(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T NumberOfElements, _In_ SIZE_T SizeOfOneElement)
|
||||
{
|
||||
SIZE_T Size;
|
||||
if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
|
||||
return NULL;
|
||||
return LoggerAlloc(Function, Flags, Size);
|
||||
}
|
||||
_Must_inspect_result_
|
||||
DECLSPEC_ALLOCATOR
|
||||
static inline _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
|
||||
VOID *
|
||||
LoggerReAllocArray(
|
||||
_In_z_ LPCWSTR Function,
|
||||
_In_ DWORD Flags,
|
||||
_Frees_ptr_opt_ LPVOID Mem,
|
||||
_In_ SIZE_T NumberOfElements,
|
||||
_In_ SIZE_T SizeOfOneElement)
|
||||
{
|
||||
SIZE_T Size;
|
||||
if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
|
||||
return NULL;
|
||||
return LoggerReAlloc(Function, Flags, Mem, Size);
|
||||
}
|
||||
#define AllocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), 0, Count, Size)
|
||||
#define ReAllocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), 0, Mem, Count, Size)
|
||||
#define ZallocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Count, Size)
|
||||
#define ReZallocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Count, Size)
|
||||
|
||||
static inline VOID
|
||||
Free(_Frees_ptr_opt_ VOID *Ptr)
|
||||
{
|
||||
if (!Ptr)
|
||||
return;
|
||||
|
43
api/main.c
43
api/main.c
@ -3,18 +3,15 @@
|
||||
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "adapter.h"
|
||||
#include "logger.h"
|
||||
#include "registry.h"
|
||||
#include "adapter.h"
|
||||
#include "main.h"
|
||||
#include "namespace.h"
|
||||
#include "wintun.h"
|
||||
#include "registry.h"
|
||||
#include "ntdll.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201)
|
||||
/* nonstandard extension used: nameless struct/union */
|
||||
#include <delayimp.h>
|
||||
#pragma warning(pop)
|
||||
#include <sddl.h>
|
||||
#include <winefs.h>
|
||||
#include <stdlib.h>
|
||||
@ -23,6 +20,8 @@ HINSTANCE ResourceModule;
|
||||
HANDLE ModuleHeap;
|
||||
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
|
||||
BOOL IsLocalSystem;
|
||||
USHORT NativeMachine = IMAGE_FILE_PROCESS;
|
||||
BOOL IsWindows10;
|
||||
|
||||
static FARPROC WINAPI
|
||||
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||
@ -37,8 +36,7 @@ DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
|
||||
|
||||
const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook;
|
||||
|
||||
static BOOL
|
||||
InitializeSecurityObjects(void)
|
||||
static BOOL InitializeSecurityObjects(VOID)
|
||||
{
|
||||
BYTE LocalSystemSid[MAX_SID_SIZE];
|
||||
DWORD RequiredBytes = sizeof(LocalSystemSid);
|
||||
@ -72,11 +70,32 @@ cleanupProcessToken:
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static VOID EnvInit(VOID)
|
||||
{
|
||||
DWORD MajorVersion;
|
||||
RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
|
||||
IsWindows10 = MajorVersion >= 10;
|
||||
|
||||
#ifdef MAYBE_WOW64
|
||||
typedef BOOL(WINAPI * IsWow64Process2_t)(
|
||||
_In_ HANDLE hProcess, _Out_ USHORT * pProcessMachine, _Out_opt_ USHORT * pNativeMachine);
|
||||
HANDLE Kernel32;
|
||||
IsWow64Process2_t IsWow64Process2;
|
||||
USHORT ProcessMachine;
|
||||
if ((Kernel32 = GetModuleHandleW(L"kernel32.dll")) == NULL ||
|
||||
(IsWow64Process2 = (IsWow64Process2_t)GetProcAddress(Kernel32, "IsWow64Process2")) == NULL ||
|
||||
!IsWow64Process2(GetCurrentProcess(), &ProcessMachine, &NativeMachine))
|
||||
{
|
||||
BOOL IsWoW64;
|
||||
NativeMachine =
|
||||
IsWow64Process(GetCurrentProcess(), &IsWoW64) && IsWoW64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_PROCESS;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL APIENTRY
|
||||
DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpvReserved);
|
||||
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
@ -89,7 +108,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
|
||||
HeapDestroy(ModuleHeap);
|
||||
return FALSE;
|
||||
}
|
||||
AdapterInit();
|
||||
EnvInit();
|
||||
NamespaceInit();
|
||||
break;
|
||||
|
||||
|
27
api/main.h
27
api/main.h
@ -7,26 +7,21 @@
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
/* TODO: Replace with is_defined. MSVC has issues with the linux kernel varadic macro trick for this. */
|
||||
#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)
|
||||
# define MAYBE_WOW64 1
|
||||
#if defined(_M_IX86)
|
||||
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386
|
||||
#elif defined(_M_AMD64)
|
||||
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64
|
||||
#elif defined(_M_ARM)
|
||||
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT
|
||||
#elif defined(_M_ARM64)
|
||||
# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64
|
||||
#else
|
||||
# define MAYBE_WOW64 0
|
||||
# error Unsupported architecture
|
||||
#endif
|
||||
#if defined(_M_AMD64) || defined(_M_ARM64)
|
||||
# define ACCEPT_WOW64 1
|
||||
#else
|
||||
# define ACCEPT_WOW64 0
|
||||
#endif
|
||||
#ifdef HAVE_WHQL
|
||||
# undef HAVE_WHQL
|
||||
# define HAVE_WHQL 1
|
||||
#else
|
||||
# define HAVE_WHQL 0
|
||||
#endif
|
||||
#pragma warning(disable : 4127) /* conditional expression is constant */
|
||||
|
||||
extern HINSTANCE ResourceModule;
|
||||
extern HANDLE ModuleHeap;
|
||||
extern SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
extern BOOL IsLocalSystem;
|
||||
extern USHORT NativeMachine;
|
||||
extern BOOL IsWindows10;
|
@ -19,13 +19,16 @@ static HANDLE BoundaryDescriptor = NULL;
|
||||
static CRITICAL_SECTION Initializing;
|
||||
static BCRYPT_ALG_HANDLE AlgProvider;
|
||||
|
||||
static _Return_type_success_(
|
||||
return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source)
|
||||
_Must_inspect_result_
|
||||
static _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
LPWSTR
|
||||
NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source)
|
||||
{
|
||||
int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
|
||||
for (;;)
|
||||
{
|
||||
WCHAR *Str = Alloc(sizeof(WCHAR) * Len);
|
||||
LPWSTR Str = AllocArray(Len, sizeof(*Str));
|
||||
if (!Str)
|
||||
return NULL;
|
||||
Len = NormalizeString(NormForm, Source, -1, Str, Len);
|
||||
@ -41,7 +44,8 @@ static _Return_type_success_(
|
||||
}
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void)
|
||||
static _Return_type_success_(return != FALSE)
|
||||
BOOL NamespaceRuntimeInit(VOID)
|
||||
{
|
||||
DWORD LastError;
|
||||
|
||||
@ -110,8 +114,9 @@ cleanupLeaveCriticalSection:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_Check_return_
|
||||
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool)
|
||||
_Use_decl_annotations_
|
||||
HANDLE
|
||||
NamespaceTakePoolMutex(LPCWSTR Pool)
|
||||
{
|
||||
if (!NamespaceRuntimeInit())
|
||||
return NULL;
|
||||
@ -133,7 +138,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
|
||||
LastError = RtlNtStatusToDosError(Status);
|
||||
goto cleanupSha256;
|
||||
}
|
||||
WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
|
||||
LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
|
||||
if (!PoolNorm)
|
||||
{
|
||||
LastError = GetLastError();
|
||||
@ -184,8 +189,9 @@ cleanupSha256:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_Check_return_
|
||||
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void)
|
||||
_Use_decl_annotations_
|
||||
HANDLE
|
||||
NamespaceTakeDriverInstallationMutex(VOID)
|
||||
{
|
||||
if (!NamespaceRuntimeInit())
|
||||
return NULL;
|
||||
@ -208,21 +214,20 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMute
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceReleaseMutex(_In_ HANDLE Mutex)
|
||||
_Use_decl_annotations_
|
||||
VOID
|
||||
NamespaceReleaseMutex(HANDLE Mutex)
|
||||
{
|
||||
ReleaseMutex(Mutex);
|
||||
CloseHandle(Mutex);
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceInit(void)
|
||||
VOID NamespaceInit(VOID)
|
||||
{
|
||||
InitializeCriticalSection(&Initializing);
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceDone(void)
|
||||
VOID NamespaceDone(VOID)
|
||||
{
|
||||
EnterCriticalSection(&Initializing);
|
||||
if (PrivateNamespace)
|
||||
|
@ -7,17 +7,24 @@
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
_Check_return_
|
||||
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Acquires_lock_(_Curr_)
|
||||
HANDLE
|
||||
NamespaceTakePoolMutex(_In_z_ LPCWSTR Pool);
|
||||
|
||||
_Check_return_
|
||||
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Acquires_lock_(_Curr_)
|
||||
HANDLE
|
||||
NamespaceTakeDriverInstallationMutex(VOID);
|
||||
|
||||
void
|
||||
_Releases_lock_(Mutex)
|
||||
VOID
|
||||
NamespaceReleaseMutex(_In_ HANDLE Mutex);
|
||||
|
||||
void
|
||||
NamespaceInit(void);
|
||||
VOID NamespaceInit(VOID);
|
||||
|
||||
void
|
||||
NamespaceDone(void);
|
||||
VOID NamespaceDone(VOID);
|
||||
|
16
api/nci.h
16
api/nci.h
@ -9,19 +9,23 @@
|
||||
|
||||
#ifdef GENERATE_LIB
|
||||
# define DECLSPEC __declspec(dllexport)
|
||||
# define STUB { return 0; }
|
||||
# define STUB \
|
||||
{ \
|
||||
return 0; \
|
||||
}
|
||||
#else
|
||||
# define DECLSPEC __declspec(dllimport)
|
||||
# define STUB ;
|
||||
#endif
|
||||
|
||||
EXTERN_C
|
||||
DECLSPEC DWORD WINAPI
|
||||
NciSetConnectionName(_In_ const GUID *Guid, _In_z_ LPCWSTR NewName) STUB
|
||||
|
||||
EXTERN_C DECLSPEC DWORD WINAPI
|
||||
NciSetConnectionName(_In_ const GUID *Guid, _In_z_ const WCHAR *NewName) STUB
|
||||
|
||||
EXTERN_C DECLSPEC DWORD WINAPI
|
||||
EXTERN_C
|
||||
DECLSPEC DWORD WINAPI
|
||||
NciGetConnectionName(
|
||||
_In_ const GUID *Guid,
|
||||
_Out_z_bytecap_(InDestNameBytes) WCHAR *Name,
|
||||
_Out_z_bytecap_(InDestNameBytes) LPWSTR Name,
|
||||
_In_ DWORD InDestNameBytes,
|
||||
_Out_opt_ DWORD *OutDestNameBytes) STUB
|
@ -45,7 +45,7 @@ typedef struct _KEY_NAME_INFORMATION
|
||||
* when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
|
||||
*
|
||||
* Another way would be reading from the PEB directly:
|
||||
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
|
||||
* ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(VOID *) == 8 ? 70 : 41]
|
||||
* Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
|
||||
* *(DWORD *)0x7FFE026C
|
||||
*/
|
||||
@ -61,9 +61,3 @@ NtQueryKey(
|
||||
_Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation,
|
||||
_In_ ULONG Length,
|
||||
_Out_ PULONG ResultLength);
|
||||
|
||||
/* This is documented in NTSecAPI.h, which we can't include, due to header conflicts. It actually lives in advapi32.dll. */
|
||||
#define RtlGenRandom SystemFunction036
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
RtlGenRandom(_Out_writes_bytes_all_(RandomBufferLength) PVOID RandomBuffer, _In_ ULONG RandomBufferLength);
|
160
api/registry.c
160
api/registry.c
@ -10,11 +10,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
static _Return_type_success_(return != NULL) HKEY
|
||||
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
|
||||
_Must_inspect_result_
|
||||
static _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
HKEY
|
||||
OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
|
||||
{
|
||||
DWORD LastError;
|
||||
WCHAR *PathNext = wcschr(Path, L'\\');
|
||||
LPWSTR PathNext = wcschr(Path, L'\\');
|
||||
if (PathNext)
|
||||
*PathNext = 0;
|
||||
|
||||
@ -87,8 +90,9 @@ static _Return_type_success_(return != NULL) HKEY
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != NULL) HKEY
|
||||
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout)
|
||||
_Use_decl_annotations_
|
||||
HKEY
|
||||
RegistryOpenKeyWait(HKEY Key, LPCWSTR Path, DWORD Access, DWORD Timeout)
|
||||
{
|
||||
WCHAR Buf[MAX_REG_PATH];
|
||||
if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
|
||||
@ -100,17 +104,17 @@ _Return_type_success_(return != NULL) HKEY
|
||||
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout);
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType)
|
||||
{
|
||||
if (wcsnlen(*Buf, Len) >= Len)
|
||||
{
|
||||
/* String is missing zero-terminator. */
|
||||
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR));
|
||||
LPWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
|
||||
if (!BufZ)
|
||||
return FALSE;
|
||||
wmemcpy(BufZ, *Buf, Len);
|
||||
BufZ[Len] = 0;
|
||||
Free(*Buf);
|
||||
_Analysis_assume_((wmemset(BufZ, L'A', (SIZE_T)Len + 1), TRUE));
|
||||
*Buf = BufZ;
|
||||
}
|
||||
|
||||
@ -122,10 +126,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu
|
||||
if (!(*Buf)[0])
|
||||
return TRUE;
|
||||
|
||||
Len = Len * 2 + 64;
|
||||
for (;;)
|
||||
{
|
||||
WCHAR *Expanded = Alloc(Len * sizeof(WCHAR));
|
||||
LPWSTR Expanded = AllocArray(Len, sizeof(*Expanded));
|
||||
if (!Expanded)
|
||||
return FALSE;
|
||||
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
|
||||
@ -147,8 +150,9 @@ _Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Bu
|
||||
}
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
RegistryGetMultiString(PZZWSTR *Buf, DWORD Len, DWORD ValueType)
|
||||
{
|
||||
if (ValueType == REG_MULTI_SZ)
|
||||
{
|
||||
@ -157,25 +161,18 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
if (i > Len)
|
||||
{
|
||||
/* Missing string and list terminators. */
|
||||
WCHAR *BufZ = Alloc(((size_t)Len + 2) * sizeof(WCHAR));
|
||||
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 2, sizeof(*BufZ));
|
||||
if (!BufZ)
|
||||
return FALSE;
|
||||
wmemcpy(BufZ, *Buf, Len);
|
||||
BufZ[Len] = 0;
|
||||
BufZ[Len + 1] = 0;
|
||||
Free(*Buf);
|
||||
*Buf = BufZ;
|
||||
return TRUE;
|
||||
}
|
||||
if (i == Len)
|
||||
{
|
||||
/* Missing list terminator. */
|
||||
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR));
|
||||
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
|
||||
if (!BufZ)
|
||||
return FALSE;
|
||||
wmemcpy(BufZ, *Buf, Len);
|
||||
BufZ[Len] = 0;
|
||||
Free(*Buf);
|
||||
*Buf = BufZ;
|
||||
return TRUE;
|
||||
}
|
||||
@ -188,22 +185,19 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
if (!RegistryGetString(Buf, Len, ValueType))
|
||||
return FALSE;
|
||||
Len = (DWORD)wcslen(*Buf) + 1;
|
||||
WCHAR *BufZ = Alloc(((size_t)Len + 1) * sizeof(WCHAR));
|
||||
PZZWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(WCHAR));
|
||||
if (!BufZ)
|
||||
return FALSE;
|
||||
wmemcpy(BufZ, *Buf, Len);
|
||||
BufZ[Len] = 0;
|
||||
Free(*Buf);
|
||||
*Buf = BufZ;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != NULL) void *RegistryQuery(
|
||||
_In_ HKEY Key,
|
||||
_In_opt_z_ const WCHAR *Name,
|
||||
_Out_opt_ DWORD *ValueType,
|
||||
_Inout_ DWORD *BufLen,
|
||||
_In_ BOOL Log)
|
||||
_Must_inspect_result_
|
||||
static _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_(*BufLen)
|
||||
VOID *
|
||||
RegistryQuery(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_opt_ DWORD *ValueType, _Inout_ DWORD *BufLen, _In_ BOOL Log)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
@ -220,7 +214,7 @@ static _Return_type_success_(return != NULL) void *RegistryQuery(
|
||||
{
|
||||
WCHAR RegPath[MAX_REG_PATH];
|
||||
LoggerGetRegistryKeyPath(Key, RegPath);
|
||||
LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name);
|
||||
LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
|
||||
}
|
||||
SetLastError(LastError);
|
||||
return NULL;
|
||||
@ -228,11 +222,12 @@ static _Return_type_success_(return != NULL) void *RegistryQuery(
|
||||
}
|
||||
}
|
||||
|
||||
_Return_type_success_(
|
||||
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log)
|
||||
_Use_decl_annotations_
|
||||
LPWSTR
|
||||
RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log)
|
||||
{
|
||||
DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR);
|
||||
WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
|
||||
LPWSTR Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
|
||||
if (!Value)
|
||||
return NULL;
|
||||
switch (ValueType)
|
||||
@ -240,7 +235,7 @@ _Return_type_success_(
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
case REG_MULTI_SZ:
|
||||
if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType))
|
||||
if (RegistryGetString(&Value, Size / sizeof(*Value), ValueType))
|
||||
return Value;
|
||||
LastError = GetLastError();
|
||||
break;
|
||||
@ -261,8 +256,9 @@ _Return_type_success_(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_Return_type_success_(
|
||||
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout)
|
||||
_Use_decl_annotations_
|
||||
LPWSTR
|
||||
RegistryQueryStringWait(HKEY Key, LPCWSTR Name, DWORD Timeout)
|
||||
{
|
||||
DWORD LastError;
|
||||
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
||||
@ -282,7 +278,7 @@ _Return_type_success_(
|
||||
LOG_ERROR(LastError, L"Failed to setup registry key %.*s notification", MAX_REG_PATH, RegPath);
|
||||
break;
|
||||
}
|
||||
WCHAR *Value = RegistryQueryString(Key, Name, FALSE);
|
||||
LPWSTR Value = RegistryQueryString(Key, Name, FALSE);
|
||||
if (Value)
|
||||
{
|
||||
CloseHandle(Event);
|
||||
@ -313,8 +309,9 @@ _Return_type_success_(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log)
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log)
|
||||
{
|
||||
DWORD ValueType, Size = sizeof(DWORD);
|
||||
DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
|
||||
@ -324,7 +321,7 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
{
|
||||
WCHAR RegPath[MAX_REG_PATH];
|
||||
LoggerGetRegistryKeyPath(Key, RegPath);
|
||||
LOG_ERROR(LastError, L"Querying registry value %.*s\\%s failed", MAX_REG_PATH, RegPath, Name);
|
||||
LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
|
||||
}
|
||||
SetLastError(LastError);
|
||||
return FALSE;
|
||||
@ -348,8 +345,9 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
RegistryQueryDWORDWait(HKEY Key, LPCWSTR Name, DWORD Timeout, DWORD *Value)
|
||||
{
|
||||
DWORD LastError;
|
||||
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
||||
@ -398,73 +396,3 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
SetLastError(LastError);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) static BOOL
|
||||
DeleteNodeRecurse(_In_ HKEY Key, _In_z_ WCHAR *Name)
|
||||
{
|
||||
LSTATUS Ret;
|
||||
DWORD Size;
|
||||
SIZE_T Len;
|
||||
WCHAR SubName[MAX_REG_PATH], *End;
|
||||
HKEY SubKey;
|
||||
|
||||
Len = wcslen(Name);
|
||||
if (Len >= MAX_REG_PATH || !Len)
|
||||
return TRUE;
|
||||
|
||||
if (RegDeleteKeyW(Key, Name) == ERROR_SUCCESS)
|
||||
return TRUE;
|
||||
|
||||
Ret = RegOpenKeyEx(Key, Name, 0, KEY_READ, &SubKey);
|
||||
if (Ret != ERROR_SUCCESS)
|
||||
{
|
||||
if (Ret == ERROR_FILE_NOT_FOUND)
|
||||
return TRUE;
|
||||
SetLastError(Ret);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
End = Name + Len;
|
||||
if (End[-1] != L'\\')
|
||||
{
|
||||
*(End++) = L'\\';
|
||||
*End = L'\0';
|
||||
}
|
||||
Size = MAX_REG_PATH;
|
||||
Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL);
|
||||
if (Ret == ERROR_SUCCESS)
|
||||
{
|
||||
do
|
||||
{
|
||||
End[0] = L'\0';
|
||||
StringCchCatW(Name, MAX_REG_PATH * 2, SubName);
|
||||
if (!DeleteNodeRecurse(Key, Name))
|
||||
break;
|
||||
Size = MAX_REG_PATH;
|
||||
Ret = RegEnumKeyEx(SubKey, 0, SubName, &Size, NULL, NULL, NULL, NULL);
|
||||
} while (Ret == ERROR_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(Ret);
|
||||
*(--End) = L'\0';
|
||||
RegCloseKey(SubKey);
|
||||
return FALSE;
|
||||
}
|
||||
*(--End) = L'\0';
|
||||
RegCloseKey(SubKey);
|
||||
|
||||
Ret = RegDeleteKey(Key, Name);
|
||||
if (Ret == ERROR_SUCCESS)
|
||||
return TRUE;
|
||||
SetLastError(Ret);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name)
|
||||
{
|
||||
WCHAR NameBuf[(MAX_REG_PATH + 2) * 2] = { 0 };
|
||||
StringCchCopyW(NameBuf, MAX_REG_PATH * 2, Name);
|
||||
return DeleteNodeRecurse(Key, NameBuf);
|
||||
}
|
@ -26,8 +26,11 @@
|
||||
* @return Key handle on success. If the function fails, the return value is zero. To get extended error information,
|
||||
* call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != NULL) HKEY
|
||||
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
HKEY
|
||||
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ LPCWSTR Path, _In_ DWORD Access, _In_ DWORD Timeout);
|
||||
|
||||
/**
|
||||
* Validates and/or sanitizes string value read from registry.
|
||||
@ -44,8 +47,10 @@ _Return_type_success_(return != NULL) HKEY
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||
|
||||
/**
|
||||
* Validates and/or sanitizes multi-string value read from registry.
|
||||
@ -61,8 +66,10 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
RegistryGetMultiString(_Inout_ PZZWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||
|
||||
/**
|
||||
* Reads string value from registry key.
|
||||
@ -83,8 +90,11 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
* @return String with registry value on success; If the function fails, the return value is zero. To get extended error
|
||||
* information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(
|
||||
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
LPWSTR
|
||||
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log);
|
||||
|
||||
/**
|
||||
* Reads string value from registry key. It waits for the registry value to become available.
|
||||
@ -101,8 +111,11 @@ _Return_type_success_(
|
||||
* get extended error information, call GetLastError. Possible errors include the following:
|
||||
* ERROR_INVALID_DATATYPE when the registry value is not a string
|
||||
*/
|
||||
_Return_type_success_(
|
||||
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
LPWSTR
|
||||
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout);
|
||||
|
||||
/**
|
||||
* Reads a 32-bit DWORD value from registry key.
|
||||
@ -120,8 +133,10 @@ _Return_type_success_(
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log);
|
||||
|
||||
/**
|
||||
* Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available.
|
||||
@ -139,17 +154,7 @@ _Return_type_success_(return != FALSE) BOOL
|
||||
* ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
|
||||
* ERROR_INVALID_DATA when registry value size is not 4 bytes
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
|
||||
|
||||
/**
|
||||
* Deletes the entire registry key subtree recursively.
|
||||
*
|
||||
* @param Key Handle of the registry key to at which the subtree is rooted.
|
||||
*
|
||||
* @param Name Name of the subtree to delete.
|
||||
*
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL RegistryDeleteKeyRecursive(_In_ HKEY Key, _In_z_ const WCHAR *Name);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
|
||||
|
@ -7,9 +7,12 @@
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include <Windows.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <NTSecAPI.h>
|
||||
|
||||
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
|
||||
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size)
|
||||
_Use_decl_annotations_
|
||||
const VOID *
|
||||
ResourceGetAddress(LPCWSTR ResourceName, DWORD *Size)
|
||||
{
|
||||
HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
|
||||
if (!FoundResource)
|
||||
@ -39,11 +42,12 @@ _Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
|
||||
return Address;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName)
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
ResourceCopyToFile(LPCWSTR DestinationPath, LPCWSTR ResourceName)
|
||||
{
|
||||
DWORD SizeResource;
|
||||
const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
|
||||
const VOID *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
|
||||
if (!LockedResource)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName);
|
||||
@ -84,3 +88,42 @@ cleanupDestinationHandle:
|
||||
CloseHandle(DestinationHandle);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
||||
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory)
|
||||
{
|
||||
WCHAR WindowsDirectory[MAX_PATH];
|
||||
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
||||
{
|
||||
LOG_LAST_ERROR(L"Failed to get Windows folder");
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR WindowsTempDirectory[MAX_PATH];
|
||||
if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
|
||||
{
|
||||
SetLastError(ERROR_BUFFER_OVERFLOW);
|
||||
return FALSE;
|
||||
}
|
||||
UCHAR RandomBytes[32] = { 0 };
|
||||
if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to generate random");
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
|
||||
for (int i = 0; i < sizeof(RandomBytes); ++i)
|
||||
swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]);
|
||||
if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
|
||||
{
|
||||
SetLastError(ERROR_BUFFER_OVERFLOW);
|
||||
return FALSE;
|
||||
}
|
||||
if (!CreateDirectoryW(RandomTempSubDirectory, &SecurityAttributes))
|
||||
{
|
||||
LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -11,25 +11,40 @@
|
||||
/**
|
||||
* Locates RT_RCDATA resource memory address and size.
|
||||
*
|
||||
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
||||
* @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
||||
*
|
||||
* Size Pointer to a variable to receive resource size.
|
||||
* @param Size Pointer to a variable to receive resource size.
|
||||
*
|
||||
* @return Resource address on success. If the function fails, the return value is NULL. To get extended error
|
||||
* information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
|
||||
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size);
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_readable_byte_size_(*Size) const VOID *ResourceGetAddress(_In_z_ LPCWSTR ResourceName, _Out_ DWORD *Size);
|
||||
|
||||
/**
|
||||
* Copies resource to a file.
|
||||
*
|
||||
* DestinationPath File path
|
||||
* @param DestinationPath File path
|
||||
*
|
||||
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
||||
* @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
|
||||
*
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != FALSE) BOOL
|
||||
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName);
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
ResourceCopyToFile(_In_z_ LPCWSTR DestinationPath, _In_z_ LPCWSTR ResourceName);
|
||||
|
||||
/**
|
||||
* Creates a temporary directory.
|
||||
*
|
||||
* @param RandomTempSubDirectory Name of random temporary directory.
|
||||
*
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory);
|
||||
|
544
api/rundll32.c
544
api/rundll32.c
@ -3,12 +3,14 @@
|
||||
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "rundll32.h"
|
||||
#include "adapter.h"
|
||||
#include "main.h"
|
||||
#include "logger.h"
|
||||
#include "wintun.h"
|
||||
|
||||
#include "resource.h"
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <objbase.h>
|
||||
#include <assert.h>
|
||||
@ -18,10 +20,10 @@
|
||||
# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
|
||||
|
||||
static DWORD
|
||||
WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
|
||||
WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...)
|
||||
{
|
||||
WCHAR *FormattedMessage = NULL;
|
||||
DWORD SizeWritten;
|
||||
LPWSTR FormattedMessage = NULL;
|
||||
DWORD Size;
|
||||
va_list Arguments;
|
||||
va_start(Arguments, Template);
|
||||
DWORD Len = FormatMessageW(
|
||||
@ -29,19 +31,22 @@ WriteFormatted(_In_ DWORD StdHandle, _In_z_ const WCHAR *Template, ...)
|
||||
Template,
|
||||
0,
|
||||
0,
|
||||
(void *)&FormattedMessage,
|
||||
(VOID *)&FormattedMessage,
|
||||
0,
|
||||
&Arguments);
|
||||
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Len * sizeof(WCHAR), &SizeWritten, NULL);
|
||||
if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size)))
|
||||
WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL);
|
||||
else
|
||||
Size = 0;
|
||||
LocalFree(FormattedMessage);
|
||||
va_end(Arguments);
|
||||
return SizeWritten / sizeof(WCHAR);
|
||||
return Size / sizeof(*FormattedMessage);
|
||||
}
|
||||
|
||||
static void CALLBACK
|
||||
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
|
||||
static VOID CALLBACK
|
||||
ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine)
|
||||
{
|
||||
const WCHAR *Template;
|
||||
LPCWSTR Template;
|
||||
switch (Level)
|
||||
{
|
||||
case WINTUN_LOG_INFO:
|
||||
@ -59,29 +64,14 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
|
||||
WriteFormatted(STD_ERROR_HANDLE, Template, LogLine);
|
||||
}
|
||||
|
||||
static int Argc;
|
||||
static WCHAR **Argv;
|
||||
|
||||
static void
|
||||
Init(void)
|
||||
{
|
||||
WintunSetLogger(ConsoleLogger);
|
||||
Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
|
||||
}
|
||||
|
||||
static void
|
||||
Done(void)
|
||||
{
|
||||
LocalFree(Argv);
|
||||
}
|
||||
|
||||
# pragma warning(disable : 4100) /* unreferenced formal parameter */
|
||||
|
||||
VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
||||
{
|
||||
# pragma EXPORT
|
||||
|
||||
Init();
|
||||
int Argc;
|
||||
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
|
||||
WintunSetLogger(ConsoleLogger);
|
||||
|
||||
if (Argc < 4)
|
||||
goto cleanup;
|
||||
if (wcslen(Argv[2]) >= WINTUN_MAX_POOL)
|
||||
@ -95,47 +85,52 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
|
||||
BOOL RebootRequired;
|
||||
WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired);
|
||||
DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError();
|
||||
WCHAR GuidStr[MAX_GUID_STRING_LEN];
|
||||
WriteFormatted(
|
||||
STD_OUTPUT_HANDLE,
|
||||
L"%1!X! %2!.*s! %3!X!",
|
||||
LastError,
|
||||
StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
|
||||
GuidStr,
|
||||
RebootRequired);
|
||||
STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"", RebootRequired);
|
||||
if (Adapter)
|
||||
WintunFreeAdapter(Adapter);
|
||||
|
||||
cleanup:
|
||||
Done();
|
||||
LocalFree(Argv);
|
||||
}
|
||||
|
||||
VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
||||
{
|
||||
# pragma EXPORT
|
||||
|
||||
Init();
|
||||
if (Argc < 3)
|
||||
int Argc;
|
||||
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
|
||||
WintunSetLogger(ConsoleLogger);
|
||||
|
||||
if (Argc < 4)
|
||||
goto cleanup;
|
||||
|
||||
WINTUN_ADAPTER Adapter = { 0 };
|
||||
BOOL ForceCloseSessions = wcstoul(Argv[2], NULL, 10);
|
||||
if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID)))
|
||||
goto cleanup;
|
||||
BOOL RebootRequired;
|
||||
DWORD LastError =
|
||||
WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
|
||||
DWORD LastError;
|
||||
BOOL RebootRequired = FALSE;
|
||||
WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]);
|
||||
if (!Adapter)
|
||||
{
|
||||
LastError = GetLastError();
|
||||
goto write;
|
||||
}
|
||||
BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10);
|
||||
LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
|
||||
WintunFreeAdapter(Adapter);
|
||||
write:
|
||||
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
|
||||
|
||||
cleanup:
|
||||
Done();
|
||||
LocalFree(Argv);
|
||||
}
|
||||
|
||||
VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
||||
{
|
||||
# pragma EXPORT
|
||||
|
||||
Init();
|
||||
int Argc;
|
||||
LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
|
||||
WintunSetLogger(ConsoleLogger);
|
||||
|
||||
if (Argc < 2)
|
||||
goto cleanup;
|
||||
|
||||
@ -144,6 +139,455 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i
|
||||
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
|
||||
|
||||
cleanup:
|
||||
Done();
|
||||
LocalFree(Argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MAYBE_WOW64
|
||||
|
||||
_Return_type_success_(return != FALSE)
|
||||
static BOOL
|
||||
AppendToBuffer(_Inout_ LPWSTR *Buffer, _In_ CONST WCHAR Addition, _Inout_ SIZE_T *BufferPos, _Inout_ SIZE_T *BufferLen)
|
||||
{
|
||||
SIZE_T NewPos;
|
||||
if (FAILED(SIZETAdd(*BufferPos, sizeof(Addition), &NewPos)))
|
||||
return FALSE;
|
||||
if (NewPos >= *BufferLen)
|
||||
{
|
||||
SIZE_T NewLen;
|
||||
if (FAILED(SIZETMult(NewPos, 3, &NewLen)))
|
||||
return FALSE;
|
||||
LPWSTR NewBuffer = ReZalloc(*Buffer, NewLen);
|
||||
if (!NewBuffer)
|
||||
return FALSE;
|
||||
*Buffer = NewBuffer;
|
||||
*BufferLen = NewLen;
|
||||
}
|
||||
SIZE_T NewIndex = *BufferPos / sizeof(**Buffer);
|
||||
if (*Buffer + NewIndex < *Buffer)
|
||||
return FALSE;
|
||||
(*Buffer)[NewIndex] = Addition;
|
||||
*BufferPos = NewPos;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_Must_inspect_result_
|
||||
static _Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
LPWSTR
|
||||
ArgvToCommandLineW(_In_ SIZE_T ArgCount, ...)
|
||||
{
|
||||
LPWSTR Output = NULL;
|
||||
SIZE_T BufferPos = 0, BufferLen = 0;
|
||||
# define Append(Char) \
|
||||
do \
|
||||
{ \
|
||||
if (!AppendToBuffer(&Output, Char, &BufferPos, &BufferLen)) \
|
||||
goto cleanupBuffer; \
|
||||
} while (0)
|
||||
|
||||
va_list Args;
|
||||
va_start(Args, ArgCount);
|
||||
for (SIZE_T i = 0; i < ArgCount; ++i)
|
||||
{
|
||||
LPCWSTR Arg = va_arg(Args, LPCWSTR);
|
||||
SIZE_T ArgLen = wcslen(Arg);
|
||||
if (ArgLen >= DWORD_MAX >> 3)
|
||||
goto cleanupBuffer;
|
||||
if (i)
|
||||
Append(L' ');
|
||||
Append(L'"');
|
||||
for (SIZE_T j = 0;; ++j)
|
||||
{
|
||||
SIZE_T NumberBackslashes = 0;
|
||||
|
||||
while (j < ArgLen && Arg[j] == L'\\')
|
||||
{
|
||||
++j;
|
||||
++NumberBackslashes;
|
||||
}
|
||||
if (j >= ArgLen)
|
||||
{
|
||||
for (SIZE_T k = 0; k < NumberBackslashes * 2; ++k)
|
||||
Append(L'\\');
|
||||
break;
|
||||
}
|
||||
else if (Arg[j] == L'"')
|
||||
{
|
||||
for (SIZE_T k = 0; k < NumberBackslashes * 2 + 1; ++k)
|
||||
Append(L'\\');
|
||||
Append(Arg[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (SIZE_T k = 0; k < NumberBackslashes; ++k)
|
||||
Append(L'\\');
|
||||
Append(Arg[j]);
|
||||
}
|
||||
}
|
||||
Append(L'"');
|
||||
}
|
||||
va_end(Args);
|
||||
return Output;
|
||||
|
||||
cleanupBuffer:
|
||||
Free(Output);
|
||||
return NULL;
|
||||
# undef Append
|
||||
}
|
||||
|
||||
typedef struct _PROCESS_STDOUT_STATE
|
||||
{
|
||||
HANDLE Stdout;
|
||||
LPWSTR Response;
|
||||
DWORD ResponseCapacity;
|
||||
} PROCESS_STDOUT_STATE;
|
||||
|
||||
_Return_type_success_(return != ERROR_SUCCESS)
|
||||
static DWORD WINAPI
|
||||
ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
|
||||
{
|
||||
for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
|
||||
{
|
||||
DWORD Size;
|
||||
if (FAILED(DWordMult(MaxLen - Offset, sizeof(WCHAR), &Size)))
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
if (!ReadFile(State->Stdout, State->Response + Offset, Size, &Size, NULL))
|
||||
return ERROR_SUCCESS;
|
||||
if (Size % sizeof(WCHAR))
|
||||
return ERROR_INVALID_DATA;
|
||||
Offset += Size / sizeof(WCHAR);
|
||||
State->Response[Offset] = 0;
|
||||
}
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
static DWORD WINAPI
|
||||
ProcessStderr(_In_ HANDLE Stderr)
|
||||
{
|
||||
enum
|
||||
{
|
||||
OnNone,
|
||||
OnLevelStart,
|
||||
OnLevel,
|
||||
OnLevelEnd,
|
||||
OnSpace,
|
||||
OnMsg
|
||||
} State = OnNone;
|
||||
WCHAR Msg[0x200];
|
||||
DWORD Count = 0;
|
||||
WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO;
|
||||
for (;;)
|
||||
{
|
||||
WCHAR Buf[0x200];
|
||||
DWORD SizeRead;
|
||||
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
|
||||
return ERROR_SUCCESS;
|
||||
if (SizeRead % sizeof(*Buf))
|
||||
return ERROR_INVALID_DATA;
|
||||
SizeRead /= sizeof(*Buf);
|
||||
for (DWORD i = 0; i < SizeRead; ++i)
|
||||
{
|
||||
WCHAR c = Buf[i];
|
||||
if (State == OnNone && c == L'[')
|
||||
State = OnLevelStart;
|
||||
else if (
|
||||
State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') ||
|
||||
(Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!')))
|
||||
State = OnLevelEnd;
|
||||
else if (State == OnLevelEnd && c == L']')
|
||||
State = OnSpace;
|
||||
else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n')
|
||||
{
|
||||
if (Count < _countof(Msg) - 1)
|
||||
Msg[Count++] = c;
|
||||
State = OnMsg;
|
||||
}
|
||||
else if (State == OnMsg && c == L'\n')
|
||||
{
|
||||
Msg[Count] = 0;
|
||||
LoggerLog(Level, NULL, Msg);
|
||||
State = OnNone;
|
||||
Count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
ExecuteRunDll32(
|
||||
_In_z_ LPCWSTR Function,
|
||||
_In_z_ LPCWSTR Arguments,
|
||||
_Out_z_cap_c_(ResponseCapacity) LPWSTR Response,
|
||||
_In_ DWORD ResponseCapacity)
|
||||
{
|
||||
WCHAR WindowsDirectory[MAX_PATH];
|
||||
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
||||
{
|
||||
LOG_LAST_ERROR(L"Failed to get Windows folder");
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR RunDll32Path[MAX_PATH];
|
||||
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
|
||||
{
|
||||
SetLastError(ERROR_BUFFER_OVERFLOW);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD LastError;
|
||||
WCHAR RandomTempSubDirectory[MAX_PATH];
|
||||
if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder");
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR DllPath[MAX_PATH] = { 0 };
|
||||
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
|
||||
{
|
||||
LastError = ERROR_BUFFER_OVERFLOW;
|
||||
goto cleanupDirectory;
|
||||
}
|
||||
LPCWSTR WintunDllResourceName;
|
||||
switch (NativeMachine)
|
||||
{
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
WintunDllResourceName = L"wintun-amd64.dll";
|
||||
break;
|
||||
case IMAGE_FILE_MACHINE_ARM64:
|
||||
WintunDllResourceName = L"wintun-arm64.dll";
|
||||
break;
|
||||
default:
|
||||
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
|
||||
LastError = ERROR_NOT_SUPPORTED;
|
||||
goto cleanupDirectory;
|
||||
}
|
||||
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
|
||||
{
|
||||
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
|
||||
goto cleanupDelete;
|
||||
}
|
||||
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1 + wcslen(Function) + 1;
|
||||
LPWSTR CommandLine = AllocArray(CommandLineLen, sizeof(*CommandLine));
|
||||
if (!CommandLine)
|
||||
{
|
||||
LastError = GetLastError();
|
||||
goto cleanupDelete;
|
||||
}
|
||||
if (_snwprintf_s(
|
||||
CommandLine,
|
||||
CommandLineLen,
|
||||
_TRUNCATE,
|
||||
L"rundll32 \"%.*s\",%s %s",
|
||||
MAX_PATH,
|
||||
DllPath,
|
||||
Function,
|
||||
Arguments) == -1)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupDelete;
|
||||
}
|
||||
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
|
||||
StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
|
||||
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
|
||||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
|
||||
goto cleanupPipes;
|
||||
}
|
||||
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
|
||||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
|
||||
goto cleanupPipes;
|
||||
}
|
||||
if (ResponseCapacity)
|
||||
Response[0] = 0;
|
||||
PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
|
||||
.Response = Response,
|
||||
.ResponseCapacity = ResponseCapacity };
|
||||
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
|
||||
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
|
||||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
|
||||
goto cleanupThreads;
|
||||
}
|
||||
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
|
||||
.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
|
||||
.wShowWindow = SW_HIDE,
|
||||
.hStdOutput = StreamWStdout,
|
||||
.hStdError = StreamWStderr };
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
|
||||
goto cleanupThreads;
|
||||
}
|
||||
LastError = ERROR_SUCCESS;
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
cleanupThreads:
|
||||
if (ThreadStderr)
|
||||
{
|
||||
CloseHandle(StreamWStderr);
|
||||
StreamWStderr = INVALID_HANDLE_VALUE;
|
||||
WaitForSingleObject(ThreadStderr, INFINITE);
|
||||
CloseHandle(ThreadStderr);
|
||||
}
|
||||
if (ThreadStdout)
|
||||
{
|
||||
CloseHandle(StreamWStdout);
|
||||
StreamWStdout = INVALID_HANDLE_VALUE;
|
||||
WaitForSingleObject(ThreadStdout, INFINITE);
|
||||
DWORD ThreadResult;
|
||||
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
|
||||
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
|
||||
else if (ThreadResult != ERROR_SUCCESS)
|
||||
LOG_ERROR(LastError, L"Failed to read process output");
|
||||
CloseHandle(ThreadStdout);
|
||||
}
|
||||
cleanupPipes:
|
||||
CloseHandle(StreamRStderr);
|
||||
CloseHandle(StreamWStderr);
|
||||
CloseHandle(StreamRStdout);
|
||||
CloseHandle(StreamWStdout);
|
||||
Free(CommandLine);
|
||||
cleanupDelete:
|
||||
DeleteFileW(DllPath);
|
||||
cleanupDirectory:
|
||||
RemoveDirectoryW(RandomTempSubDirectory);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
WINTUN_ADAPTER *
|
||||
CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||
LPWSTR Arguments = NULL;
|
||||
if (RequestedGUID)
|
||||
{
|
||||
WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
|
||||
if (StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)))
|
||||
Arguments = ArgvToCommandLineW(3, Pool, Name, RequestedGUIDStr);
|
||||
}
|
||||
else
|
||||
Arguments = ArgvToCommandLineW(2, Pool, Name);
|
||||
if (!Arguments)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
WINTUN_ADAPTER *Adapter = NULL;
|
||||
DWORD LastError;
|
||||
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
|
||||
if (!ExecuteRunDll32(L"CreateAdapter", Arguments, Response, _countof(Response)))
|
||||
{
|
||||
LastError = GetLastError();
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
goto cleanupArguments;
|
||||
}
|
||||
int Argc;
|
||||
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
|
||||
if (Argc < 3)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupArgv;
|
||||
}
|
||||
LastError = wcstoul(Argv[0], NULL, 16);
|
||||
if (LastError == ERROR_SUCCESS && (Adapter = AdapterOpenFromDevInstanceId(Pool, Argv[1])) == NULL)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]);
|
||||
LastError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
if (wcstoul(Argv[2], NULL, 16))
|
||||
*RebootRequired = TRUE;
|
||||
cleanupArgv:
|
||||
LocalFree(Argv);
|
||||
cleanupArguments:
|
||||
Free(Arguments);
|
||||
SetLastError(LastError);
|
||||
return Adapter;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||
LPWSTR Arguments = ArgvToCommandLineW(3, Adapter->Pool, Adapter->DevInstanceID, ForceCloseSessions ? L"1" : L"0");
|
||||
if (!Arguments)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR Response[8 + 1 + 8 + 1];
|
||||
DWORD LastError;
|
||||
if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response)))
|
||||
{
|
||||
LastError = GetLastError();
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
goto cleanupArguments;
|
||||
}
|
||||
int Argc;
|
||||
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
|
||||
if (Argc < 2)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupArgv;
|
||||
}
|
||||
LastError = wcstoul(Argv[0], NULL, 16);
|
||||
if (wcstoul(Argv[1], NULL, 16))
|
||||
*RebootRequired = TRUE;
|
||||
cleanupArgv:
|
||||
LocalFree(Argv);
|
||||
cleanupArguments:
|
||||
Free(Arguments);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
BOOL
|
||||
DeletePoolDriverViaRundll32(LPCWSTR Pool, BOOL *RebootRequired)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||
LPWSTR Arguments = ArgvToCommandLineW(1, Pool);
|
||||
if (!Arguments)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR Response[8 + 1 + 8 + 1];
|
||||
DWORD LastError;
|
||||
if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response)))
|
||||
{
|
||||
LastError = GetLastError();
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
goto cleanupArguments;
|
||||
}
|
||||
int Argc;
|
||||
LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
|
||||
if (Argc < 2)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response);
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupArgv;
|
||||
}
|
||||
LastError = wcstoul(Argv[0], NULL, 16);
|
||||
if (wcstoul(Argv[1], NULL, 16))
|
||||
*RebootRequired = TRUE;
|
||||
cleanupArgv:
|
||||
LocalFree(Argv);
|
||||
cleanupArguments:
|
||||
Free(Arguments);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
||||
#endif
|
||||
|
29
api/rundll32.h
Normal file
29
api/rundll32.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "adapter.h"
|
||||
|
||||
_Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
WINTUN_ADAPTER *
|
||||
CreateAdapterViaRundll32(
|
||||
_In_z_ LPCWSTR Pool,
|
||||
_In_z_ LPCWSTR Name,
|
||||
_In_opt_ const GUID *RequestedGUID,
|
||||
_Inout_ BOOL *RebootRequired);
|
||||
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
DeleteAdapterViaRundll32(
|
||||
_In_ const WINTUN_ADAPTER *Adapter,
|
||||
_In_ BOOL ForceCloseSessions,
|
||||
_Inout_ BOOL *RebootRequired);
|
||||
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL
|
||||
DeletePoolDriverViaRundll32(_In_z_ LPCWSTR Pool, _Inout_ BOOL *RebootRequired);
|
352
api/rundll32_i.c
352
api/rundll32_i.c
@ -1,352 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* TODO: This is currently #include'd in adapter.c. Move into rundll32.c properly. */
|
||||
|
||||
typedef struct _PROCESS_STDOUT_STATE
|
||||
{
|
||||
HANDLE Stdout;
|
||||
WCHAR *Response;
|
||||
DWORD ResponseCapacity;
|
||||
} PROCESS_STDOUT_STATE;
|
||||
|
||||
static DWORD WINAPI
|
||||
ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
|
||||
{
|
||||
for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
|
||||
{
|
||||
DWORD SizeRead;
|
||||
if (!ReadFile(State->Stdout, State->Response + Offset, sizeof(WCHAR) * (MaxLen - Offset), &SizeRead, NULL))
|
||||
return ERROR_SUCCESS;
|
||||
if (SizeRead % sizeof(WCHAR))
|
||||
return ERROR_INVALID_DATA;
|
||||
Offset += SizeRead / sizeof(WCHAR);
|
||||
State->Response[Offset] = 0;
|
||||
}
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
static DWORD WINAPI
|
||||
ProcessStderr(_In_ HANDLE Stderr)
|
||||
{
|
||||
enum
|
||||
{
|
||||
OnNone,
|
||||
OnLevelStart,
|
||||
OnLevel,
|
||||
OnLevelEnd,
|
||||
OnSpace,
|
||||
OnMsg
|
||||
} State = OnNone;
|
||||
WCHAR Msg[0x200];
|
||||
DWORD Count = 0;
|
||||
WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO;
|
||||
for (;;)
|
||||
{
|
||||
WCHAR Buf[0x200];
|
||||
DWORD SizeRead;
|
||||
if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL))
|
||||
return ERROR_SUCCESS;
|
||||
if (SizeRead % sizeof(WCHAR))
|
||||
return ERROR_INVALID_DATA;
|
||||
SizeRead /= sizeof(WCHAR);
|
||||
for (DWORD i = 0; i < SizeRead; ++i)
|
||||
{
|
||||
WCHAR c = Buf[i];
|
||||
if (State == OnNone && c == L'[')
|
||||
State = OnLevelStart;
|
||||
else if (
|
||||
State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') ||
|
||||
(Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!')))
|
||||
State = OnLevelEnd;
|
||||
else if (State == OnLevelEnd && c == L']')
|
||||
State = OnSpace;
|
||||
else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n')
|
||||
{
|
||||
if (Count < _countof(Msg) - 1)
|
||||
Msg[Count++] = c;
|
||||
State = OnMsg;
|
||||
}
|
||||
else if (State == OnMsg && c == L'\n')
|
||||
{
|
||||
Msg[Count] = 0;
|
||||
LoggerLog(Level, NULL, Msg);
|
||||
State = OnNone;
|
||||
Count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != FALSE) BOOL ExecuteRunDll32(
|
||||
_In_z_ const WCHAR *Arguments,
|
||||
_Out_z_cap_c_(ResponseCapacity) WCHAR *Response,
|
||||
_In_ DWORD ResponseCapacity)
|
||||
{
|
||||
WCHAR WindowsDirectory[MAX_PATH];
|
||||
if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
|
||||
{
|
||||
LOG_LAST_ERROR(L"Failed to get Windows folder");
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR RunDll32Path[MAX_PATH];
|
||||
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
|
||||
{
|
||||
SetLastError(ERROR_BUFFER_OVERFLOW);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD LastError;
|
||||
WCHAR RandomTempSubDirectory[MAX_PATH];
|
||||
if (!CreateTemporaryDirectory(RandomTempSubDirectory))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder %s", RandomTempSubDirectory);
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR DllPath[MAX_PATH] = { 0 };
|
||||
if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll"))
|
||||
{
|
||||
LastError = ERROR_BUFFER_OVERFLOW;
|
||||
goto cleanupDirectory;
|
||||
}
|
||||
const WCHAR *WintunDllResourceName;
|
||||
switch (NativeMachine)
|
||||
{
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
WintunDllResourceName = L"wintun-amd64.dll";
|
||||
break;
|
||||
case IMAGE_FILE_MACHINE_ARM64:
|
||||
WintunDllResourceName = L"wintun-arm64.dll";
|
||||
break;
|
||||
default:
|
||||
LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
|
||||
LastError = ERROR_NOT_SUPPORTED;
|
||||
goto cleanupDirectory;
|
||||
}
|
||||
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
|
||||
{
|
||||
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
|
||||
goto cleanupDelete;
|
||||
}
|
||||
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1;
|
||||
WCHAR *CommandLine = Alloc(CommandLineLen * sizeof(WCHAR));
|
||||
if (!CommandLine)
|
||||
{
|
||||
LastError = GetLastError();
|
||||
goto cleanupDelete;
|
||||
}
|
||||
if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) ==
|
||||
-1)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupDelete;
|
||||
}
|
||||
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
|
||||
StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
|
||||
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
|
||||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to create pipes");
|
||||
goto cleanupPipes;
|
||||
}
|
||||
if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
|
||||
!SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
|
||||
goto cleanupPipes;
|
||||
}
|
||||
if (ResponseCapacity)
|
||||
Response[0] = 0;
|
||||
PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
|
||||
.Response = Response,
|
||||
.ResponseCapacity = ResponseCapacity };
|
||||
HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
|
||||
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
|
||||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
|
||||
goto cleanupThreads;
|
||||
}
|
||||
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
|
||||
.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
|
||||
.wShowWindow = SW_HIDE,
|
||||
.hStdOutput = StreamWStdout,
|
||||
.hStdError = StreamWStderr };
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
||||
{
|
||||
LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
|
||||
goto cleanupThreads;
|
||||
}
|
||||
LastError = ERROR_SUCCESS;
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
cleanupThreads:
|
||||
if (ThreadStderr)
|
||||
{
|
||||
CloseHandle(StreamWStderr);
|
||||
StreamWStderr = INVALID_HANDLE_VALUE;
|
||||
WaitForSingleObject(ThreadStderr, INFINITE);
|
||||
CloseHandle(ThreadStderr);
|
||||
}
|
||||
if (ThreadStdout)
|
||||
{
|
||||
CloseHandle(StreamWStdout);
|
||||
StreamWStdout = INVALID_HANDLE_VALUE;
|
||||
WaitForSingleObject(ThreadStdout, INFINITE);
|
||||
DWORD ThreadResult;
|
||||
if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
|
||||
LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
|
||||
else if (ThreadResult != ERROR_SUCCESS)
|
||||
LOG_ERROR(LastError, L"Failed to read process output");
|
||||
CloseHandle(ThreadStdout);
|
||||
}
|
||||
cleanupPipes:
|
||||
CloseHandle(StreamRStderr);
|
||||
CloseHandle(StreamWStderr);
|
||||
CloseHandle(StreamRStdout);
|
||||
CloseHandle(StreamWStdout);
|
||||
Free(CommandLine);
|
||||
cleanupDelete:
|
||||
DeleteFileW(DllPath);
|
||||
cleanupDirectory:
|
||||
RemoveDirectoryW(RandomTempSubDirectory);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32(
|
||||
_In_z_ const WCHAR *Pool,
|
||||
_In_z_ const WCHAR *Name,
|
||||
_In_opt_ const GUID *RequestedGUID,
|
||||
_Inout_ BOOL *RebootRequired)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||
WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN];
|
||||
WCHAR Arguments[15 + WINTUN_MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1];
|
||||
if (_snwprintf_s(
|
||||
Arguments,
|
||||
_countof(Arguments),
|
||||
_TRUNCATE,
|
||||
RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"",
|
||||
Pool,
|
||||
Name,
|
||||
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
|
||||
RequestedGUIDStr) == -1)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1];
|
||||
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
return NULL;
|
||||
}
|
||||
DWORD LastError;
|
||||
WINTUN_ADAPTER *Adapter = NULL;
|
||||
int Argc;
|
||||
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
||||
GUID CfgInstanceID;
|
||||
if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID)))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupArgv;
|
||||
}
|
||||
LastError = wcstoul(Argv[0], NULL, 16);
|
||||
if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]);
|
||||
LastError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
if (wcstoul(Argv[2], NULL, 16))
|
||||
*RebootRequired = TRUE;
|
||||
cleanupArgv:
|
||||
LocalFree(Argv);
|
||||
SetLastError(LastError);
|
||||
return Adapter;
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != FALSE) BOOL DeleteAdapterViaRundll32(
|
||||
_In_ const WINTUN_ADAPTER *Adapter,
|
||||
_In_ BOOL ForceCloseSessions,
|
||||
_Inout_ BOOL *RebootRequired)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||
WCHAR GuidStr[MAX_GUID_STRING_LEN];
|
||||
WCHAR Arguments[16 + MAX_GUID_STRING_LEN + 1];
|
||||
if (_snwprintf_s(
|
||||
Arguments,
|
||||
_countof(Arguments),
|
||||
_TRUNCATE,
|
||||
L"DeleteAdapter %d %.*s",
|
||||
ForceCloseSessions ? 1 : 0,
|
||||
StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)),
|
||||
GuidStr) == -1)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR Response[8 + 1 + 8 + 1];
|
||||
DWORD LastError;
|
||||
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
return FALSE;
|
||||
}
|
||||
int Argc;
|
||||
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
||||
if (Argc < 2)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupArgv;
|
||||
}
|
||||
LastError = wcstoul(Argv[0], NULL, 16);
|
||||
if (wcstoul(Argv[1], NULL, 16))
|
||||
*RebootRequired = TRUE;
|
||||
cleanupArgv:
|
||||
LocalFree(Argv);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
||||
|
||||
static _Return_type_success_(return != FALSE) BOOL
|
||||
DeletePoolDriverViaRundll32(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
|
||||
{
|
||||
LOG(WINTUN_LOG_INFO, L"Spawning native process");
|
||||
|
||||
WCHAR Arguments[17 + WINTUN_MAX_POOL + 1];
|
||||
if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Command line too long");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
WCHAR Response[8 + 1 + 8 + 1];
|
||||
DWORD LastError;
|
||||
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments);
|
||||
return FALSE;
|
||||
}
|
||||
int Argc;
|
||||
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
|
||||
if (Argc < 2)
|
||||
{
|
||||
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response: %s", Response);
|
||||
LastError = ERROR_INVALID_PARAMETER;
|
||||
goto cleanupArgv;
|
||||
}
|
||||
LastError = wcstoul(Argv[0], NULL, 16);
|
||||
if (wcstoul(Argv[1], NULL, 16))
|
||||
*RebootRequired = TRUE;
|
||||
cleanupArgv:
|
||||
LocalFree(Argv);
|
||||
return RET_ERROR(TRUE, LastError);
|
||||
}
|
@ -70,8 +70,10 @@ typedef struct _TUN_SESSION
|
||||
HANDLE Handle;
|
||||
} TUN_SESSION;
|
||||
|
||||
_Return_type_success_(return != NULL) TUN_SESSION *WINAPI
|
||||
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity)
|
||||
WINTUN_START_SESSION_FUNC_IMPL WintunStartSession;
|
||||
_Use_decl_annotations_
|
||||
TUN_SESSION *WINAPI
|
||||
WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity)
|
||||
{
|
||||
DWORD LastError;
|
||||
TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION));
|
||||
@ -126,8 +128,8 @@ _Return_type_success_(return != NULL) TUN_SESSION *WINAPI
|
||||
goto cleanupHandle;
|
||||
}
|
||||
Session->Capacity = Capacity;
|
||||
(void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
|
||||
(void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
|
||||
(VOID) InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
|
||||
(VOID) InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
|
||||
return Session;
|
||||
cleanupHandle:
|
||||
CloseHandle(Session->Handle);
|
||||
@ -144,8 +146,10 @@ cleanup:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void WINAPI
|
||||
WintunEndSession(_In_ TUN_SESSION *Session)
|
||||
WINTUN_END_SESSION_FUNC_IMPL WintunEndSession;
|
||||
_Use_decl_annotations_
|
||||
VOID WINAPI
|
||||
WintunEndSession(TUN_SESSION *Session)
|
||||
{
|
||||
DeleteCriticalSection(&Session->Send.Lock);
|
||||
DeleteCriticalSection(&Session->Receive.Lock);
|
||||
@ -156,14 +160,18 @@ WintunEndSession(_In_ TUN_SESSION *Session)
|
||||
Free(Session);
|
||||
}
|
||||
|
||||
WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL WintunGetReadWaitEvent;
|
||||
_Use_decl_annotations_
|
||||
HANDLE WINAPI
|
||||
WintunGetReadWaitEvent(_In_ TUN_SESSION *Session)
|
||||
WintunGetReadWaitEvent(TUN_SESSION *Session)
|
||||
{
|
||||
return Session->Descriptor.Send.TailMoved;
|
||||
}
|
||||
|
||||
_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI
|
||||
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize)
|
||||
WINTUN_RECEIVE_PACKET_FUNC_IMPL WintunReceivePacket;
|
||||
_Use_decl_annotations_
|
||||
BYTE *WINAPI
|
||||
WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize)
|
||||
{
|
||||
DWORD LastError;
|
||||
EnterCriticalSection(&Session->Send.Lock);
|
||||
@ -213,8 +221,10 @@ cleanup:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void WINAPI
|
||||
WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
||||
WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL WintunReleaseReceivePacket;
|
||||
_Use_decl_annotations_
|
||||
VOID WINAPI
|
||||
WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet)
|
||||
{
|
||||
EnterCriticalSection(&Session->Send.Lock);
|
||||
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
|
||||
@ -232,8 +242,10 @@ WintunReleaseReceivePacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
||||
LeaveCriticalSection(&Session->Send.Lock);
|
||||
}
|
||||
|
||||
_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI
|
||||
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize)
|
||||
WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL WintunAllocateSendPacket;
|
||||
_Use_decl_annotations_
|
||||
BYTE *WINAPI
|
||||
WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize)
|
||||
{
|
||||
DWORD LastError;
|
||||
EnterCriticalSection(&Session->Receive.Lock);
|
||||
@ -268,8 +280,10 @@ cleanup:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void WINAPI
|
||||
WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
||||
WINTUN_SEND_PACKET_FUNC_IMPL WintunSendPacket;
|
||||
_Use_decl_annotations_
|
||||
VOID WINAPI
|
||||
WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet)
|
||||
{
|
||||
EnterCriticalSection(&Session->Receive.Lock);
|
||||
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
|
||||
@ -285,7 +299,8 @@ WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
||||
TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity);
|
||||
Session->Receive.PacketsToRelease--;
|
||||
}
|
||||
if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease) {
|
||||
if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease)
|
||||
{
|
||||
WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
|
||||
if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable))
|
||||
SetEvent(Session->Descriptor.Receive.TailMoved);
|
||||
|
108
api/wintun.h
108
api/wintun.h
@ -16,7 +16,7 @@ extern "C" {
|
||||
/**
|
||||
* A handle representing Wintun adapter
|
||||
*/
|
||||
typedef void *WINTUN_ADAPTER_HANDLE;
|
||||
typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
|
||||
|
||||
/**
|
||||
* Maximum pool name length including zero terminator
|
||||
@ -41,11 +41,12 @@ typedef void *WINTUN_ADAPTER_HANDLE;
|
||||
* @return If the function succeeds, the return value is the adapter handle. Must be released with WintunFreeAdapter. If
|
||||
* the function fails, the return value is NULL. To get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
|
||||
_In_z_ const WCHAR *Pool,
|
||||
_In_z_ const WCHAR *Name,
|
||||
_In_opt_ const GUID *RequestedGUID,
|
||||
_Out_opt_ BOOL *RebootRequired);
|
||||
typedef _Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC_IMPL)
|
||||
(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name, _In_opt_ const GUID *RequestedGUID, _Out_opt_ BOOL *RebootRequired);
|
||||
typedef WINTUN_CREATE_ADAPTER_FUNC_IMPL *WINTUN_CREATE_ADAPTER_FUNC;
|
||||
|
||||
/**
|
||||
* Opens an existing Wintun adapter.
|
||||
@ -55,14 +56,15 @@ typedef _Return_type_success_(return != NULL) WINTUN_ADAPTER_HANDLE(WINAPI *WINT
|
||||
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
|
||||
*
|
||||
* @return If the function succeeds, the return value is adapter handle. Must be released with WintunFreeAdapter. If the
|
||||
* function fails, the return value is NULL. To get extended error information, call GetLastError. Possible
|
||||
* errors include the following:
|
||||
* ERROR_FILE_NOT_FOUND if adapter with given name is not found;
|
||||
* ERROR_ALREADY_EXISTS if adapter is found but not a Wintun-class or not a member of the pool
|
||||
* function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors
|
||||
* include the following: ERROR_FILE_NOT_FOUND if adapter with given name is not found; ERROR_ALREADY_EXISTS if adapter
|
||||
* is found but not a Wintun-class or not a member of the pool
|
||||
*/
|
||||
typedef _Return_type_success_(return != NULL)
|
||||
WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name);
|
||||
|
||||
typedef _Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_z_ LPCWSTR Name);
|
||||
typedef WINTUN_OPEN_ADAPTER_FUNC_IMPL *WINTUN_OPEN_ADAPTER_FUNC;
|
||||
|
||||
/**
|
||||
* Deletes a Wintun adapter.
|
||||
@ -78,10 +80,10 @@ typedef _Return_type_success_(return != NULL)
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
|
||||
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
||||
_In_ BOOL ForceCloseSessions,
|
||||
_Out_opt_ BOOL *RebootRequired);
|
||||
typedef _Return_type_success_(return != FALSE)
|
||||
BOOL(WINAPI WINTUN_DELETE_ADAPTER_FUNC_IMPL)
|
||||
(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired);
|
||||
typedef WINTUN_DELETE_ADAPTER_FUNC_IMPL *WINTUN_DELETE_ADAPTER_FUNC;
|
||||
|
||||
/**
|
||||
* Called by WintunEnumAdapters for each adapter in the pool.
|
||||
@ -107,15 +109,17 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK)(_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != FALSE) BOOL(
|
||||
WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(_In_z_ const WCHAR *Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param);
|
||||
typedef _Return_type_success_(return != FALSE)
|
||||
BOOL(WINAPI WINTUN_ENUM_ADAPTERS_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _In_ WINTUN_ENUM_CALLBACK Callback, _In_ LPARAM Param);
|
||||
typedef WINTUN_ENUM_ADAPTERS_FUNC_IMPL *WINTUN_ENUM_ADAPTERS_FUNC;
|
||||
|
||||
/**
|
||||
* Releases Wintun adapter resources.
|
||||
*
|
||||
* @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
|
||||
*/
|
||||
typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
|
||||
typedef VOID(WINAPI WINTUN_FREE_ADAPTER_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
|
||||
typedef WINTUN_FREE_ADAPTER_FUNC_IMPL *WINTUN_FREE_ADAPTER_FUNC;
|
||||
|
||||
/**
|
||||
* Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun
|
||||
@ -129,7 +133,8 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != FALSE)
|
||||
BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
|
||||
BOOL(WINAPI WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL)(_In_z_ LPCWSTR Pool, _Out_opt_ BOOL *RebootRequired);
|
||||
typedef WINTUN_DELETE_POOL_DRIVER_FUNC_IMPL *WINTUN_DELETE_POOL_DRIVER_FUNC;
|
||||
|
||||
/**
|
||||
* Returns the LUID of the adapter.
|
||||
@ -138,7 +143,8 @@ typedef _Return_type_success_(return != FALSE)
|
||||
*
|
||||
* @param Luid Pointer to LUID to receive adapter LUID.
|
||||
*/
|
||||
typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
|
||||
typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
|
||||
typedef WINTUN_GET_ADAPTER_LUID_FUNC_IMPL *WINTUN_GET_ADAPTER_LUID_FUNC;
|
||||
|
||||
/**
|
||||
* Returns the name of the Wintun adapter.
|
||||
@ -150,9 +156,11 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad
|
||||
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
|
||||
_In_ WINTUN_ADAPTER_HANDLE Adapter,
|
||||
_Out_cap_c_(MAX_ADAPTER_NAME) WCHAR *Name);
|
||||
typedef _Must_inspect_result_
|
||||
_Return_type_success_(return != FALSE)
|
||||
BOOL(WINAPI WINTUN_GET_ADAPTER_NAME_FUNC_IMPL)
|
||||
(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_writes_z_(MAX_ADAPTER_NAME) LPWSTR Name);
|
||||
typedef WINTUN_GET_ADAPTER_NAME_FUNC_IMPL *WINTUN_GET_ADAPTER_NAME_FUNC;
|
||||
|
||||
/**
|
||||
* Sets name of the Wintun adapter.
|
||||
@ -165,7 +173,8 @@ typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_GET_ADAPTER_N
|
||||
* get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != FALSE)
|
||||
BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
|
||||
BOOL(WINAPI WINTUN_SET_ADAPTER_NAME_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ LPCWSTR Name);
|
||||
typedef WINTUN_SET_ADAPTER_NAME_FUNC_IMPL *WINTUN_SET_ADAPTER_NAME_FUNC;
|
||||
|
||||
/**
|
||||
* Determines the version of the Wintun driver currently loaded.
|
||||
@ -174,7 +183,9 @@ typedef _Return_type_success_(return != FALSE)
|
||||
* zero. To get extended error information, call GetLastError. Possible errors include the following:
|
||||
* ERROR_FILE_NOT_FOUND Wintun not loaded
|
||||
*/
|
||||
typedef DWORD(WINAPI *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(void);
|
||||
typedef _Return_type_success_(return != 0)
|
||||
DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL)(VOID);
|
||||
typedef WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC_IMPL *WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC;
|
||||
|
||||
/**
|
||||
* Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
|
||||
@ -193,7 +204,7 @@ typedef enum
|
||||
*
|
||||
* @param Message Message text.
|
||||
*/
|
||||
typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Message);
|
||||
typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR Message);
|
||||
|
||||
/**
|
||||
* Sets logger callback function.
|
||||
@ -202,7 +213,8 @@ typedef void(CALLBACK *WINTUN_LOGGER_CALLBACK)(_In_ WINTUN_LOGGER_LEVEL Level, _
|
||||
* threads concurrently. Should the logging require serialization, you must handle serialization in
|
||||
* NewLogger. Set to NULL to disable.
|
||||
*/
|
||||
typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
|
||||
typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC_IMPL)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
|
||||
typedef WINTUN_SET_LOGGER_FUNC_IMPL *WINTUN_SET_LOGGER_FUNC;
|
||||
|
||||
/**
|
||||
* Minimum ring capacity.
|
||||
@ -217,7 +229,7 @@ typedef void(WINAPI *WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogg
|
||||
/**
|
||||
* A handle representing Wintun session
|
||||
*/
|
||||
typedef void *WINTUN_SESSION_HANDLE;
|
||||
typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
|
||||
|
||||
/**
|
||||
* Starts Wintun session.
|
||||
@ -230,15 +242,19 @@ typedef void *WINTUN_SESSION_HANDLE;
|
||||
* @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
|
||||
* NULL. To get extended error information, call GetLastError.
|
||||
*/
|
||||
typedef _Return_type_success_(return != NULL)
|
||||
WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
|
||||
typedef _Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC_IMPL)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
|
||||
typedef WINTUN_START_SESSION_FUNC_IMPL *WINTUN_START_SESSION_FUNC;
|
||||
|
||||
/**
|
||||
* Ends Wintun session.
|
||||
*
|
||||
* @param Session Wintun session handle obtained with WintunStartSession
|
||||
*/
|
||||
typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
|
||||
typedef VOID(WINAPI WINTUN_END_SESSION_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
|
||||
typedef WINTUN_END_SESSION_FUNC_IMPL *WINTUN_END_SESSION_FUNC;
|
||||
|
||||
/**
|
||||
* Gets Wintun session's read-wait event handle.
|
||||
@ -250,7 +266,8 @@ typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session
|
||||
* load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call
|
||||
* CloseHandle on this event - it is managed by the session.
|
||||
*/
|
||||
typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
|
||||
typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session);
|
||||
typedef WINTUN_GET_READ_WAIT_EVENT_FUNC_IMPL *WINTUN_GET_READ_WAIT_EVENT_FUNC;
|
||||
|
||||
/**
|
||||
* Maximum IP packet size
|
||||
@ -272,8 +289,12 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND
|
||||
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
|
||||
* ERROR_INVALID_DATA Wintun buffer is corrupt
|
||||
*/
|
||||
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *(
|
||||
WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
|
||||
typedef _Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_(*PacketSize)
|
||||
BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
|
||||
typedef WINTUN_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RECEIVE_PACKET_FUNC;
|
||||
|
||||
/**
|
||||
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
|
||||
@ -282,7 +303,9 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE
|
||||
*
|
||||
* @param Packet Packet obtained with WintunReceivePacket
|
||||
*/
|
||||
typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
|
||||
typedef VOID(
|
||||
WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
|
||||
typedef WINTUN_RELEASE_RECEIVE_PACKET_FUNC_IMPL *WINTUN_RELEASE_RECEIVE_PACKET_FUNC;
|
||||
|
||||
/**
|
||||
* Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
|
||||
@ -299,8 +322,12 @@ typedef void(WINAPI *WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HAN
|
||||
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
||||
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
|
||||
*/
|
||||
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *(
|
||||
WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
|
||||
typedef _Must_inspect_result_
|
||||
_Return_type_success_(return != NULL)
|
||||
_Post_maybenull_
|
||||
_Post_writable_byte_size_(PacketSize)
|
||||
BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
|
||||
typedef WINTUN_ALLOCATE_SEND_PACKET_FUNC_IMPL *WINTUN_ALLOCATE_SEND_PACKET_FUNC;
|
||||
|
||||
/**
|
||||
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
|
||||
@ -311,7 +338,8 @@ typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *
|
||||
*
|
||||
* @param Packet Packet obtained with WintunAllocateSendPacket
|
||||
*/
|
||||
typedef void(WINAPI *WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
|
||||
typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC_IMPL)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
|
||||
typedef WINTUN_SEND_PACKET_FUNC_IMPL *WINTUN_SEND_PACKET_FUNC;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user