mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-12-26 01:59:53 +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:
parent
68367fa2fb
commit
9d29d8813b
@ -5514,6 +5514,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
|
||||
ShowWindow(hWnd, SW_SHOWNORMAL);
|
||||
}
|
||||
Free(name);
|
||||
|
||||
CmRefresh(hWnd);
|
||||
}
|
||||
break;
|
||||
case CMD_DELETE_VLAN:
|
||||
@ -5554,6 +5556,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
|
||||
false, false);
|
||||
}
|
||||
}
|
||||
|
||||
CmRefresh(hWnd);
|
||||
}
|
||||
break;
|
||||
case CMD_ENABLE_VLAN:
|
||||
@ -5573,6 +5577,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
|
||||
CALL(hWnd, CcEnableVLan(cm->Client, &c));
|
||||
}
|
||||
Free(s);
|
||||
|
||||
CmRefresh(hWnd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -5593,6 +5599,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
|
||||
CALL(hWnd, CcDisableVLan(cm->Client, &c));
|
||||
}
|
||||
Free(s);
|
||||
|
||||
CmRefresh(hWnd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -5643,6 +5651,8 @@ void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
|
||||
}
|
||||
}
|
||||
Free(s);
|
||||
|
||||
CmRefresh(hWnd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2129,6 +2129,7 @@ bool MsExecDriverInstaller(char *arg)
|
||||
info.cbSize = sizeof(info);
|
||||
info.lpVerb = L"open";
|
||||
info.lpFile = tmp;
|
||||
info.lpDirectory = MsGetMyTempDirW();
|
||||
info.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
info.lpParameters = arg_w;
|
||||
info.nShow = SW_SHOWNORMAL;
|
||||
|
@ -5,7 +5,17 @@ endif()
|
||||
set(COMPONENT_NAME "Driver Installer")
|
||||
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)
|
||||
set(COMPONENT_FILE_NAME "${COMPONENT_FILE_NAME}.exe")
|
||||
@ -18,6 +28,9 @@ if(MSVC)
|
||||
set_target_properties(vpndrvinst PROPERTIES LINK_FLAGS "/manifestuac:level='requireAdministrator'")
|
||||
endif()
|
||||
|
||||
# Hide console while keeping main() as entry point
|
||||
target_link_options(vpndrvinst PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
|
||||
|
||||
if(${COMPILER_ARCHITECTURE} STREQUAL "x64")
|
||||
target_sources(vpndrvinst PRIVATE "${TOP_DIRECTORY}/src/BuildFiles/Manifests/x64_admin.manifest")
|
||||
else()
|
||||
@ -32,4 +45,9 @@ set_target_properties(vpndrvinst
|
||||
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
564
src/vpndrvinst/Device.c
Normal 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, ¶ms.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, ¶ms.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
30
src/vpndrvinst/Device.h
Normal 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
36
src/vpndrvinst/Dialog.c
Normal 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
9
src/vpndrvinst/Dialog.h
Normal 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
378
src/vpndrvinst/Driver.c
Normal 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
27
src/vpndrvinst/Driver.h
Normal 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
111
src/vpndrvinst/Str.c
Normal 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
19
src/vpndrvinst/Str.h
Normal 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
59
src/vpndrvinst/main.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -1,72 +1 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#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
|
||||
|
||||
IDI_ICON1 ICON DISCARDABLE "vpndrvinst.ico"
|
||||
|
Loading…
Reference in New Issue
Block a user