api: use GetLastError() to report failures like standard Win32

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-11-03 12:29:34 +01:00
parent 5ad7d10589
commit f657e6fd27
18 changed files with 1326 additions and 1026 deletions

File diff suppressed because it is too large Load Diff

View File

@ -37,28 +37,28 @@ WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
/**
* @copydoc WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC
*/
WINTUN_STATUS WINAPI
WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle);
_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE WINAPI
WintunOpenAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
/**
* @copydoc WINTUN_CREATE_ADAPTER_FUNC
*/
WINTUN_STATUS WINAPI
WintunCreateAdapter(
_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_ WINTUN_ADAPTER **Adapter,
_Out_opt_ BOOL *RebootRequired);
/**
* @copydoc WINTUN_DELETE_ADAPTER_FUNC
*/
WINTUN_STATUS WINAPI
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired);
_Return_type_success_(return != FALSE) BOOL WINAPI WintunDeleteAdapter(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ BOOL ForceCloseSessions,
_Out_opt_ BOOL *RebootRequired);
/**
* @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
*/
WINTUN_STATUS WINAPI
WintunDeletePoolDriver(_In_z_ const WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired);
_Return_type_success_(return != FALSE) BOOL WINAPI
WintunDeletePoolDriver(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);

View File

@ -4,12 +4,12 @@
*/
#include "elevate.h"
#include "logger.h"
#include <Windows.h>
#include <TlHelp32.h>
BOOL
ElevateToSystem(void)
_Return_type_success_(return != FALSE) BOOL ElevateToSystem(void)
{
HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken;
PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) };
@ -25,29 +25,40 @@ ElevateToSystem(void)
} TokenUserBuffer;
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to create SID");
goto cleanup;
}
Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to open process token");
goto cleanup;
}
Ret =
GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
LastError = GetLastError();
CloseHandle(CurrentProcessToken);
if (!Ret)
{
LOG_ERROR(L"Failed to get token information", LastError);
goto cleanup;
}
if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
return TRUE;
Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value");
goto cleanup;
}
ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
LastError = GetLastError();
if (ProcessSnapshot == INVALID_HANDLE_VALUE)
{
LastError = LOG_LAST_ERROR(L"Failed to create toolhelp snapshot");
goto cleanup;
}
for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret;
Ret = Process32NextW(ProcessSnapshot, &ProcessEntry))
{
@ -55,13 +66,17 @@ ElevateToSystem(void)
continue;
RevertToSelf();
Ret = ImpersonateSelf(SecurityImpersonation);
LastError = GetLastError();
if (!Ret)
{
LastError = GetLastError();
continue;
}
Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken);
LastError = GetLastError();
if (!Ret)
{
LastError = GetLastError();
continue;
}
Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
LastError = GetLastError();
CloseHandle(ThreadToken);
@ -69,9 +84,11 @@ ElevateToSystem(void)
continue;
WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID);
LastError = GetLastError();
if (!WinlogonProcess)
{
LastError = GetLastError();
continue;
}
Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken);
LastError = GetLastError();
CloseHandle(WinlogonProcess);
@ -84,13 +101,15 @@ ElevateToSystem(void)
continue;
if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
goto next;
if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
{
SetLastError(ERROR_ACCESS_DENIED);
goto next;
}
if (!SetThreadToken(NULL, DuplicatedToken))
goto next;
CloseHandle(DuplicatedToken);
CloseHandle(ProcessSnapshot);
SetLastError(ERROR_SUCCESS);
return TRUE;
next:
LastError = GetLastError();
@ -103,8 +122,7 @@ cleanup:
return FALSE;
}
HANDLE
GetPrimarySystemTokenFromThread(void)
_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void)
{
HANDLE CurrentThreadToken, DuplicatedToken;
BOOL Ret;
@ -120,26 +138,41 @@ GetPrimarySystemTokenFromThread(void)
Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to create SID");
return NULL;
}
Ret = OpenThreadToken(
GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE, FALSE, &CurrentThreadToken);
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to open thread token");
return NULL;
}
Ret = GetTokenInformation(CurrentThreadToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to get token information");
goto cleanup;
LastError = ERROR_ACCESS_DENIED;
}
if (!EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
{
LOG(WINTUN_LOG_ERR, L"Not SYSTEM");
LastError = ERROR_ACCESS_DENIED;
goto cleanup;
}
Ret = LookupPrivilegeValueW(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &Privileges.Privileges[0].Luid);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to lookup privilege value");
goto cleanup;
}
Ret = AdjustTokenPrivileges(CurrentThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to adjust token privileges");
goto cleanup;
}
Ret = DuplicateTokenEx(
CurrentThreadToken,
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
@ -147,14 +180,16 @@ GetPrimarySystemTokenFromThread(void)
SecurityImpersonation,
TokenPrimary,
&DuplicatedToken);
LastError = GetLastError();
if (!Ret)
{
LastError = LOG_LAST_ERROR(L"Failed to duplicate token");
goto cleanup;
}
CloseHandle(CurrentThreadToken);
return DuplicatedToken;
cleanup:
CloseHandle(CurrentThreadToken);
SetLastError(LastError);
return FALSE;
return NULL;
}

View File

@ -7,8 +7,6 @@
#include <Windows.h>
BOOL
ElevateToSystem(void);
_Return_type_success_(return != FALSE) BOOL ElevateToSystem(void);
HANDLE
GetPrimarySystemTokenFromThread(void);
_Return_type_success_(return != NULL) HANDLE GetPrimarySystemTokenFromThread(void);

View File

@ -22,7 +22,8 @@ HINSTANCE ResourceModule;
HANDLE ModuleHeap;
SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
static FARPROC WINAPI DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
static FARPROC WINAPI
DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if (dliNotify != dliNotePreLoadLibrary)
return NULL;
@ -53,7 +54,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
break;
case DLL_PROCESS_DETACH:
NamespaceCleanup();
NamespaceDone();
LocalFree(SecurityAttributes.lpSecurityDescriptor);
HeapDestroy(ModuleHeap);
break;

View File

@ -26,6 +26,8 @@
#endif
#pragma warning(disable : 4127) /* conditional expression is constant */
#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
extern HINSTANCE ResourceModule;
extern HANDLE ModuleHeap;
extern SECURITY_ATTRIBUTES SecurityAttributes;

View File

@ -16,20 +16,29 @@ extern WINTUN_LOGGER_CALLBACK_FUNC Logger;
void WINAPI
WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK_FUNC NewLogger);
static inline _Post_equals_last_error_ DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
{
DWORD LastError = GetLastError();
Logger(Level, LogLine);
SetLastError(LastError);
return LastError;
}
_Post_equals_last_error_ DWORD
LoggerError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error);
static inline _Post_equals_last_error_ DWORD
LoggerLastError(_In_z_ const WCHAR *Prefix)
{
DWORD Error = GetLastError();
LoggerError(Prefix, Error);
SetLastError(Error);
return Error;
DWORD LastError = GetLastError();
LoggerError(Prefix, LastError);
SetLastError(LastError);
return LastError;
}
#define __L(x) L##x
#define _L(x) __L(x)
#define LOG(lvl, msg) (Logger((lvl), _L(__FUNCTION__) L": " msg))
#define LOG(lvl, msg) (LoggerLog((lvl), _L(__FUNCTION__) L": " msg))
#define LOG_ERROR(msg, err) (LoggerError(_L(__FUNCTION__) L": " msg, (err)))
#define LOG_LAST_ERROR(msg) (LoggerLastError(_L(__FUNCTION__) L": " msg))

View File

@ -15,41 +15,48 @@ static BOOL HasInitialized = FALSE;
static CRITICAL_SECTION Initializing;
static BCRYPT_ALG_HANDLE AlgProvider;
static WCHAR *
NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source)
static _Return_type_success_(
return != NULL) WCHAR *NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ const WCHAR *Source)
{
int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
for (;;)
{
WCHAR *Str = HeapAlloc(ModuleHeap, 0, sizeof(WCHAR) * Len);
if (!Str)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), NULL;
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
Len = NormalizeString(NormForm, Source, -1, Str, Len);
if (Len > 0)
return Str;
DWORD Result = GetLastError();
DWORD LastError = GetLastError();
HeapFree(ModuleHeap, 0, Str);
if (Result != ERROR_INSUFFICIENT_BUFFER)
return LOG_ERROR(L"Failed", Result), NULL;
if (LastError != ERROR_INSUFFICIENT_BUFFER)
{
SetLastError(LOG_ERROR(L"Failed", LastError));
return NULL;
}
Len = -Len;
}
}
static WINTUN_STATUS
NamespaceRuntimeInit(void)
static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void)
{
DWORD Result;
DWORD LastError;
EnterCriticalSection(&Initializing);
if (HasInitialized)
{
LeaveCriticalSection(&Initializing);
return ERROR_SUCCESS;
return TRUE;
}
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0)))
{
Result = ERROR_GEN_FAILURE;
LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider");
LastError = ERROR_GEN_FAILURE;
goto cleanupLeaveCriticalSection;
}
@ -57,19 +64,19 @@ NamespaceRuntimeInit(void)
DWORD SidSize = MAX_SID_SIZE;
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, Sid, &SidSize))
{
Result = GetLastError();
LastError = LOG_LAST_ERROR(L"Failed to create SID");
goto cleanupBCryptCloseAlgorithmProvider;
}
HANDLE Boundary = CreateBoundaryDescriptorW(L"Wintun", 0);
if (!Boundary)
{
Result = GetLastError();
LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor");
goto cleanupBCryptCloseAlgorithmProvider;
}
if (!AddSIDToBoundaryDescriptor(&Boundary, Sid))
{
Result = GetLastError();
LastError = LOG_LAST_ERROR(L"Failed to add SID to boundary descriptor");
goto cleanupBCryptCloseAlgorithmProvider;
}
@ -77,99 +84,125 @@ NamespaceRuntimeInit(void)
{
if (CreatePrivateNamespaceW(&SecurityAttributes, Boundary, L"Wintun"))
break;
Result = GetLastError();
if (Result == ERROR_ALREADY_EXISTS)
if ((LastError = GetLastError()) == ERROR_ALREADY_EXISTS)
{
if (OpenPrivateNamespaceW(Boundary, L"Wintun"))
break;
Result = GetLastError();
if (Result == ERROR_PATH_NOT_FOUND)
if ((LastError = GetLastError()) == ERROR_PATH_NOT_FOUND)
continue;
LOG_ERROR(L"Failed to open private namespace", LastError);
}
else
LOG_ERROR(L"Failed to create private namespace", LastError);
goto cleanupBCryptCloseAlgorithmProvider;
}
HasInitialized = TRUE;
Result = ERROR_SUCCESS;
goto cleanupLeaveCriticalSection;
LeaveCriticalSection(&Initializing);
return TRUE;
cleanupBCryptCloseAlgorithmProvider:
BCryptCloseAlgorithmProvider(AlgProvider, 0);
cleanupLeaveCriticalSection:
LeaveCriticalSection(&Initializing);
return Result;
SetLastError(LastError);
return FALSE;
}
_Check_return_
HANDLE
NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool)
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool)
{
HANDLE Mutex = NULL;
if (NamespaceRuntimeInit() != ERROR_SUCCESS)
if (!NamespaceRuntimeInit())
return NULL;
BCRYPT_HASH_HANDLE Sha256 = NULL;
if (!BCRYPT_SUCCESS(BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to create hash");
SetLastError(ERROR_GEN_FAILURE);
return NULL;
}
DWORD LastError;
static const WCHAR mutex_label[] = L"Wintun Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com";
if (!BCRYPT_SUCCESS(BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
if (!BCRYPT_SUCCESS(
BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to hash data");
LastError = ERROR_GEN_FAILURE;
goto cleanupSha256;
}
WCHAR *PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
if (!PoolNorm)
{
LastError = GetLastError();
goto cleanupSha256;
if (!BCRYPT_SUCCESS(BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
}
if (!BCRYPT_SUCCESS(
BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to hash data");
LastError = ERROR_GEN_FAILURE;
goto cleanupPoolNorm;
}
BYTE Hash[32];
if (!BCRYPT_SUCCESS(BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to calculate hash");
LastError = ERROR_GEN_FAILURE;
goto cleanupPoolNorm;
}
static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-Name-Mutex-";
WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2];
memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix));
for (size_t i = 0; i < sizeof(Hash); ++i)
swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]);
Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
if (!Mutex)
{
LastError = LOG_LAST_ERROR(L"Failed to create mutex");
goto cleanupPoolNorm;
}
switch (WaitForSingleObject(Mutex, INFINITE))
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
goto cleanupPoolNorm;
HeapFree(ModuleHeap, 0, PoolNorm);
BCryptDestroyHash(Sha256);
return Mutex;
}
LOG(WINTUN_LOG_ERR, L"Failed to get mutex");
LastError = ERROR_GEN_FAILURE;
CloseHandle(Mutex);
Mutex = NULL;
cleanupPoolNorm:
HeapFree(ModuleHeap, 0, PoolNorm);
cleanupSha256:
BCryptDestroyHash(Sha256);
return Mutex;
SetLastError(LastError);
return NULL;
}
_Check_return_
HANDLE
NamespaceTakeDriverInstallationMutex(void)
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void)
{
HANDLE Mutex = NULL;
if (NamespaceRuntimeInit() != ERROR_SUCCESS)
if (!NamespaceRuntimeInit())
return NULL;
Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex");
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex");
if (!Mutex)
{
LOG_LAST_ERROR(L"Failed to create mutex");
return NULL;
}
switch (WaitForSingleObject(Mutex, INFINITE))
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
goto out;
}
CloseHandle(Mutex);
Mutex = NULL;
out:
return Mutex;
}
LOG(WINTUN_LOG_ERR, L"Failed to get mutex");
CloseHandle(Mutex);
SetLastError(ERROR_GEN_FAILURE);
return NULL;
}
void
NamespaceReleaseMutex(_In_ HANDLE Mutex)
@ -185,7 +218,7 @@ NamespaceInit(void)
}
void
NamespaceCleanup(void)
NamespaceDone(void)
{
EnterCriticalSection(&Initializing);
if (HasInitialized)

View File

@ -8,12 +8,10 @@
#include <Windows.h>
_Check_return_
HANDLE
NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool);
_Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const WCHAR *Pool);
_Check_return_
HANDLE
NamespaceTakeDriverInstallationMutex(void);
_Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMutex(void);
void
NamespaceReleaseMutex(_In_ HANDLE Mutex);
@ -22,4 +20,4 @@ void
NamespaceInit(void);
void
NamespaceCleanup(void);
NamespaceDone(void);

View File

@ -9,42 +9,54 @@
#include <Windows.h>
#include <wchar.h>
static WINTUN_STATUS
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline, _Out_ HKEY *KeyOut)
static _Return_type_success_(return != NULL) HKEY
OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGLONG Deadline)
{
DWORD Result;
DWORD LastError;
WCHAR *PathNext = wcschr(Path, L'\\');
if (PathNext)
*PathNext = 0;
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!Event)
return LOG_LAST_ERROR(L"Failed to create event");
{
LOG_LAST_ERROR(L"Failed to create event");
return NULL;
}
for (;;)
{
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
if (Result != ERROR_SUCCESS)
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
if (LastError != ERROR_SUCCESS)
{
LOG_ERROR(L"Failed to setup notification", Result);
LOG_ERROR(L"Failed to setup notification", LastError);
break;
}
HKEY Subkey;
Result = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
if (Result == ERROR_SUCCESS)
LastError = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
if (LastError == ERROR_SUCCESS)
{
if (PathNext)
{
Result = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline, KeyOut);
HKEY KeyOut = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline);
if (KeyOut)
{
RegCloseKey(Subkey);
CloseHandle(Event);
return KeyOut;
}
else
*KeyOut = Subkey;
LastError = GetLastError();
break;
}
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
else
{
LOG_ERROR(L"Failed to open", Result);
CloseHandle(Event);
return Subkey;
}
}
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
{
LOG_ERROR(L"Failed to open", LastError);
break;
}
@ -58,27 +70,35 @@ OpenKeyWait(_In_ HKEY Key, _Inout_z_ WCHAR *Path, _In_ DWORD Access, _In_ ULONGL
}
}
CloseHandle(Event);
return Result;
SetLastError(LastError);
return NULL;
}
WINTUN_STATUS
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut)
_Return_type_success_(return != NULL) HKEY
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout)
{
WCHAR Buf[MAX_REG_PATH];
if (wcsncpy_s(Buf, _countof(Buf), Path, _TRUNCATE) == STRUNCATE)
return LOG(WINTUN_LOG_ERR, L"Registry path too long"), ERROR_INVALID_PARAMETER;
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut);
{
LOG(WINTUN_LOG_ERR, L"Registry path too long");
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout);
}
WINTUN_STATUS
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
_Return_type_success_(return != FALSE) BOOL RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
{
if (wcsnlen(*Buf, Len) >= Len)
{
/* String is missing zero-terminator. */
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
if (!BufZ)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
HeapFree(ModuleHeap, 0, *Buf);
@ -86,25 +106,30 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
}
if (ValueType != REG_EXPAND_SZ)
return ERROR_SUCCESS;
return TRUE;
/* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to
* disambiguate. */
if (!(*Buf)[0])
return ERROR_SUCCESS;
return TRUE;
Len = Len * 2 + 64;
for (;;)
{
WCHAR *Expanded = HeapAlloc(ModuleHeap, 0, Len * sizeof(WCHAR));
if (!Expanded)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
if (!Result)
{
Result = LOG_LAST_ERROR(L"Failed to expand environment variables");
DWORD LastError = LOG_LAST_ERROR(L"Failed to expand environment variables");
HeapFree(ModuleHeap, 0, Expanded);
return Result;
SetLastError(LastError);
return FALSE;
}
if (Result > Len)
{
@ -114,11 +139,11 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
}
HeapFree(ModuleHeap, 0, *Buf);
*Buf = Expanded;
return ERROR_SUCCESS;
return TRUE;
}
}
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType)
{
if (ValueType == REG_MULTI_SZ)
@ -130,52 +155,61 @@ RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType
/* Missing string and list terminators. */
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 2) * sizeof(WCHAR));
if (!BufZ)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
BufZ[Len + 1] = 0;
HeapFree(ModuleHeap, 0, *Buf);
*Buf = BufZ;
return ERROR_SUCCESS;
return TRUE;
}
if (i == Len)
{
/* Missing list terminator. */
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
if (!BufZ)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
HeapFree(ModuleHeap, 0, *Buf);
*Buf = BufZ;
return ERROR_SUCCESS;
return TRUE;
}
if (!(*Buf)[i])
return ERROR_SUCCESS;
return TRUE;
}
}
/* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */
DWORD Result = RegistryGetString(Buf, Len, ValueType);
if (Result != ERROR_SUCCESS)
return Result;
if (!RegistryGetString(Buf, Len, ValueType))
return FALSE;
Len = (DWORD)wcslen(*Buf) + 1;
WCHAR *BufZ = HeapAlloc(ModuleHeap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
if (!BufZ)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
wmemcpy(BufZ, *Buf, Len);
BufZ[Len] = 0;
HeapFree(ModuleHeap, 0, *Buf);
*Buf = BufZ;
return ERROR_SUCCESS;
return TRUE;
}
static WINTUN_STATUS
RegistryQuery(
static _Return_type_success_(return != NULL) void *RegistryQuery(
_In_ HKEY Key,
_In_opt_z_ const WCHAR *Name,
_Out_opt_ DWORD *ValueType,
_Out_ void **Buf,
_Inout_ DWORD *BufLen,
_In_ BOOL Log)
{
@ -183,60 +217,77 @@ RegistryQuery(
{
BYTE *p = HeapAlloc(ModuleHeap, 0, *BufLen);
if (!p)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
LSTATUS Result = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen);
if (Result == ERROR_SUCCESS)
{
*Buf = p;
return ERROR_SUCCESS;
LOG(WINTUN_LOG_ERR, L"Out of memory");
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
LSTATUS LastError = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen);
if (LastError == ERROR_SUCCESS)
return p;
HeapFree(ModuleHeap, 0, p);
if (Result != ERROR_MORE_DATA)
return Log ? LOG_ERROR(L"Querying value failed", Result) : Result;
if (LastError != ERROR_MORE_DATA)
{
if (Log)
LOG_ERROR(L"Querying value failed", LastError);
SetLastError(LastError);
return NULL;
}
}
}
WINTUN_STATUS
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **Value, _In_ BOOL Log)
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log)
{
DWORD ValueType, Size = 256 * sizeof(WCHAR);
DWORD Result = RegistryQuery(Key, Name, &ValueType, Value, &Size, Log);
if (Result != ERROR_SUCCESS)
return Result;
DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR);
WCHAR *Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
if (!Value)
return NULL;
switch (ValueType)
{
case REG_SZ:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
Result = RegistryGetString(Value, Size / sizeof(WCHAR), ValueType);
if (Result != ERROR_SUCCESS)
HeapFree(ModuleHeap, 0, *Value);
return Result;
if (RegistryGetString(&Value, Size / sizeof(WCHAR), ValueType))
return Value;
LastError = GetLastError();
break;
default:
LOG(WINTUN_LOG_ERR, L"Value is not a string");
HeapFree(ModuleHeap, 0, *Value);
return ERROR_INVALID_DATATYPE;
LastError = ERROR_INVALID_DATATYPE;
}
HeapFree(ModuleHeap, 0, Value);
SetLastError(LastError);
return NULL;
}
WINTUN_STATUS
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ WCHAR **Value)
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout)
{
DWORD Result;
DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout;
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!Event)
return LOG_LAST_ERROR(L"Failed to create event");
{
LOG_LAST_ERROR(L"Failed to create event");
return NULL;
}
for (;;)
{
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
if (Result != ERROR_SUCCESS)
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
if (LastError != ERROR_SUCCESS)
{
LOG_ERROR(L"Failed to setup notification", Result);
LOG_ERROR(L"Failed to setup notification", LastError);
break;
}
Result = RegistryQueryString(Key, Name, Value, FALSE);
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
WCHAR *Value = RegistryQueryString(Key, Name, FALSE);
if (Value)
{
CloseHandle(Event);
return Value;
}
LastError = GetLastError();
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
break;
LONGLONG TimeLeft = Deadline - GetTickCount64();
if (TimeLeft < 0)
@ -248,51 +299,63 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD
}
}
CloseHandle(Event);
return Result;
SetLastError(LastError);
return NULL;
}
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log)
{
DWORD ValueType, Size = sizeof(DWORD);
DWORD Result = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
if (Result != ERROR_SUCCESS)
DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
if (LastError != ERROR_SUCCESS)
{
if (Log)
LOG_ERROR(L"Querying failed", Result);
return Result;
LOG_ERROR(L"Querying failed", LastError);
SetLastError(LastError);
return FALSE;
}
if (ValueType != REG_DWORD)
{
LOG(WINTUN_LOG_ERR, L"Value is not a DWORD");
return ERROR_INVALID_DATATYPE;
SetLastError(ERROR_INVALID_DATATYPE);
return FALSE;
}
if (Size != sizeof(DWORD))
{
LOG(WINTUN_LOG_ERR, L"Value size is not 4 bytes");
return ERROR_INVALID_DATA;
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
return ERROR_SUCCESS;
return TRUE;
}
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
{
DWORD Result;
DWORD LastError;
ULONGLONG Deadline = GetTickCount64() + Timeout;
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!Event)
return LOG_LAST_ERROR(L"Failed to create event");
{
LOG_LAST_ERROR(L"Failed to create event");
return FALSE;
}
for (;;)
{
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
if (Result != ERROR_SUCCESS)
LastError = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
if (LastError != ERROR_SUCCESS)
{
LOG_ERROR(L"Failed to setup notification", Result);
LOG_ERROR(L"Failed to setup notification", LastError);
break;
}
Result = RegistryQueryDWORD(Key, Name, Value, FALSE);
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
if (RegistryQueryDWORD(Key, Name, Value, FALSE))
{
CloseHandle(Event);
return TRUE;
}
LastError = GetLastError();
if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND)
break;
LONGLONG TimeLeft = Deadline - GetTickCount64();
if (TimeLeft < 0)
@ -304,5 +367,6 @@ RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD T
}
}
CloseHandle(Event);
return Result;
SetLastError(LastError);
return FALSE;
}

View File

@ -23,12 +23,11 @@
*
* @param Timeout Timeout to wait for the value in milliseconds.
*
* @param KeyOut Pointer to a variable to receive the key handle.
*
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; Win32 error code otherwise.
* @return Key handle on success. If the function fails, the return value is zero. To get extended error information,
* call GetLastError.
*/
WINTUN_STATUS
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout, _Out_ HKEY *KeyOut);
_Return_type_success_(return != NULL) HKEY
RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access, _In_ DWORD Timeout);
/**
* Validates and/or sanitizes string value read from registry.
@ -42,9 +41,10 @@ RegistryOpenKeyWait(_In_ HKEY Key, _In_z_ const WCHAR *Path, _In_ DWORD Access,
* @param ValueType Type of data. Must be either REG_SZ or REG_EXPAND_SZ. REG_MULTI_SZ is treated like REG_SZ; only
* the first string of a multi-string is to be used.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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.
*/
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
/**
@ -58,9 +58,10 @@ RegistryGetString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
*
* @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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.
*/
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType);
/**
@ -79,11 +80,11 @@ RegistryGetMultiString(_Inout_ WCHAR **Buf, _In_ DWORD Len, _In_ DWORD ValueType
* errors reduces log clutter when we are using RegistryQueryString() from
* RegistryQueryStringWait() and some errors are expected to occur.
*
* @return ERROR_SUCCESS on success; ERROR_INVALID_DATATYPE when the registry value is not a string; Win32 error code
* otherwise.
* @return String with registry value on success; If the function fails, the return value is zero. To get extended error
* information, call GetLastError.
*/
WINTUN_STATUS
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **Value, _In_ BOOL Log);
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ BOOL Log);
/**
* Reads string value from registry key. It waits for the registry value to become available.
@ -94,16 +95,14 @@ RegistryQueryString(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ WCHAR **V
*
* @param Timeout Timeout to wait for the value in milliseconds.
*
* @param Value Pointer to string to retrieve registry value. If the value type is REG_EXPAND_SZ the value is
* expanded using ExpandEnvironmentStrings(). If the value type is REG_MULTI_SZ, only the first
* string from the multi-string is returned. The string must be released with
* HeapFree(ModuleHeap, 0, Value) after use.
*
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; ERROR_INVALID_DATATYPE when the registry value is not a
* string; Win32 error code otherwise.
* @return Registry value. If the value type is REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings(). If
* the value type is REG_MULTI_SZ, only the first string from the multi-string is returned. The string must be
* released with HeapFree(ModuleHeap, 0, Value) after use. If the function fails, the return value is zero. To
* get extended error information, call GetLastError. Possible errors include the following:
* ERROR_INVALID_DATATYPE when the registry value is not a string
*/
WINTUN_STATUS
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ WCHAR **Value);
_Return_type_success_(
return != NULL) WCHAR *RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout);
/**
* Reads a 32-bit DWORD value from registry key.
@ -118,10 +117,10 @@ RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD
* errors reduces log clutter when we are using RegistryQueryDWORD() from
* RegistryQueryDWORDWait() and some errors are expected to occur.
*
* @return ERROR_SUCCESS on success; ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
* ERROR_INVALID_DATA when registry value size is not 4 bytes; Win32 error code otherwise.
* @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.
*/
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Value, _In_ BOOL Log);
/**
@ -135,8 +134,10 @@ RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _Out_ DWORD *Val
*
* @param Value Pointer to DWORD to retrieve registry value.
*
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; ERROR_INVALID_DATATYPE when registry value exist but not
* REG_DWORD type; ERROR_INVALID_DATA when registry value size is not 4 bytes; Win32 error code otherwise.
* @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. Possible errors include the following:
* ERROR_INVALID_DATATYPE when registry value exist but not REG_DWORD type;
* ERROR_INVALID_DATA when registry value size is not 4 bytes
*/
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ const WCHAR *Name, _In_ DWORD Timeout, _Out_ DWORD *Value);

View File

@ -8,35 +8,47 @@
#include "resource.h"
#include <Windows.h>
WINTUN_STATUS
ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, _Out_ DWORD *Size)
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size)
{
HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
if (!FoundResource)
return LOG_LAST_ERROR(L"Failed to find resource");
{
LOG_LAST_ERROR(L"Failed to find resource");
return NULL;
}
*Size = SizeofResource(ResourceModule, FoundResource);
if (!*Size)
return LOG_LAST_ERROR(L"Failed to query resource size");
{
LOG_LAST_ERROR(L"Failed to query resource size");
return NULL;
}
HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
if (!LoadedResource)
return LOG_LAST_ERROR(L"Failed to load resource");
*Address = LockResource(LoadedResource);
if (!*Address)
{
LOG_LAST_ERROR(L"Failed to load resource");
return NULL;
}
BYTE *Address = LockResource(LoadedResource);
if (!Address)
{
LOG(WINTUN_LOG_ERR, L"Failed to lock resource");
return ERROR_LOCK_FAILED;
SetLastError(ERROR_LOCK_FAILED);
return NULL;
}
return ERROR_SUCCESS;
return Address;
}
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName)
{
const void *LockedResource;
DWORD SizeResource;
DWORD Result = ResourceGetAddress(ResourceName, &LockedResource, &SizeResource);
if (Result != ERROR_SUCCESS)
return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
const void *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
if (!LockedResource)
{
LOG(WINTUN_LOG_ERR, L"Failed to locate resource");
return FALSE;
}
HANDLE DestinationHandle = CreateFileW(
DestinationPath,
GENERIC_WRITE,
@ -46,15 +58,25 @@ ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *Reso
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
NULL);
if (DestinationHandle == INVALID_HANDLE_VALUE)
return LOG_LAST_ERROR(L"Failed to create file");
{
LOG_LAST_ERROR(L"Failed to create file");
return FALSE;
}
DWORD BytesWritten;
DWORD LastError;
if (!WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL))
Result = LOG_LAST_ERROR(L"Failed to write file");
{
LastError = LOG_LAST_ERROR(L"Failed to write file");
goto cleanupDestinationHandle;
}
if (BytesWritten != SizeResource)
{
LOG(WINTUN_LOG_ERR, L"Incomplete write");
Result = Result != ERROR_SUCCESS ? Result : ERROR_WRITE_FAULT;
LastError = ERROR_WRITE_FAULT;
goto cleanupDestinationHandle;
}
LastError = ERROR_SUCCESS;
cleanupDestinationHandle:
CloseHandle(DestinationHandle);
return Result;
return RET_ERROR(TRUE, LastError);
}

View File

@ -13,14 +13,13 @@
*
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
*
* Address Pointer to a pointer variable to receive resource address.
*
* Size Pointer to a variable to receive resource size.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @return Resource address on success. If the function fails, the return value is NULL. To get extended error
* information, call GetLastError.
*/
WINTUN_STATUS
ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address, _Out_ DWORD *Size);
_Return_type_success_(return != NULL) _Ret_bytecount_(*Size) const
void *ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ DWORD *Size);
/**
* Copies resource to a file.
@ -29,7 +28,8 @@ ResourceGetAddress(_In_z_ const WCHAR *ResourceName, _Out_ const void **Address,
*
* ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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.
*/
WINTUN_STATUS
_Return_type_success_(return != FALSE) BOOL
ResourceCopyToFile(_In_z_ const WCHAR *DestinationPath, _In_z_ const WCHAR *ResourceName);

View File

@ -94,17 +94,18 @@ VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID)))
goto cleanup;
WINTUN_ADAPTER *Adapter;
BOOL RebootRequired;
DWORD Result = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &Adapter, &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!",
Result,
StringFromGUID2(Result == ERROR_SUCCESS ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
LastError,
StringFromGUID2(Adapter ? &Adapter->CfgInstanceID : &GUID_NULL, GuidStr, _countof(GuidStr)),
GuidStr,
RebootRequired);
if (Adapter)
WintunFreeAdapter(Adapter);
cleanup:
@ -124,8 +125,9 @@ VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int
if (FAILED(CLSIDFromString(Argv[3], &Adapter.CfgInstanceID)))
goto cleanup;
BOOL RebootRequired;
WINTUN_STATUS Ret = WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired);
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired);
DWORD LastError =
WintunDeleteAdapter(&Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError();
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup:
Done();
@ -140,8 +142,8 @@ VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, i
goto cleanup;
BOOL RebootRequired;
WINTUN_STATUS Ret = WintunDeletePoolDriver(Argv[2], &RebootRequired);
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired);
DWORD LastError = WintunDeletePoolDriver(Argv[2], &RebootRequired) ? ERROR_SUCCESS : GetLastError();
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired);
cleanup:
Done();

View File

@ -72,7 +72,7 @@ ProcessStderr(_In_ HANDLE Stderr)
else if (State == OnMsg && c == L'\n')
{
Msg[Count] = 0;
Logger(Level, Msg);
LoggerLog(Level, Msg);
State = OnNone;
Count = 0;
}
@ -80,27 +80,35 @@ ProcessStderr(_In_ HANDLE Stderr)
}
}
static WINTUN_STATUS
ExecuteRunDll32(
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)))
return LOG_LAST_ERROR(L"Failed to get Windows folder");
{
LOG_LAST_ERROR(L"Failed to get Windows folder");
return FALSE;
}
WCHAR RunDll32Path[MAX_PATH];
if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
return ERROR_BUFFER_OVERFLOW;
{
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
DWORD Result;
DWORD LastError;
WCHAR RandomTempSubDirectory[MAX_PATH];
if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS)
return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result;
if (!CreateTemporaryDirectory(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"))
{
Result = ERROR_BUFFER_OVERFLOW;
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanupDirectory;
}
const WCHAR *WintunDllResourceName;
@ -114,12 +122,12 @@ ExecuteRunDll32(
break;
default:
LOG(WINTUN_LOG_ERR, L"Unsupported platform");
Result = ERROR_NOT_SUPPORTED;
LastError = ERROR_NOT_SUPPORTED;
goto cleanupDirectory;
}
if ((Result = ResourceCopyToFile(DllPath, WintunDllResourceName)) != ERROR_SUCCESS)
if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
{
LOG(WINTUN_LOG_ERR, L"Failed to copy resource");
LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource");
goto cleanupDelete;
}
size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1;
@ -127,14 +135,14 @@ ExecuteRunDll32(
if (!CommandLine)
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
Result = ERROR_OUTOFMEMORY;
LastError = ERROR_OUTOFMEMORY;
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");
Result = ERROR_INVALID_PARAMETER;
LastError = ERROR_INVALID_PARAMETER;
goto cleanupDelete;
}
HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
@ -142,13 +150,13 @@ ExecuteRunDll32(
if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
!CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
{
Result = LOG_LAST_ERROR(L"Failed to create pipes");
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))
{
Result = LOG_LAST_ERROR(L"Failed to set handle info");
LastError = LOG_LAST_ERROR(L"Failed to set handle info");
goto cleanupPipes;
}
if (ResponseCapacity)
@ -160,7 +168,7 @@ ExecuteRunDll32(
if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
(ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
{
Result = LOG_LAST_ERROR(L"Failed to spawn readers");
LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
goto cleanupThreads;
}
STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
@ -172,14 +180,15 @@ ExecuteRunDll32(
HANDLE ProcessToken = GetPrimarySystemTokenFromThread();
if (!ProcessToken)
{
Result = LOG_LAST_ERROR(L"Failed to get primary system token from thread");
LastError = LOG(WINTUN_LOG_ERR, L"Failed to get primary system token from thread");
goto cleanupThreads;
}
if (!CreateProcessAsUserW(ProcessToken, RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
Result = LOG_LAST_ERROR(L"Failed to create process");
LastError = LOG_LAST_ERROR(L"Failed to create process");
goto cleanupToken;
}
LastError = ERROR_SUCCESS;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
@ -198,10 +207,10 @@ cleanupThreads:
CloseHandle(StreamWStdout);
StreamWStdout = INVALID_HANDLE_VALUE;
WaitForSingleObject(ThreadStdout, INFINITE);
if (!GetExitCodeThread(ThreadStdout, &Result))
Result = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (Result != ERROR_SUCCESS)
LOG_ERROR(L"Failed to read process output", Result);
if (!GetExitCodeThread(ThreadStdout, &LastError))
LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
else if (LastError != ERROR_SUCCESS)
LOG_ERROR(L"Failed to read process output", LastError);
CloseHandle(ThreadStdout);
}
cleanupPipes:
@ -214,15 +223,13 @@ cleanupDelete:
DeleteFileW(DllPath);
cleanupDirectory:
RemoveDirectoryW(RandomTempSubDirectory);
return Result;
return RET_ERROR(TRUE, LastError);
}
static WINTUN_STATUS
CreateAdapterViaRundll32(
static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapterViaRundll32(
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name,
_In_opt_ const GUID *RequestedGUID,
_Out_ WINTUN_ADAPTER **Adapter,
_Inout_ BOOL *RebootRequired)
{
LOG(WINTUN_LOG_INFO, L"Spawning native process");
@ -237,38 +244,46 @@ CreateAdapterViaRundll32(
Name,
RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0,
RequestedGUIDStr) == -1)
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
{
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];
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
if (Result != ERROR_SUCCESS)
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
return Result;
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");
Result = ERROR_INVALID_PARAMETER;
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
Result = wcstoul(Argv[0], NULL, 16);
if (Result == ERROR_SUCCESS && GetAdapter(Pool, &CfgInstanceID, Adapter) != ERROR_SUCCESS)
LastError = wcstoul(Argv[0], NULL, 16);
if (LastError == ERROR_SUCCESS && (Adapter = GetAdapter(Pool, &CfgInstanceID)) == NULL)
{
LOG(WINTUN_LOG_ERR, L"Failed to get adapter");
Result = ERROR_FILE_NOT_FOUND;
LastError = ERROR_FILE_NOT_FOUND;
}
if (wcstoul(Argv[2], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return Result;
SetLastError(LastError);
return Adapter;
}
static WINTUN_STATUS
DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Inout_ BOOL *RebootRequired)
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];
@ -281,57 +296,65 @@ DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceClos
ForceCloseSessions ? 1 : 0,
StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)),
GuidStr) == -1)
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
if (Result != ERROR_SUCCESS)
DWORD LastError;
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
return Result;
return FALSE;
}
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
Result = ERROR_INVALID_PARAMETER;
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
Result = wcstoul(Argv[0], NULL, 16);
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return Result;
return RET_ERROR(TRUE, LastError);
}
static WINTUN_STATUS
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)
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
{
LOG(WINTUN_LOG_ERR, L"Command line too long");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WCHAR Response[8 + 1 + 8 + 1];
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
if (Result != ERROR_SUCCESS)
DWORD LastError;
if (!ExecuteRunDll32(Arguments, Response, _countof(Response)))
{
LOG(WINTUN_LOG_ERR, L"Error executing worker process");
return Result;
return FALSE;
}
int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 2)
{
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
Result = ERROR_INVALID_PARAMETER;
LastError = ERROR_INVALID_PARAMETER;
goto cleanupArgv;
}
Result = wcstoul(Argv[0], NULL, 16);
LastError = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv:
LocalFree(Argv);
return Result;
return RET_ERROR(TRUE, LastError);
}

View File

@ -69,86 +69,87 @@ typedef struct _TUN_SESSION
HANDLE Handle;
} TUN_SESSION;
WINTUN_STATUS WINAPI
WintunStartSession(
_In_ const WINTUN_ADAPTER *Adapter,
_In_ DWORD Capacity,
_Out_ TUN_SESSION **Session)
_Return_type_success_(return != NULL) TUN_SESSION *WINAPI
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity)
{
TUN_SESSION *s = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION));
if (!s)
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
DWORD LastError;
TUN_SESSION *Session = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION));
if (!Session)
{
LOG(WINTUN_LOG_ERR, L"Out of memory");
LastError = ERROR_OUTOFMEMORY;
goto out;
}
const ULONG RingSize = TUN_RING_SIZE(Capacity);
DWORD Result;
BYTE *AllocatedRegion = VirtualAlloc(0, (size_t)RingSize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!AllocatedRegion)
{
Result = LOG_LAST_ERROR(L"Failed to allocate ring memory");
LastError = LOG_LAST_ERROR(L"Failed to allocate ring memory");
goto cleanupRings;
}
if (!ElevateToSystem())
{
LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user");
Result = ERROR_ACCESS_DENIED;
LastError = LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user");
goto cleanupAllocatedRegion;
}
s->Descriptor.Send.RingSize = RingSize;
s->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
s->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
if (!s->Descriptor.Send.TailMoved)
Session->Descriptor.Send.RingSize = RingSize;
Session->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
Session->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
if (!Session->Descriptor.Send.TailMoved)
{
Result = LOG_LAST_ERROR(L"Failed to create send event");
LastError = LOG_LAST_ERROR(L"Failed to create send event");
goto cleanupToken;
}
s->Descriptor.Receive.RingSize = RingSize;
s->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize);
s->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
if (!s->Descriptor.Receive.TailMoved)
Session->Descriptor.Receive.RingSize = RingSize;
Session->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize);
Session->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
if (!Session->Descriptor.Receive.TailMoved)
{
Result = LOG_LAST_ERROR(L"Failed to create receive event");
LastError = LOG_LAST_ERROR(L"Failed to create receive event");
goto cleanupSendTailMoved;
}
Result = WintunOpenAdapterDeviceObject(Adapter, &s->Handle);
if (Result != ERROR_SUCCESS)
Session->Handle = WintunOpenAdapterDeviceObject(Adapter);
if (Session->Handle == INVALID_HANDLE_VALUE)
{
LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object");
LastError = LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object");
goto cleanupReceiveTailMoved;
}
DWORD BytesReturned;
if (!DeviceIoControl(
s->Handle,
Session->Handle,
TUN_IOCTL_REGISTER_RINGS,
&s->Descriptor,
&Session->Descriptor,
sizeof(TUN_REGISTER_RINGS),
NULL,
0,
&BytesReturned,
NULL))
{
Result = LOG_LAST_ERROR(L"Failed to register rings");
LastError = LOG_LAST_ERROR(L"Failed to register rings");
goto cleanupHandle;
}
RevertToSelf();
s->Capacity = Capacity;
(void)InitializeCriticalSectionAndSpinCount(&s->Receive.Lock, LOCK_SPIN_COUNT);
(void)InitializeCriticalSectionAndSpinCount(&s->Send.Lock, LOCK_SPIN_COUNT);
*Session = s;
return ERROR_SUCCESS;
Session->Capacity = Capacity;
(void)InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
(void)InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
return Session;
cleanupHandle:
CloseHandle(s->Handle);
CloseHandle(Session->Handle);
cleanupReceiveTailMoved:
CloseHandle(s->Descriptor.Receive.TailMoved);
CloseHandle(Session->Descriptor.Receive.TailMoved);
cleanupSendTailMoved:
CloseHandle(s->Descriptor.Send.TailMoved);
CloseHandle(Session->Descriptor.Send.TailMoved);
cleanupToken:
RevertToSelf();
cleanupAllocatedRegion:
VirtualFree(AllocatedRegion, 0, MEM_RELEASE);
cleanupRings:
HeapFree(ModuleHeap, 0, s);
return Result;
HeapFree(ModuleHeap, 0, Session);
out:
SetLastError(LastError);
return NULL;
}
void WINAPI
@ -170,53 +171,55 @@ WintunGetReadWaitEvent(_In_ TUN_SESSION *Session)
return Session->Descriptor.Send.TailMoved;
}
WINTUN_STATUS WINAPI
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_bytecapcount_(*PacketSize) BYTE **Packet, _Out_ DWORD *PacketSize)
_Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *WINAPI
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_ DWORD *PacketSize)
{
DWORD Result;
DWORD LastError;
EnterCriticalSection(&Session->Send.Lock);
if (Session->Send.Head >= Session->Capacity)
{
Result = ERROR_HANDLE_EOF;
LastError = ERROR_HANDLE_EOF;
goto cleanup;
}
const ULONG BuffTail = ReadULongAcquire(&Session->Descriptor.Send.Ring->Tail);
if (BuffTail >= Session->Capacity)
{
Result = ERROR_HANDLE_EOF;
LastError = ERROR_HANDLE_EOF;
goto cleanup;
}
if (Session->Send.Head == BuffTail)
{
Result = ERROR_NO_MORE_ITEMS;
LastError = ERROR_NO_MORE_ITEMS;
goto cleanup;
}
const ULONG BuffContent = TUN_RING_WRAP(BuffTail - Session->Send.Head, Session->Capacity);
if (BuffContent < sizeof(TUN_PACKET))
{
Result = ERROR_INVALID_DATA;
LastError = ERROR_INVALID_DATA;
goto cleanup;
}
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.Head];
if (BuffPacket->Size > WINTUN_MAX_IP_PACKET_SIZE)
{
Result = ERROR_INVALID_DATA;
LastError = ERROR_INVALID_DATA;
goto cleanup;
}
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
if (AlignedPacketSize > BuffContent)
{
Result = ERROR_INVALID_DATA;
LastError = ERROR_INVALID_DATA;
goto cleanup;
}
*PacketSize = BuffPacket->Size;
*Packet = BuffPacket->Data;
BYTE *Packet = BuffPacket->Data;
Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity);
Session->Send.PacketsToRelease++;
Result = ERROR_SUCCESS;
LeaveCriticalSection(&Session->Send.Lock);
return Packet;
cleanup:
LeaveCriticalSection(&Session->Send.Lock);
return Result;
SetLastError(LastError);
return NULL;
}
void WINAPI
@ -238,38 +241,40 @@ WintunReceiveRelease(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
LeaveCriticalSection(&Session->Send.Lock);
}
WINTUN_STATUS WINAPI
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize, _Out_bytecapcount_(PacketSize) BYTE **Packet)
_Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *WINAPI
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize)
{
DWORD Result;
DWORD LastError;
EnterCriticalSection(&Session->Receive.Lock);
if (Session->Receive.Tail >= Session->Capacity)
{
Result = ERROR_HANDLE_EOF;
LastError = ERROR_HANDLE_EOF;
goto cleanup;
}
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
const ULONG BuffHead = ReadULongAcquire(&Session->Descriptor.Receive.Ring->Head);
if (BuffHead >= Session->Capacity)
{
Result = ERROR_HANDLE_EOF;
LastError = ERROR_HANDLE_EOF;
goto cleanup;
}
const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - Session->Receive.Tail - TUN_ALIGNMENT, Session->Capacity);
if (AlignedPacketSize > BuffSpace)
{
Result = ERROR_BUFFER_OVERFLOW;
LastError = ERROR_BUFFER_OVERFLOW;
goto cleanup;
}
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail];
BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE;
*Packet = BuffPacket->Data;
BYTE *Packet = BuffPacket->Data;
Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity);
Session->Receive.PacketsToRelease++;
Result = ERROR_SUCCESS;
LeaveCriticalSection(&Session->Receive.Lock);
return Packet;
cleanup:
LeaveCriticalSection(&Session->Receive.Lock);
return Result;
SetLastError(LastError);
return NULL;
}
void WINAPI

View File

@ -13,8 +13,6 @@
extern "C" {
#endif
typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINTUN_STATUS;
/**
* A handle representing Wintun adapter
*/
@ -33,24 +31,20 @@ typedef void *WINTUN_ADAPTER_HANDLE;
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation
* deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence
* a new NLA entry is created for each new adapter. It is called "requested" GUID because the API
* it uses is completely undocumented, and so there could be minor interesting complications with
* its usage.
*
* @param Adapter Pointer to a handle to receive the adapter handle. Must be released with
* WintunFreeAdapter.
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
* If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
* created for each new adapter. It is called "requested" GUID because the API it uses is
* completely undocumented, and so there could be minor interesting complications with its usage.
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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 WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
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_ WINTUN_ADAPTER_HANDLE *Adapter,
_Out_opt_ BOOL *RebootRequired);
/**
@ -64,9 +58,10 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_CREATE_ADAPTER_FUNC)(
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
*
* @return ERROR_SUCCESS on success or the adapter was not found; Win32 error code otherwise.
* @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 WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
_In_ WINTUN_ADAPTER_HANDLE Adapter,
_In_ BOOL ForceCloseSessions,
_Out_opt_ BOOL *RebootRequired);
@ -79,11 +74,11 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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 WINTUN_STATUS(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(
_In_z_ const WCHAR Pool[WINTUN_MAX_POOL],
_Out_opt_ BOOL *RebootRequired);
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(_In_z_ const WCHAR *Pool, _Out_opt_ BOOL *RebootRequired);
/**
* Called by WintunEnumAdapters for each adapter in the pool.
@ -106,9 +101,10 @@ typedef BOOL(CALLBACK *WINTUN_ENUM_CALLBACK_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ada
*
* @param Param An application-defined value to be passed to the callback function.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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 WINTUN_STATUS(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(
typedef _Return_type_success_(return != FALSE) BOOL(WINAPI *WINTUN_ENUM_ADAPTERS_FUNC)(
_In_z_ const WCHAR *Pool,
_In_ WINTUN_ENUM_CALLBACK_FUNC Callback,
_In_ LPARAM Param);
@ -127,27 +123,26 @@ typedef void(WINAPI *WINTUN_FREE_ADAPTER_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapte
*
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
*
* @param Adapter Pointer to a handle to receive the adapter handle. Must be released with WintunFreeAdapter.
*
* @return ERROR_SUCCESS on success; 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; Win32 error code otherwise
* @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
*/
typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_FUNC)(
_In_z_ const WCHAR *Pool,
_In_z_ const WCHAR *Name,
_Out_ WINTUN_ADAPTER_HANDLE *Adapter);
typedef _Return_type_success_(return != NULL)
WINTUN_ADAPTER_HANDLE(WINAPI *WINTUN_GET_ADAPTER_FUNC)(_In_z_ const WCHAR *Pool, _In_z_ const WCHAR *Name);
/**
* Returns a handle to the adapter device object.
*
* @param Adapter Adapter handle obtained with WintunGetAdapter or WintunCreateAdapter.
*
* @param Handle Pointer to receive the adapter device object handle. Must be released with CloseHandle.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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
* information, call GetLastError.
*/
typedef WINTUN_STATUS(
WINAPI *WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ HANDLE *Handle);
typedef _Return_type_success_(return != INVALID_HANDLE_VALUE)
HANDLE(WINAPI *WINTUN_OPEN_ADAPTER_DEVICE_OBJECT_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter);
/**
* Returns the LUID of the adapter.
@ -165,9 +160,10 @@ typedef void(WINAPI *WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Ad
*
* @param Name Pointer to a string to receive adapter name
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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 WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
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);
@ -178,15 +174,19 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_GET_ADAPTER_NAME_FUNC)(
*
* @param Name Adapter name. Zero-terminated string of up to MAX_ADAPTER_NAME-1 characters.
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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 WINTUN_STATUS(
WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI *WINTUN_SET_ADAPTER_NAME_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_z_ const WCHAR *Name);
/**
* Determines the version of the Wintun driver currently loaded.
*
* @return The version number on success, or 0 if failure or Wintun not loaded.
* @return If the function succeeds, the return value is the version number. If the function fails, the return value is
* zero. To get extended error information, call GetLastError. Possible errors include the following:
* ERROR_FILE_NOT_FOUND Wintun not loaded;
* ERROR_GEN_FAILURE Enumerating drivers failed
*/
typedef DWORD(WINAPI *WINTUN_GET_VERSION_FUNC)(void);
@ -240,14 +240,11 @@ typedef void *WINTUN_SESSION_HANDLE;
* @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
* Must be a power of two.
*
* @param Session Pointer to a variable to receive Wintun session handle
*
* @return ERROR_SUCCESS on success; Win32 error code otherwise.
* @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 WINTUN_STATUS(WINAPI *WINTUN_START_SESSION_FUNC)(
_In_ WINTUN_ADAPTER_HANDLE Adapter,
_In_ DWORD Capacity,
_Out_ WINTUN_SESSION_HANDLE *Session);
typedef _Return_type_success_(return != NULL)
WINTUN_SESSION_HANDLE(WINAPI *WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
/**
* Ends Wintun session.
@ -279,22 +276,17 @@ typedef HANDLE(WINAPI *WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HAND
*
* @param Session Wintun session handle obtained with WintunStartSession
*
* @param Packet Pointer to receive pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at
* will.
* @param PacketSize Pointer to receive packet size.
*
* @param PacketSize Pointer to receive Packet size.
*
* @return Returns one of the following values:
* @return Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the
* return value is NULL. To get extended error information, call GetLastError. Possible errors include the
* following:
* ERROR_HANDLE_EOF Wintun adapter is terminating;
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
* ERROR_INVALID_DATA Wintun buffer is corrupt;
* ERROR_SUCCESS on success.
* Regardless, if the error was returned, some packets might have been read nevertheless.
* ERROR_INVALID_DATA Wintun buffer is corrupt
*/
typedef WINTUN_STATUS(WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(
_In_ WINTUN_SESSION_HANDLE *Session,
_Out_bytecapcount_(*PacketSize) BYTE **Packet,
_Out_ DWORD *PacketSize);
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(*PacketSize) BYTE *(
WINAPI *WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _Out_ DWORD *PacketSize);
/**
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
@ -314,17 +306,14 @@ typedef void(WINAPI *WINTUN_RECEIVE_RELEASE_FUNC)(_In_ WINTUN_SESSION_HANDLE *Se
*
* @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
*
* @param Packet Pointer to receive pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending.
*
* @return Returns one of the following values:
* @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails,
* the return value is NULL. To get extended error information, call GetLastError. Possible errors include the
* following:
* ERROR_HANDLE_EOF Wintun adapter is terminating;
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
* ERROR_SUCCESS on success.
*/
typedef WINTUN_STATUS(WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(
_In_ WINTUN_SESSION_HANDLE *Session,
_In_ DWORD PacketSize,
_Out_bytecapcount_(PacketSize) BYTE **Packet);
typedef _Return_type_success_(return != NULL) _Ret_bytecount_(PacketSize) BYTE *(
WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _In_ DWORD PacketSize);
/**
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket

View File

@ -100,6 +100,15 @@ LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
return Error;
}
static DWORD
LogLastError(_In_z_ const WCHAR *Prefix)
{
DWORD LastError = GetLastError();
LogError(Prefix, LastError);
SetLastError(LastError);
return LastError;
}
static void
Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
{
@ -206,22 +215,26 @@ ReceivePackets(_Inout_ DWORD_PTR SessionPtr)
while (!HaveQuit)
{
BYTE *Packet;
DWORD PacketSize;
DWORD Result = WintunReceivePacket(Session, &Packet, &PacketSize);
switch (Result)
BYTE *Packet = WintunReceivePacket(Session, &PacketSize);
if (Packet)
{
case ERROR_SUCCESS:
PrintPacket(Packet, PacketSize);
WintunReceiveRelease(Session, Packet);
continue;
}
else
{
DWORD LastError = GetLastError();
switch (LastError)
{
case ERROR_NO_MORE_ITEMS:
if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
continue;
return ERROR_SUCCESS;
default:
LogError(L"Packet read failed", Result);
return Result;
LogError(L"Packet read failed", LastError);
return LastError;
}
}
}
return ERROR_SUCCESS;
@ -233,8 +246,9 @@ SendPackets(_Inout_ DWORD_PTR SessionPtr)
WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
while (!HaveQuit)
{
BYTE *Packet;
WintunAllocateSendPacket(Session, 28, &Packet);
BYTE *Packet = WintunAllocateSendPacket(Session, 28);
if (!Packet)
return LogLastError(L"Packet write failed");
MakeICMP(Packet);
WintunSendPacket(Session, Packet);
@ -269,9 +283,9 @@ InitializeWintun(void)
X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
#undef X
{
DWORD Result = GetLastError();
DWORD LastError = GetLastError();
FreeLibrary(Wintun);
SetLastError(Result);
SetLastError(LastError);
return NULL;
}
SetLastError(ERROR_SUCCESS);
@ -287,30 +301,32 @@ main(void)
WintunSetLogger(ConsoleLogger);
Log(WINTUN_LOG_INFO, L"Wintun library loaded");
DWORD Result;
DWORD LastError;
HaveQuit = FALSE;
QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!QuitEvent)
{
Result = LogError(L"Failed to create event", GetLastError());
LastError = LogError(L"Failed to create event", GetLastError());
goto cleanupWintun;
}
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
{
Result = LogError(L"Failed to set console handler", GetLastError());
LastError = LogError(L"Failed to set console handler", GetLastError());
goto cleanupQuit;
}
GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
WINTUN_ADAPTER_HANDLE Adapter;
Result = WintunGetAdapter(L"Example", L"Demo", &Adapter);
if (Result != ERROR_SUCCESS)
Result = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, &Adapter, NULL);
if (Result != ERROR_SUCCESS)
WINTUN_ADAPTER_HANDLE Adapter = WintunGetAdapter(L"Example", L"Demo");
if (!Adapter)
{
LogError(L"Failed to create adapter", Result);
Adapter = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, NULL);
if (!Adapter)
{
LastError = GetLastError();
LogError(L"Failed to create adapter", LastError);
goto cleanupQuit;
}
}
DWORD Version = WintunGetVersion();
Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
@ -321,18 +337,17 @@ main(void)
AddressRow.Address.Ipv4.sin_family = AF_INET;
AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
Result = CreateUnicastIpAddressEntry(&AddressRow);
if (Result != ERROR_SUCCESS && Result != ERROR_OBJECT_ALREADY_EXISTS)
LastError = CreateUnicastIpAddressEntry(&AddressRow);
if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
{
LogError(L"Failed to set IP address", Result);
LogError(L"Failed to set IP address", LastError);
goto cleanupAdapter;
}
WINTUN_SESSION_HANDLE Session;
Result = WintunStartSession(Adapter, 0x40000, &Session);
if (Result != ERROR_SUCCESS)
WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x40000);
if (!Session)
{
LogError(L"Failed to create adapter", Result);
LastError = LogLastError(L"Failed to create adapter");
goto cleanupAdapter;
}
@ -342,11 +357,11 @@ main(void)
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
if (!Workers[0] || !Workers[1])
{
Result = LogError(L"Failed to create threads", GetLastError());
LastError = LogError(L"Failed to create threads", GetLastError());
goto cleanupWorkers;
}
WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
Result = ERROR_SUCCESS;
LastError = ERROR_SUCCESS;
cleanupWorkers:
HaveQuit = TRUE;
@ -368,5 +383,5 @@ cleanupQuit:
CloseHandle(QuitEvent);
cleanupWintun:
FreeLibrary(Wintun);
return Result;
return LastError;
}