1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-22 09:29:52 +03:00

New vpndrvinst implementation, independent from Cedar and Mayaqua

This greatly improves performance and reduces the binary's size (~0.2 MB vs ~5 MB).

All recent Windows versions are supported, starting with Vista.

No dialogs are created, aside from error/warning ones in case of failure.

The only dependency (aside from Windows libraries) is libhamcore.
This commit is contained in:
Davide Beatrici 2021-03-12 05:46:20 +01:00
parent 68367fa2fb
commit 9d29d8813b
15 changed files with 1265 additions and 350 deletions

View File

@ -5514,6 +5514,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
ShowWindow(hWnd, SW_SHOWNORMAL); ShowWindow(hWnd, SW_SHOWNORMAL);
} }
Free(name); Free(name);
CmRefresh(hWnd);
} }
break; break;
case CMD_DELETE_VLAN: case CMD_DELETE_VLAN:
@ -5554,6 +5556,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
false, false); false, false);
} }
} }
CmRefresh(hWnd);
} }
break; break;
case CMD_ENABLE_VLAN: case CMD_ENABLE_VLAN:
@ -5573,6 +5577,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
CALL(hWnd, CcEnableVLan(cm->Client, &c)); CALL(hWnd, CcEnableVLan(cm->Client, &c));
} }
Free(s); Free(s);
CmRefresh(hWnd);
} }
} }
break; break;
@ -5593,6 +5599,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
CALL(hWnd, CcDisableVLan(cm->Client, &c)); CALL(hWnd, CcDisableVLan(cm->Client, &c));
} }
Free(s); Free(s);
CmRefresh(hWnd);
} }
} }
break; break;
@ -5643,6 +5651,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
} }
} }
Free(s); Free(s);
CmRefresh(hWnd);
} }
} }
break; break;

View File

@ -2129,6 +2129,7 @@ bool MsExecDriverInstaller(char *arg)
info.cbSize = sizeof(info); info.cbSize = sizeof(info);
info.lpVerb = L"open"; info.lpVerb = L"open";
info.lpFile = tmp; info.lpFile = tmp;
info.lpDirectory = MsGetMyTempDirW();
info.fMask = SEE_MASK_NOCLOSEPROCESS; info.fMask = SEE_MASK_NOCLOSEPROCESS;
info.lpParameters = arg_w; info.lpParameters = arg_w;
info.nShow = SW_SHOWNORMAL; info.nShow = SW_SHOWNORMAL;

View File

@ -5,7 +5,17 @@ endif()
set(COMPONENT_NAME "Driver Installer") set(COMPONENT_NAME "Driver Installer")
set(COMPONENT_INTERNAL_NAME "vpndrvinst") set(COMPONENT_INTERNAL_NAME "vpndrvinst")
add_executable(vpndrvinst WIN32 vpndrvinst.c vpndrvinst.h) add_executable(vpndrvinst
main.c
Device.c
Device.h
Dialog.c
Dialog.h
Driver.c
Driver.h
Str.c
Str.h
)
get_filename_component(COMPONENT_FILE_NAME vpndrvinst NAME) get_filename_component(COMPONENT_FILE_NAME vpndrvinst NAME)
set(COMPONENT_FILE_NAME "${COMPONENT_FILE_NAME}.exe") set(COMPONENT_FILE_NAME "${COMPONENT_FILE_NAME}.exe")
@ -18,6 +28,9 @@ if(MSVC)
set_target_properties(vpndrvinst PROPERTIES LINK_FLAGS "/manifestuac:level='requireAdministrator'") set_target_properties(vpndrvinst PROPERTIES LINK_FLAGS "/manifestuac:level='requireAdministrator'")
endif() endif()
# Hide console while keeping main() as entry point
target_link_options(vpndrvinst PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
if(${COMPILER_ARCHITECTURE} STREQUAL "x64") if(${COMPILER_ARCHITECTURE} STREQUAL "x64")
target_sources(vpndrvinst PRIVATE "${TOP_DIRECTORY}/src/BuildFiles/Manifests/x64_admin.manifest") target_sources(vpndrvinst PRIVATE "${TOP_DIRECTORY}/src/BuildFiles/Manifests/x64_admin.manifest")
else() else()
@ -32,4 +45,9 @@ set_target_properties(vpndrvinst
PDB_OUTPUT_DIRECTORY "${BUILD_DIRECTORY}" PDB_OUTPUT_DIRECTORY "${BUILD_DIRECTORY}"
) )
target_link_libraries(vpndrvinst cedar mayaqua) target_link_libraries(vpndrvinst
PRIVATE
libhamcore
newdev.lib
SetupAPI.Lib
)

564
src/vpndrvinst/Device.c Normal file
View File

@ -0,0 +1,564 @@
#include "Device.h"
#include "Dialog.h"
#include "Driver.h"
#include "Str.h"
#include "Hamcore.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include <newdev.h>
#include <RegStr.h>
#include <SetupAPI.h>
HDEVINFO GetDeviceInfo(SP_DEVINFO_DATA *devinfo_data, const char *instance)
{
if (!devinfo_data || !instance)
{
return NULL;
}
HDEVINFO devinfo = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
if (devinfo == INVALID_HANDLE_VALUE)
{
ShowWarning("GetDeviceInfo()", "SetupDiGetClassDevs() failed with error %lu!", GetLastError());
return NULL;
}
SP_DEVINFO_LIST_DETAIL_DATA detail_data;
detail_data.cbSize = sizeof(detail_data);
if (!SetupDiGetDeviceInfoListDetail(devinfo, &detail_data))
{
ShowWarning("GetDeviceInfo()", "SetupDiGetDeviceInfoListDetail() failed with error %lu!", GetLastError());
FreeDeviceInfo(devinfo);
return NULL;
}
char id[MAX_PATH];
snprintf(id, sizeof(id), DRIVER_DEVICE_ID_TAG, instance);
bool found = false;
SP_DEVINFO_DATA data;
data.cbSize = sizeof(data);
for (DWORD i = 0; SetupDiEnumDeviceInfo(devinfo, i, &data); ++i)
{
DWORD size;
if (!SetupDiGetDeviceRegistryProperty(devinfo, &data, SPDRP_HARDWAREID, NULL, NULL, 0, &size))
{
const DWORD error = GetLastError();
if (error != ERROR_INSUFFICIENT_BUFFER)
{
ShowWarning("GetDeviceInfo()", "SetupDiGetDeviceRegistryProperty() failed with error %lu!", error);
continue;
}
}
char *buffer = malloc(size);
if (!SetupDiGetDeviceRegistryProperty(devinfo, &data, SPDRP_HARDWAREID, NULL, (BYTE *)buffer, size, NULL))
{
ShowWarning("GetDeviceInfo()", "SetupDiGetDeviceRegistryProperty() failed with error %lu!", GetLastError());
free(buffer);
continue;
}
if (strcmp(buffer, id) == 0)
{
found = true;
}
free(buffer);
if (found)
{
break;
}
}
if (!found)
{
FreeDeviceInfo(devinfo);
return NULL;
}
memcpy(devinfo_data, &data, sizeof(data));
return devinfo;
}
void FreeDeviceInfo(HDEVINFO info)
{
if (info)
{
SetupDiDestroyDeviceInfoList(info);
}
}
bool ToggleDevice(const char *instance, const bool enable)
{
if (!instance)
{
return false;
}
SP_DEVINFO_DATA data;
HDEVINFO info = GetDeviceInfo(&data, instance);
if (!info)
{
ShowWarning("ToggleDevice()", "The specified device was not found!");
return false;
}
bool ok = false;
SP_PROPCHANGE_PARAMS params;
params.HwProfile = 0;
params.Scope = DICS_FLAG_CONFIGSPECIFIC;
params.StateChange = enable ? DICS_ENABLE : DICS_DISABLE;
params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
params.ClassInstallHeader.cbSize = sizeof(params.ClassInstallHeader);
if (!SetupDiSetClassInstallParams(info, &data, &params.ClassInstallHeader, sizeof(params)))
{
ShowWarning("ToggleDevice()", "SetupDiSetClassInstallParams() failed with error %lu!", GetLastError());
goto FINAL;
}
if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, info, &data))
{
ShowWarning("ToggleDevice()", "SetupDiCallClassInstaller() failed with error %lu!", GetLastError());
// Clear parameters, otherwise the device may remain in an inconsistent state
// (e.g. with the enabled icon even if disabled).
SetupDiSetClassInstallParams(info, &data, NULL, 0);
goto FINAL;
}
ok = true;
FINAL:
FreeDeviceInfo(info);
return ok;
}
bool InstallDevice(const char *instance)
{
if (!instance)
{
return false;
}
char mac[MAC_BUFFER_SIZE];
GenMacAddress(mac, sizeof(mac));
return InstallDeviceWithMac(instance, mac);
}
bool InstallDeviceWithMac(const char *instance, const char *mac)
{
if (!instance || !mac)
{
return false;
}
SP_DEVINFO_DATA data;
HDEVINFO info = GetDeviceInfo(&data, instance);
if (info)
{
ShowWarning("InstallDevice()", "The specified device already exists!");
return false;
}
HAMCORE *hamcore = HamcoreOpen("hamcore.se2");
if (!hamcore)
{
ShowWarning("InstallDevice()", "Failed to open hamcore.se2!");
return false;
}
bool ok = false;
bool delete_files = false;
if (!IsInstanceNameOK(hamcore, instance))
{
ShowWarning("InstallDevice()", "\"%s\" cannot be used as instance name, please choose another!", instance);
goto FINAL;
}
char cat[MAX_PATH];
if (!PrepareCat(hamcore, cat, sizeof(cat), instance))
{
goto FINAL;
}
char sys[MAX_PATH];
if (!PrepareSys(hamcore, sys, sizeof(sys), instance))
{
goto FINAL;
}
char inf[MAX_PATH];
if (!PrepareInf(hamcore, inf, sizeof(inf), instance, sys, mac))
{
goto FINAL;
}
delete_files = true;
GUID inf_guid;
char inf_class[MAX_CLASS_NAME_LEN];
if (!SetupDiGetINFClass(inf, &inf_guid, inf_class, sizeof(inf_class), NULL))
{
ShowWarning("InstallDevice()", "SetupDiGetINFClass() failed with error %lu!", GetLastError());
goto FINAL;
}
info = SetupDiCreateDeviceInfoList(&inf_guid, NULL);
if (info == INVALID_HANDLE_VALUE)
{
ShowWarning("InstallDevice()", "SetupDiCreateDeviceInfoList() failed with error %lu!", GetLastError());
goto FINAL;
}
SP_DEVINFO_DATA info_data;
info_data.cbSize = sizeof(info_data);
if (!SetupDiCreateDeviceInfo(info, inf_class, &inf_guid, NULL, NULL, DICD_GENERATE_ID, &info_data))
{
ShowWarning("InstallDevice()", "SetupDiCreateDeviceInfo() failed with error %lu!", GetLastError());
goto FINAL;
}
char id[MAX_PATH];
snprintf(id, sizeof(id), DRIVER_DEVICE_ID_TAG, instance);
// Passing the full buffer size caused a second hardware ID containing random symbols to appear
// on a fresh Windows 7 VM several times when using long instance names.
// As a simple and effective solution, we simply pass the string length + 1 for the NULL char.
if (!SetupDiSetDeviceRegistryProperty(info, &info_data, SPDRP_HARDWAREID, (BYTE *)id, (DWORD)strlen(id) + 1))
{
ShowWarning("InstallDevice()", "SetupDiSetDeviceRegistryProperty() failed with error %lu!", GetLastError());
goto FINAL;
}
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, info, &info_data))
{
ShowWarning("InstallDevice()", "SetupDiCallClassInstaller() failed with error %lu!", GetLastError());
goto FINAL;
}
BOOL reboot_required;
if (!UpdateDriverForPlugAndPlayDevices(NULL, id, inf, INSTALLFLAG_FORCE, &reboot_required))
{
ShowWarning("InstallDevice()", "UpdateDriverForPlugAndPlayDevices() failed with error %lu!", GetLastError());
if (!SetupDiCallClassInstaller(DIF_REMOVE, info, &info_data))
{
ShowWarning("InstallDevice()", "SetupDiCallClassInstaller() failed with error %lu!", GetLastError());
}
if (!SetupDiRemoveDevice(info, &info_data))
{
ShowWarning("InstallDevice()", "SetupDiRemoveDevice() failed with error %lu!", GetLastError());
}
goto FINAL;
}
if (IsMacAddressManual())
{
SetDeviceMac(instance, mac);
}
SetDeviceNetConfig(instance);
ok = true;
FINAL:
if (delete_files)
{
DeleteFile(cat);
DeleteFile(sys);
DeleteFile(inf);
}
HamcoreClose(hamcore);
FreeDeviceInfo(info);
return ok;
}
bool UninstallDevice(const char *instance)
{
if (!instance)
{
return false;
}
SP_DEVINFO_DATA info_data;
HDEVINFO info = GetDeviceInfo(&info_data, instance);
if (!info)
{
ShowWarning("UninstallDevice()", "The specified device was not found!");
return false;
}
bool ok = false;
SP_DEVINFO_LIST_DETAIL_DATA detail_data;
detail_data.cbSize = sizeof(detail_data);
if (!SetupDiGetDeviceInfoListDetail(info, &detail_data))
{
ShowWarning("UninstallDevice()", "SetupDiGetDeviceInfoListDetail() failed with error %lu!", GetLastError());
goto FINAL;
}
SP_REMOVEDEVICE_PARAMS params;
params.Scope = DI_REMOVEDEVICE_GLOBAL;
params.ClassInstallHeader.InstallFunction = DIF_REMOVE;
params.ClassInstallHeader.cbSize = sizeof(params.ClassInstallHeader);
if (!SetupDiSetClassInstallParams(info, &info_data, &params.ClassInstallHeader, sizeof(params)))
{
ShowWarning("UninstallDevice()", "SetupDiSetClassInstallParams() failed with error %lu!", GetLastError());
goto FINAL;
}
if (!SetupDiCallClassInstaller(DIF_REMOVE, info, &info_data))
{
ShowWarning("UninstallDevice()", "SetupDiCallClassInstaller() failed with error %lu!", GetLastError());
goto FINAL;
}
ok = true;
FINAL:
FreeDeviceInfo(info);
return ok;
}
bool UpgradeDevice(const char *instance)
{
if (!instance)
{
return false;
}
SP_DEVINFO_DATA data;
HDEVINFO info = GetDeviceInfo(&data, instance);
if (!info)
{
ShowWarning("UpgradeDevice()", "The specified device was not found!");
return false;
}
FreeDeviceInfo(info);
char mac[MAC_BUFFER_SIZE];
if (!GetDeviceMac(instance, mac, sizeof(mac)))
{
return false;
}
if (!UninstallDevice(instance))
{
return false;
}
if (!InstallDeviceWithMac(instance, mac))
{
return false;
}
if (IsMacAddressManual())
{
SetDeviceMac(instance, mac);
}
return true;
}
bool GetDeviceMac(const char *instance, char *dst, const size_t size)
{
if (!instance || !dst || size == 0)
{
return false;
}
HKEY key = GetDeviceRegKey(instance, false);
if (!key)
{
return false;
}
DWORD buffer_size = (DWORD)size;
LSTATUS ret = RegGetValue(key, NULL, "NetworkAddress", RRF_RT_REG_SZ, NULL, dst, &buffer_size);
RegCloseKey(key);
if (ret != ERROR_SUCCESS)
{
ShowWarning("GetDeviceMac()", "RegGetValue() failed with error %ld!", ret);
return false;
}
return true;
}
bool SetDeviceMac(const char *instance, const char *src)
{
if (!instance || !src)
{
return false;
}
HKEY key = GetDeviceRegKey(instance, true);
if (!key)
{
return false;
}
LSTATUS ret = RegSetKeyValue(key, NULL, "NetworkAddress", REG_SZ, src, (DWORD)strlen(src) + 1);
RegCloseKey(key);
if (ret != ERROR_SUCCESS)
{
ShowWarning("SetDeviceMac()", "RegSetValue() failed with error %ld!", ret);
return false;
}
ToggleDevice(instance, false);
ToggleDevice(instance, true);
return true;
}
bool SetDeviceNetConfig(const char *instance)
{
if (!instance)
{
return false;
}
HKEY key = GetDeviceRegKey(instance, true);
if (!key)
{
return false;
}
char path[MAX_PATH] = REGSTR_PATH_SERVICES "\\Tcpip\\Parameters\\Interfaces\\";
const size_t path_len = strlen(path);
DWORD buffer_size = sizeof(path) - path_len;
LSTATUS ret = RegGetValue(key, NULL, "NetCfgInstanceId", RRF_RT_REG_SZ, NULL, path + path_len, &buffer_size);
RegCloseKey(key);
if (ret != ERROR_SUCCESS)
{
ShowWarning("SetDeviceNetConfig()", "RegGetValue() failed with error %ld!", ret);
return false;
}
bool ok = true;
DWORD tmp = 0;
ret = RegSetKeyValue(HKEY_LOCAL_MACHINE, path, "EnableDeadGWDetect", REG_DWORD, &tmp, sizeof(tmp));
if (ret != ERROR_SUCCESS)
{
ShowWarning("SetDeviceNetConfig()", "RegSetKeyValue() failed to set EnableDeadGWDetect with error %ld!", ret);
ok = false;
}
tmp = 1;
ret = RegSetKeyValue(HKEY_LOCAL_MACHINE, path, "InterfaceMetric", REG_DWORD, &tmp, sizeof(tmp));
if (ret != ERROR_SUCCESS)
{
ShowWarning("SetDeviceNetConfig()", "RegSetKeyValue() failed to set InterfaceMetric with error %ld!", ret);
ok = false;
}
return ok;
}
HKEY GetDeviceRegKey(const char *instance, const bool writable)
{
if (!instance)
{
return NULL;
}
char path[MAX_PATH] = REGSTR_PATH_CLASS_NT "\\";
const size_t path_len = strlen(path);
StrFromGUID(path + path_len, sizeof(path) - path_len, &GUID_DEVCLASS_NET);
HKEY key_list;
LSTATUS ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &key_list);
if (ret != ERROR_SUCCESS)
{
ShowWarning("GetDeviceRegKey()", "RegOpenKeyEx() failed to open \"%s\", with error %ld!", path, ret);
return NULL;
}
char device_id[MAX_PATH];
snprintf(device_id, sizeof(device_id), DRIVER_DEVICE_ID_TAG, instance);
char driver_desc[MAX_PATH];
snprintf(driver_desc, sizeof(driver_desc), VLAN_ADAPTER_NAME_TAG, instance);
for (DWORD i = 0; ++i;)
{
char key_name[MAX_PATH];
DWORD key_name_size = sizeof(key_name);
ret = RegEnumKeyEx(key_list, i, key_name, &key_name_size, 0, NULL, 0, NULL);
if (ret != ERROR_SUCCESS)
{
if (ret != ERROR_NO_MORE_ITEMS)
{
ShowWarning("GetDeviceRegKey()", "RegEnumKeyEx() failed at index %lu with error %ld!", i, ret);
}
break;
}
HKEY key;
if (RegOpenKeyEx(key_list, key_name, 0, writable ? KEY_READ | KEY_WRITE : KEY_READ, &key) != ERROR_SUCCESS)
{
continue;
}
char buffer[MAX_PATH];
DWORD buffer_size = sizeof(buffer);
if (RegGetValue(key, NULL, REGSTR_VAL_MATCHINGDEVID, RRF_RT_REG_SZ, NULL, buffer, &buffer_size) != ERROR_SUCCESS)
{
RegCloseKey(key);
continue;
}
if (strncmp(buffer, device_id, buffer_size) == 0)
{
return key;
}
buffer_size = sizeof(buffer);
if (RegGetValue(key, NULL, REGSTR_VAL_DRVDESC, RRF_RT_REG_SZ, NULL, buffer, &buffer_size) != ERROR_SUCCESS)
{
RegCloseKey(key);
continue;
}
if (strncmp(buffer, driver_desc, buffer_size) == 0)
{
return key;
}
}
return NULL;
}

30
src/vpndrvinst/Device.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef DEVICE_H
#define DEVICE_H
#include <stdbool.h>
#include <stddef.h>
typedef void *PVOID;
typedef PVOID HDEVINFO;
typedef struct HKEY__ *HKEY;
typedef struct _SP_DEVINFO_DATA SP_DEVINFO_DATA;
HDEVINFO GetDeviceInfo(SP_DEVINFO_DATA *devinfo_data, const char *instance);
void FreeDeviceInfo(HDEVINFO info);
bool ToggleDevice(const char *instance, const bool enable);
bool InstallDevice(const char *instance);
bool InstallDeviceWithMac(const char *instance, const char *mac);
bool UninstallDevice(const char *instance);
bool UpgradeDevice(const char *instance);
bool GetDeviceMac(const char *instance, char *dst, const size_t size);
bool SetDeviceMac(const char *instance, const char *src);
bool SetDeviceNetConfig(const char *instance);
HKEY GetDeviceRegKey(const char *instance, const bool writable);
#endif

36
src/vpndrvinst/Dialog.c Normal file
View File

@ -0,0 +1,36 @@
#include "Dialog.h"
#include <stdio.h>
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
int ShowMessage(const char *title, const char *message, const unsigned int type, const va_list args)
{
char buf[MAX_MESSAGE_SIZE];
vsnprintf(buf, sizeof(buf), message, args);
return MessageBox(NULL, buf, title, type);
}
int ShowInformation(const char *title, const char *message, ...)
{
va_list args;
va_start(args, message);
const int ret = ShowMessage(title, message, MB_OK | MB_ICONINFORMATION, args);
va_end(args);
return ret;
}
int ShowWarning(const char *title, const char *message, ...)
{
va_list args;
va_start(args, message);
const int ret = ShowMessage(title, message, MB_OK | MB_ICONWARNING, args);
va_end(args);
return ret;
}

9
src/vpndrvinst/Dialog.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef DIALOG_H
#define DIALOG_H
#define MAX_MESSAGE_SIZE 1024
int ShowInformation(const char *title, const char *message, ...);
int ShowWarning(const char *title, const char *message, ...);
#endif

378
src/vpndrvinst/Driver.c Normal file
View File

@ -0,0 +1,378 @@
#include "Driver.h"
#include "Dialog.h"
#include "Str.h"
#include <stdlib.h>
#include <Hamcore.h>
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <VersionHelpers.h>
const char *GetArch()
{
SYSTEM_INFO info;
GetNativeSystemInfo(&info);
switch (info.wProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_AMD64:
return "x64";
case PROCESSOR_ARCHITECTURE_INTEL:
return "x86";
case PROCESSOR_ARCHITECTURE_ARM64:
return "arm64";
case PROCESSOR_ARCHITECTURE_ARM:
return "arm";
case PROCESSOR_ARCHITECTURE_IA64:
return "ia64";
}
return NULL;
}
const char *GetDriverPath()
{
static char path[MAX_PATH];
static bool set = false;
if (set)
{
return path;
}
const char *type_folder;
if (IsWindows10OrGreater())
{
type_folder = "Neo6_Win10";
}
else if (IsWindows8OrGreater())
{
type_folder = "Neo6_Win8";
}
else if (IsWindows7OrGreater())
{
type_folder = "Neo6";
}
else
{
type_folder = "Neo";
}
snprintf(path, sizeof(path), "DriverPackages/%s/%s/", type_folder, GetArch());
set = true;
return path;
}
const char *GetTmpPath()
{
static char path[MAX_PATH];
static bool set = false;
if (set)
{
return path;
}
if (!GetTempPath(sizeof(path), path))
{
ShowWarning("GetTmpPath()", "GetTempPath() failed with error %lu!", GetLastError());
return NULL;
}
set = true;
return path;
}
void GetCatPath(char *dst, const size_t size, const char *instance)
{
if (!dst || size == 0)
{
return;
}
if (IsWindows10OrGreater())
{
if (!instance)
{
return;
}
snprintf(dst, size, "%sNeo6_%s_%s.cat", GetDriverPath(), GetArch(), instance);
}
else if (IsWindows8OrGreater())
{
snprintf(dst, size, "%sinf2.cat", GetDriverPath());
}
}
void GetInfPath(char *dst, const size_t size, const char *instance)
{
if (!dst || size == 0)
{
return;
}
if (IsWindows8OrGreater())
{
if (!instance)
{
return;
}
snprintf(dst, size, "%sNeo6_%s_%s.inf", GetDriverPath(), GetArch(), instance);
}
else if (IsWindows7OrGreater())
{
snprintf(dst, size, "%sNeo6_%s.inf", GetDriverPath(), GetArch());
}
else
{
snprintf(dst, size, "%sNeo_%s.inf", GetDriverPath(), GetArch());
}
}
void GetSysPath(char *dst, const size_t size, const char *instance)
{
if (!dst || size == 0)
{
return;
}
if (IsWindows10OrGreater())
{
if (!instance)
{
return;
}
snprintf(dst, size, "%sNeo6_%s_%s.sys", GetDriverPath(), GetArch(), instance);
}
else if (IsWindows7OrGreater())
{
snprintf(dst, size, "%sNeo6_%s.sys", GetDriverPath(), GetArch());
}
else
{
snprintf(dst, size, "%sNeo_%s.sys", GetDriverPath(), GetArch());
}
}
bool IsInstanceNameOK(HAMCORE *hamcore, const char *instance)
{
if (!IsWindows8OrGreater())
{
return true;
}
if (!hamcore || !instance)
{
return false;
}
char path[MAX_PATH];
GetInfPath(path, sizeof(path), instance);
const HAMCORE_FILE *file = HamcoreFind(hamcore, path);
return file ? true : false;
}
bool IsMacAddressManual()
{
return IsWindows8OrGreater();
}
bool PrepareCat(HAMCORE *hamcore, char *dst, const size_t size, const char *instance)
{
if (!IsWindows8OrGreater())
{
return true;
}
if (!hamcore || !dst || size == 0 || !instance)
{
return false;
}
char src[MAX_PATH];
GetCatPath(src, sizeof(src), instance);
const HAMCORE_FILE *hamcore_file = HamcoreFind(hamcore, src);
if (!hamcore_file)
{
ShowWarning("PrepareCat()", "%s not found in hamcore archive!", src);
return false;
}
void *buf = malloc(hamcore_file->OriginalSize);
if (!HamcoreRead(hamcore, buf, hamcore_file))
{
ShowWarning("PrepareCat()", "Failed to read %s from hamcore archive!", src);
free(buf);
return false;
}
if (IsWindows10OrGreater())
{
snprintf(dst, size, "%s%s", GetTmpPath(), PathFileName(src, false));
}
else
{
snprintf(dst, size, "%sinf_%s.cat", GetTmpPath(), instance);
}
bool ok = false;
HANDLE file = CreateFile(dst, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
{
ShowWarning("PrepareCat()", "CreateFile() failed to open \"%s\" with error %lu!", dst, GetLastError());
goto FINAL;
}
DWORD processed;
ok = WriteFile(file, buf, (DWORD)hamcore_file->OriginalSize, &processed, NULL);
CloseHandle(file);
if (!ok)
{
ShowWarning("PrepareCat()", "WriteFile() failed with error %lu!", src, GetLastError());
DeleteFile(dst);
}
FINAL:
free(buf);
return ok;
}
bool PrepareInf(HAMCORE *hamcore, char *dst, const size_t size, const char *instance, const char *sys, const char *mac)
{
if (!hamcore || !dst || size == 0 || !instance || !sys || !mac)
{
return false;
}
char src[MAX_PATH];
GetInfPath(src, sizeof(src), instance);
const HAMCORE_FILE *hamcore_file = HamcoreFind(hamcore, src);
if (!hamcore_file)
{
ShowWarning("PrepareInf()", "%s not found in hamcore archive!", src);
return false;
}
size_t buf_size = hamcore_file->OriginalSize;
char *buf = malloc(buf_size);
if (!HamcoreRead(hamcore, buf, hamcore_file))
{
ShowWarning("PrepareInf()", "Failed to read %s from hamcore archive!", src);
free(buf);
return false;
}
if (IsWindows10OrGreater())
{
snprintf(dst, size, "%s%s", GetTmpPath(), PathFileName(src, false));
}
else if (IsWindows7OrGreater())
{
snprintf(dst, size, "%sNeo6_%s_%s.inf", GetTmpPath(), GetArch(), instance);
}
else
{
snprintf(dst, size, "%sNeo_%s_%s.inf", GetTmpPath(), GetArch(), instance);
}
if (!IsWindows8OrGreater())
{
buf = StrReplace(buf, &buf_size, "$TAG_INSTANCE_NAME$", instance, false);
buf = StrReplace(buf, &buf_size, "$TAG_MAC_ADDRESS$", mac, false);
buf = StrReplace(buf, &buf_size, "$TAG_SYS_NAME$", PathFileName(sys, true), true);
}
bool ok = false;
HANDLE file = CreateFile(dst, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
{
ShowWarning("PrepareInf()", "CreateFile() failed to open \"%s\" with error %lu!", dst, GetLastError());
goto FINAL;
}
DWORD processed;
ok = WriteFile(file, buf, (DWORD)buf_size, &processed, NULL);
CloseHandle(file);
if (!ok)
{
ShowWarning("PrepareInf()", "WriteFile() failed with error %lu!", src, GetLastError());
DeleteFile(dst);
}
FINAL:
free(buf);
return ok;
}
bool PrepareSys(HAMCORE *hamcore, char *dst, const size_t size, const char *instance)
{
if (!hamcore || !dst || size == 0 || !instance)
{
return false;
}
char src[MAX_PATH];
GetSysPath(src, sizeof(src), instance);
const HAMCORE_FILE *hamcore_file = HamcoreFind(hamcore, src);
if (!hamcore_file)
{
ShowWarning("PrepareSys()", "%s not found in hamcore archive!", src);
return false;
}
void *buf = malloc(hamcore_file->OriginalSize);
if (!HamcoreRead(hamcore, buf, hamcore_file))
{
ShowWarning("PrepareSys()", "Failed to read %s from hamcore archive!", src);
free(buf);
return false;
}
if (IsWindows10OrGreater())
{
snprintf(dst, size, "%s%s", GetTmpPath(), PathFileName(src, false));
}
else
{
snprintf(dst, size, "%sNeo_%s.sys", GetTmpPath(), instance);
}
bool ok = false;
HANDLE file = CreateFile(dst, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
{
ShowWarning("PrepareSys()", "CreateFile() failed to open \"%s\" with error %lu!", dst, GetLastError());
goto FINAL;
}
DWORD processed;
ok = WriteFile(file, buf, (DWORD)hamcore_file->OriginalSize, &processed, NULL);
CloseHandle(file);
if (!ok)
{
ShowWarning("PrepareSys()", "WriteFile() failed with error %lu!", src, GetLastError());
DeleteFile(dst);
}
FINAL:
free(buf);
return ok;
}

27
src/vpndrvinst/Driver.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef DRIVER_H
#define DRIVER_H
#include <stdbool.h>
#include <stddef.h>
#define DRIVER_DEVICE_ID_TAG "NeoAdapter_%s"
#define VLAN_ADAPTER_NAME_TAG "VPN Client Adapter - %s"
typedef struct HAMCORE HAMCORE;
const char *GetArch();
const char *GetDriverPath();
const char *GetTmpPath();
void GetCatPath(char *dst, const size_t size, const char *instance);
void GetInfPath(char *dst, const size_t size, const char *instance);
void GetSysPath(char *dst, const size_t size, const char *instance);
bool IsInstanceNameOK(HAMCORE *hamcore, const char *instance);
bool IsMacAddressManual();
bool PrepareCat(HAMCORE *hamcore, char *dst, const size_t size, const char *instance);
bool PrepareInf(HAMCORE *hamcore, char *dst, const size_t size, const char *instance, const char *sys, const char *mac);
bool PrepareSys(HAMCORE *hamcore, char *dst, const size_t size, const char *instance);
#endif

111
src/vpndrvinst/Str.c Normal file
View File

@ -0,0 +1,111 @@
#include "Str.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <guiddef.h>
void GenMacAddress(char *dst, const size_t size)
{
if (!dst || size == 0)
{
return;
}
srand((unsigned int)time(NULL));
uint8_t mac[6];
mac[0] = 0x5E;
mac[1] = rand() % 256;
mac[2] = rand() % 256;
mac[3] = rand() % 256;
mac[4] = rand() % 256;
mac[5] = rand() % 256;
snprintf(dst, size, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
const char *PathFileName(const char *path, const bool backslash)
{
if (!path)
{
return NULL;
}
const char *ret = strrchr(path, backslash ? '\\' : '/');
if (ret)
{
++ret;
}
return ret;
}
void StrFromGUID(char *dst, const size_t size, const GUID *guid)
{
if (!dst || size == 0 || !guid)
{
return;
}
snprintf(dst, size, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
char *StrReplace(char *str, size_t *size, const char *target, const char *replacement, const bool shrink)
{
if (!str || !size || !target || !replacement)
{
return str;
}
const char *seek = str;
size_t str_len = strlen(str);
const size_t target_len = strlen(target);
const size_t replacement_len = strlen(replacement);
char *at_target;
while ((at_target = strstr(seek, target)))
{
size_t new_str_len = str_len;
if (target_len > replacement_len)
{
new_str_len -= target_len - replacement_len;
}
else
{
new_str_len += replacement_len - target_len;
const size_t required_size = new_str_len + 1;
if (*size < required_size)
{
const char *old_str = str;
*size = required_size;
str = realloc(str, *size);
seek = str + (seek - old_str);
at_target = str + (at_target - old_str);
}
}
const char *after_target = at_target + target_len;
memmove(at_target + replacement_len, after_target, str_len - (after_target - seek) + 1);
memcpy(at_target, replacement, replacement_len);
str_len = new_str_len;
}
if (shrink && *size > str_len + 1)
{
*size = str_len + 1;
str = realloc(str, *size);
}
return str;
}

19
src/vpndrvinst/Str.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef STR_H
#define STR_H
#include <stdbool.h>
#include <stddef.h>
#define MAC_BUFFER_SIZE 13
typedef struct _GUID GUID;
void GenMacAddress(char *dst, const size_t size);
const char *PathFileName(const char *path, const bool backslash);
void StrFromGUID(char *dst, const size_t size, const GUID *guid);
char *StrReplace(char *str, size_t *size, const char *target, const char *replacement, const bool shrink);
#endif

59
src/vpndrvinst/main.c Normal file
View File

@ -0,0 +1,59 @@
#include "Device.h"
#include "Dialog.h"
#include <stdio.h>
void ShowUsage()
{
const char *message =
"Usage: vpndrvinst <action> <instance>\n"
"\n"
"\"instvlan\": Installs a new virtual network interface\n"
"\"uninstvlan\": Uninstalls an existing virtual network interface\n"
"\"upgradevlan\": Updates the driver for an existing virtual network interface\n"
"\"enablevlan\": Enables an existing virtual network interface\n"
"\"disablevlan\": Disables an existing virtual network interface\n"
"\n"
"Example: vpndrvinst instvlan VPN21";
ShowInformation("Usage", message);
}
int main(const int argc, const char **argv)
{
if (argc < 3)
{
ShowUsage();
return 0;
}
bool ok = true;
const char* action = argv[1];
if (strcmp(action, "instvlan") == 0)
{
ok = InstallDevice(argv[2]);
}
else if (strcmp(action, "uninstvlan") == 0)
{
ok = UninstallDevice(argv[2]);
}
else if (strcmp(action, "upgradevlan") == 0)
{
ok = UpgradeDevice(argv[2]);
}
else if (strcmp(action, "enablevlan") == 0)
{
ok = ToggleDevice(argv[2], true);
}
else if (strcmp(action, "disablevlan") == 0)
{
ok = ToggleDevice(argv[2], false);
}
else
{
ShowUsage();
}
return ok ? 0 : 1;
}

View File

@ -1,253 +0,0 @@
// SoftEther VPN Source Code - Developer Edition Master Branch
// VPN Driver Installer
#include <GlobalConst.h>
#ifdef WIN32
#define HAM_WIN32
#define _WIN32_WINNT 0x0502
#define WINVER 0x0502
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <DbgHelp.h>
#include <Iphlpapi.h>
#include <wtsapi32.h>
#include "../pencore/resource.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <math.h>
#include <Mayaqua/Mayaqua.h>
#include <Cedar/Cedar.h>
#include "vpndrvinst.h"
void disablevlan(UINT num, char **arg)
{
bool ok;
if (num < 1)
{
return;
}
ok = MsDisableVLan(arg[0]);
if (ok == false)
{
_exit(1);
}
else
{
_exit(0);
}
}
void enablevlan(UINT num, char **arg)
{
bool ok;
if (num < 1)
{
return;
}
ok = MsEnableVLan(arg[0]);
if (ok == false)
{
_exit(1);
}
else
{
_exit(0);
}
}
void instvlan(UINT num, char **arg)
{
KAKUSHI *k = NULL;
MS_DRIVER_VER ver;
bool ok;
if (num < 1)
{
return;
}
InitWinUi(L"VPN", _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
if (MsIsNt())
{
k = InitKakushi();
}
CiInitDriverVerStruct(&ver);
ok = MsInstallVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, arg[0], &ver);
FreeKakushi(k);
FreeWinUi();
if (ok == false)
{
_exit(1);
}
else
{
_exit(0);
}
}
void upgradevlan(UINT num, char **arg)
{
bool ok;
KAKUSHI *k = NULL;
MS_DRIVER_VER ver;
if (num < 1)
{
return;
}
InitWinUi(L"VPN", _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
if (MsIsNt())
{
k = InitKakushi();
}
CiInitDriverVerStruct(&ver);
ok = MsUpgradeVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, arg[0], &ver);
FreeKakushi(k);
FreeWinUi();
if (ok == false)
{
_exit(1);
}
else
{
_exit(0);
}
}
void uninstvlan(UINT num, char **arg)
{
bool ok;
if (num < 1)
{
return;
}
ok = MsUninstallVLan(arg[0]);
if (ok == false)
{
_exit(1);
}
else
{
_exit(0);
}
}
TEST_LIST test_list[] =
{
{"instvlan", instvlan},
{"uninstvlan", uninstvlan},
{"upgradevlan", upgradevlan},
{"enablevlan", enablevlan},
{"disablevlan", disablevlan},
};
// Main function
void MainFunction(char *cmd)
{
char tmp[MAX_SIZE];
bool first = true;
bool exit_now = false;
while (true)
{
if (first && StrLen(cmd) != 0 && g_memcheck == false)
{
first = false;
StrCpy(tmp, sizeof(tmp), cmd);
exit_now = true;
Print("%s\n", cmd);
}
else
{
_exit(0);
}
Trim(tmp);
if (StrLen(tmp) != 0)
{
UINT i, num;
bool b = false;
TOKEN_LIST *token = ParseCmdLine(tmp);
char *cmd = token->Token[0];
num = sizeof(test_list) / sizeof(TEST_LIST);
for (i = 0;i < num;i++)
{
if (!StrCmpi(test_list[i].command_str, cmd))
{
char **arg = Malloc(sizeof(char *) * (token->NumTokens - 1));
UINT j;
for (j = 0;j < token->NumTokens - 1;j++)
{
arg[j] = CopyStr(token->Token[j + 1]);
}
test_list[i].proc(token->NumTokens - 1, arg);
for (j = 0;j < token->NumTokens - 1;j++)
{
Free(arg[j]);
}
Free(arg);
b = true;
_exit(1);
break;
}
}
FreeToken(token);
if (exit_now)
{
break;
}
}
}
}
// winmain function
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow)
{
InitProcessCallOnce();
#if defined(_DEBUG) || defined(DEBUG) // In VC++ compilers, the macro is "_DEBUG", not "DEBUG".
// If set memcheck = true, the program will be vitally slow since it will log all malloc() / realloc() / free() calls to find the cause of memory leak.
// For normal debug we set memcheck = false.
// Please set memcheck = true if you want to test the cause of memory leaks.
InitMayaqua(false, true, 0, NULL);
#else
InitMayaqua(false, false, 0, NULL);
#endif
EnableProbe(false);
InitCedar();
SetHamMode();
MainFunction(cmdline);
FreeCedar();
FreeMayaqua();
return 0;
}

View File

@ -1,23 +0,0 @@
// SoftEther VPN Source Code - Developer Edition Master Branch
// VPN Driver Installer
// List of test functions
typedef void (TEST_PROC)(UINT num, char **arg);
typedef struct TEST_LIST
{
char *command_str;
TEST_PROC *proc;
} TEST_LIST;
// function prototypes
void disablevlan(UINT num, char **arg);
void enablevlan(UINT num, char **arg);
void instvlan(UINT num, char **arg);
void upgradevlan(UINT num, char **arg);
void uninstvlan(UINT num, char **arg);
void MainFunction(char *cmd);
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow);

View File

@ -1,72 +1 @@
// Microsoft Visual C++ generated resource script. IDI_ICON1 ICON DISCARDABLE "vpndrvinst.ico"
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Japanese resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)
#ifdef _WIN32
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
#pragma code_page(932)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON2 ICON "vpndrvinst.ico"
#endif // Japanese resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED