1. 初始化工程

This commit is contained in:
黄昕 2023-08-22 15:12:52 +08:00
commit 699beabd78
51 changed files with 20046 additions and 0 deletions

220
.clang-format Normal file
View File

@ -0,0 +1,220 @@
# ClangFormatConfigureSource: 'clang-format-file://D:/development/c/daemon_agent/.clang-format'
Language: Cpp
AccessModifierOffset: -4
InsertBraces: true
AlignArrayOfStructures: Left
AlignAfterOpenBracket: Align
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
PadOperators: true
AlignCompound: true
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
PadOperators: true
AlignCompound: true
AlignEscapedNewlines: Left
AlignOperands: DontAlign
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
- __unused
BinPackArguments: true
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: true
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequiresClause: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 1000
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 140
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: false
SortIncludes: Never
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 4
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
SeparateDefinitionBlocks: Always
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
TypenameMacros:
- CONFIG_ITEM
- PCONFIG_ITEM

133
.gitignore vendored Normal file
View File

@ -0,0 +1,133 @@
### C++ template
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
### CMake template
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
### CLion template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

9
CMakeLists.txt Normal file
View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.22)
project(scc)
set(CMAKE_CXX_STANDARD 23)
add_definitions(-D_UNICODE)
ADD_SUBDIRECTORY(NetTunnelSvr)
ADD_SUBDIRECTORY(NetTunnelServerApp)
ADD_SUBDIRECTORY(NetTunnelSDK)

View File

@ -0,0 +1,44 @@
cmake_minimum_required(VERSION 3.22)
project(NetTunnelSDK)
set(CMAKE_CXX_STANDARD 23)
find_path(CPPCODEC_INCLUDE_DIRS "cppcodec/base32_crockford.hpp")
INCLUDE_DIRECTORIES(include ./include/json ./include/httplib ../depends/WireGuardNT/include ${CPPCODEC_INCLUDE_DIRS})
FILE(GLOB CPP_HEADS ./include/*.h ./include/json/AIGCJson.hpp ./include/httplib/httplib.h ../depends/WireGuardNT/include/*.h ${CPPCODEC_INCLUDE_DIRS}/*.hpp)
ADD_DEFINITIONS(-DNETTUNNELSDK_EXPORTS)
AUX_SOURCE_DIRECTORY(tunnel CPP_SRC)
AUX_SOURCE_DIRECTORY(crypto CPP_SRC)
AUX_SOURCE_DIRECTORY(misc CPP_SRC)
AUX_SOURCE_DIRECTORY(network CPP_SRC)
AUX_SOURCE_DIRECTORY(protocol CPP_SRC)
AUX_SOURCE_DIRECTORY(user CPP_SRC)
find_package(spdlog CONFIG REQUIRED)
find_package(magic_enum CONFIG REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(RapidJSON CONFIG REQUIRED)
ADD_LIBRARY(NetTunnelSDK SHARED dllmain.cpp ${CPP_SRC} ${CPP_HEADS})
target_link_libraries(NetTunnelSDK PRIVATE spdlog::spdlog)
target_link_libraries(NetTunnelSDK PRIVATE magic_enum::magic_enum)
target_link_libraries(NetTunnelSDK PRIVATE OpenSSL::SSL OpenSSL::Crypto)
target_link_libraries(NetTunnelSDK PRIVATE rapidjson)
ADD_CUSTOM_COMMAND(TARGET NetTunnelSDK
PRE_BUILD
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "!!!!!! Notice: Clearup SDK includes."
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_SOURCE_DIR}/sdk"
COMMAND ../scripts/cleansdk.bat)
ADD_CUSTOM_COMMAND(TARGET NetTunnelSDK
POST_BUILD
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "!!!!!! Notice: Create SDK includes."
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_SOURCE_DIR}/sdk"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/include/sccsdk.h" "${PROJECT_SOURCE_DIR}/sdk"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/include/common.h" "${PROJECT_SOURCE_DIR}/sdk"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/include/usrerr.h" "${PROJECT_SOURCE_DIR}/sdk"
COMMAND ../scripts/gensdk.bat)

View File

@ -0,0 +1,288 @@
#include "pch.h"
#include "tunnel.h"
#include "usrerr.h"
#include "misc.h"
#include <bcrypt.h>
#include <wincrypt.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <cppcodec/base64_url_unpadded.hpp>
#include <spdlog/spdlog.h>
#pragma comment(lib, "Bcrypt.lib")
#pragma comment(lib, "Crypt32.lib")
#define NT_FAILED(s) (((NTSTATUS)(s)) < 0)
static const LPCWSTR g_BcryptHash[] = {
BCRYPT_MD2_ALGORITHM,
BCRYPT_MD4_ALGORITHM,
BCRYPT_MD5_ALGORITHM,
BCRYPT_SHA1_ALGORITHM,
BCRYPT_SHA256_ALGORITHM,
BCRYPT_SHA384_ALGORITHM,
BCRYPT_SHA512_ALGORITHM,
};
int CalcFileHash(HASH_TYPE type, const TCHAR *pPath, TCHAR outHash[]) {
HANDLE hFile;
BYTE rgbFile[1024];
DWORD cbRead = 0;
BCRYPT_ALG_HANDLE hAlg = nullptr;
BCRYPT_HASH_HANDLE hHash = nullptr;
NTSTATUS status;
DWORD cbData = 0, cbHash = 0, cbHashObject = 0;
PBYTE pbHashObject;
PBYTE pbHash;
if (pPath == nullptr) {
SPDLOG_ERROR(TEXT("Input pPath params error: {0}"), pPath);
return -ERR_INPUT_PARAMS;
}
if (!PathFileExists(pPath)) {
SPDLOG_ERROR(TEXT("File \'{0}\' not found."), pPath);
return -ERR_ITEM_UNEXISTS;
}
hFile = CreateFile(pPath,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
nullptr);
if (INVALID_HANDLE_VALUE == hFile) {
SPDLOG_ERROR(TEXT("Error opening file %s\nError: {0}"), pPath, GetLastError());
return -ERR_OPEN_FILE;
}
//open an algorithm handle
if (NT_FAILED(status = BCryptOpenAlgorithmProvider(&hAlg, g_BcryptHash[type], nullptr, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptOpenAlgorithmProvider"), status);
CloseHandle(hFile);
return -ERR_BCRYPT_OPEN;
}
//calculate the size of the buffer to hold the hash object
if (NT_FAILED(status = BCryptGetProperty(hAlg,
BCRYPT_OBJECT_LENGTH,
reinterpret_cast<PBYTE>(&cbHashObject),
sizeof(DWORD),
&cbData,
0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptGetProperty"), status);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
return -ERR_BCRYPT_GETPROPERTY;
}
//allocate the hash object on the heap
pbHashObject = static_cast<PBYTE>(HeapAlloc(GetProcessHeap(), 0, cbHashObject));
if (nullptr == pbHashObject) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), cbHashObject);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
return -ERR_MALLOC_MEMORY;
}
//calculate the length of the hash
if (NT_FAILED(status = BCryptGetProperty(hAlg,
BCRYPT_HASH_LENGTH,
reinterpret_cast<PBYTE>(&cbHash),
sizeof(DWORD),
&cbData,
0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptGetProperty"), status);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
HeapFree(GetProcessHeap(), 0, pbHashObject);
return -ERR_BCRYPT_GETPROPERTY;
}
//allocate the hash buffer on the heap
pbHash = static_cast<PBYTE>(HeapAlloc(GetProcessHeap(), 0, cbHash));
if (nullptr == pbHash) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), cbHash);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
HeapFree(GetProcessHeap(), 0, pbHashObject);
return -ERR_MALLOC_MEMORY;
}
//create a hash
if (NT_FAILED(status = BCryptCreateHash(hAlg, &hHash, pbHashObject, cbHashObject, nullptr, 0, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptCreateHash"), status);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return -ERR_BCRYPT_CREATEHASH;
}
while (ReadFile(hFile, rgbFile, 1024, &cbRead, nullptr)) {
if (0 == cbRead) {
break;
}
if (NT_FAILED(status = BCryptHashData(hHash, rgbFile, cbRead, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptHashData"), status);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
BCryptDestroyHash(hHash);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return -ERR_BCRYPT_HASHDATA;
}
}
//close the hash
if (NT_FAILED(status = BCryptFinishHash(hHash, pbHash, cbHash, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptFinishHash"), status);
CloseHandle(hFile);
BCryptCloseAlgorithmProvider(hAlg, 0);
BCryptDestroyHash(hHash);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return -ERR_BCRYPT_FINISHHASH;
}
binToHexString(outHash, pbHash, cbHash);
BCryptCloseAlgorithmProvider(hAlg, 0);
BCryptDestroyHash(hHash);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
CloseHandle(hFile);
return ERR_SUCCESS;
}
/**
* @brief HMAC HASH
* @param[in] type Hash @see HASH_TYPE
* @param[in] pHashData Hash
* @param[in] inSize Hash ()
* @param[in] pKey HMAC Hash
* @param[in] keySize HMAC Hash ()
* @param[out] outHash
* @param[in] outBase64 BASE64
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_OPEN_FILE
* - -ERR_BCRYPT_OPEN
* - -ERR_BCRYPT_GETPROPERTY
* - -ERR_BCRYPT_CREATEHASH Hash
* - -ERR_BCRYPT_HASHDATA Hash
* - -ERR_BCRYPT_FINISHHASH Hash
* - ERR_SUCCESS
*/
int CalcHmacHash(HASH_TYPE type,
PUCHAR pHashData,
int inSize,
PUCHAR pKey,
int keySize,
TCHAR outHash[],
bool outBase64) {
BCRYPT_ALG_HANDLE hAlg = nullptr;
BCRYPT_HASH_HANDLE hHash = nullptr;
NTSTATUS status;
DWORD cbData = 0, cbHash = 0, cbHashObject = 0;
PBYTE pbHashObject;
PBYTE pbHash;
//open an algorithm handle
if (NT_FAILED(
status = BCryptOpenAlgorithmProvider(&hAlg, g_BcryptHash[type], nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptOpenAlgorithmProvider"), status);
return -ERR_BCRYPT_OPEN;
}
//calculate the size of the buffer to hold the hash object
if (NT_FAILED(status = BCryptGetProperty(hAlg,
BCRYPT_OBJECT_LENGTH,
reinterpret_cast<PBYTE>(&cbHashObject),
sizeof(DWORD),
&cbData,
0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptGetProperty"), status);
BCryptCloseAlgorithmProvider(hAlg, 0);
return -ERR_BCRYPT_GETPROPERTY;
}
//allocate the hash object on the heap
pbHashObject = static_cast<PBYTE>(HeapAlloc(GetProcessHeap(), 0, cbHashObject));
if (nullptr == pbHashObject) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), cbHashObject);
BCryptCloseAlgorithmProvider(hAlg, 0);
return -ERR_MALLOC_MEMORY;
}
//calculate the length of the hash
if (NT_FAILED(status = BCryptGetProperty(hAlg,
BCRYPT_HASH_LENGTH,
reinterpret_cast<PBYTE>(&cbHash),
sizeof(DWORD),
&cbData,
0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptGetProperty"), status);
BCryptCloseAlgorithmProvider(hAlg, 0);
HeapFree(GetProcessHeap(), 0, pbHashObject);
return -ERR_BCRYPT_GETPROPERTY;
}
//allocate the hash buffer on the heap
pbHash = static_cast<PBYTE>(HeapAlloc(GetProcessHeap(), 0, cbHash));
if (nullptr == pbHash) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), cbHash);
BCryptCloseAlgorithmProvider(hAlg, 0);
HeapFree(GetProcessHeap(), 0, pbHashObject);
return -ERR_MALLOC_MEMORY;
}
//create a hash
if (NT_FAILED(status = BCryptCreateHash(hAlg, &hHash, pbHashObject, cbHashObject, pKey, keySize, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptCreateHash"), status);
BCryptCloseAlgorithmProvider(hAlg, 0);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return -ERR_BCRYPT_CREATEHASH;
}
//hash some data
if (NT_FAILED(status = BCryptHashData(hHash, pHashData, inSize, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptHashData"), status);
BCryptCloseAlgorithmProvider(hAlg, 0);
BCryptDestroyHash(hHash);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return -ERR_BCRYPT_HASHDATA;
}
//close the hash
if (NT_FAILED(status = BCryptFinishHash(hHash, pbHash, cbHash, 0))) {
SPDLOG_ERROR(TEXT("Error {0} returned by BCryptFinishHash"), status);
BCryptCloseAlgorithmProvider(hAlg, 0);
BCryptDestroyHash(hHash);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return -ERR_BCRYPT_FINISHHASH;
}
if (outBase64) {
using base64 = cppcodec::base64_url_unpadded;
StringCbCopy(outHash, 256, base64::encode(pbHash, cbHash).c_str());
} else {
binToHexString(outHash, pbHash, cbHash);
}
BCryptCloseAlgorithmProvider(hAlg, 0);
BCryptDestroyHash(hHash);
HeapFree(GetProcessHeap(), 0, pbHashObject);
HeapFree(GetProcessHeap(), 0, pbHash);
return ERR_SUCCESS;
}

View File

@ -0,0 +1,9 @@
#include "pch.h"
#include "tunnel.h"
#include "usrerr.h"
#include "misc.h"
#include <strsafe.h>
#include <bcrypt.h>
#include <spdlog/spdlog.h>

17
NetTunnelSDK/dllmain.cpp Normal file
View File

@ -0,0 +1,17 @@
//
// Created by HuangXin on 2023/8/22.
//
#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}

View File

@ -0,0 +1,56 @@
#pragma once
#include "AIGCJson.hpp"
#define USER_REAL_PLATFORM (0)
class ProtocolBase {
public:
ProtocolBase() {
this->ver = 1;
this->timeStamp = static_cast<unsigned int>(time(nullptr));
this->cryptoType = 0;
}
unsigned int ver;
unsigned int cryptoType;
unsigned int timeStamp;
AIGC_JSON_HELPER(ver, cryptoType, timeStamp)
void SetVersion(unsigned int versino) {
this->ver = versino;
}
void SetTimeStamp(unsigned int ts) {
this->timeStamp = ts;
}
void SetCryptoType(unsigned int crypto) {
this->cryptoType = crypto;
}
};
class ResponseStatus {
public:
int errCode;
std::string errMessage;
AIGC_JSON_HELPER(errCode, errMessage)
};
template<class T> class ProtocolRequest : public ProtocolBase {
public:
T msgContent;
AIGC_JSON_HELPER(msgContent)
AIGC_JSON_HELPER_BASE((ProtocolBase *)this)
};
template<class T> class ProtocolResponse : public ProtocolBase {
public:
int code;
T msgContent;
AIGC_JSON_HELPER(code, msgContent)
AIGC_JSON_HELPER_BASE((ProtocolBase *)this)
};

View File

@ -0,0 +1,142 @@
#pragma once
#define USED_PORTMAP_TUNNEL (1)
/**
* @brief WireGuard key
*/
#define WG_KEY_MAX (64)
/**
* @brief
*/
#define NET_CARD_MAX (32)
/**
* @brief IP (IPv6)
*/
#define MAX_IP_LEN (48)
/**
* @brief IP
*/
#define MIN_IP_LEN (7)
/**
* @brief (IPv6)
*/
#define MAX_NETCARD_NAME (64)
/**
* @brief SCG ID
*
*/
typedef enum {
WG_TUNNEL_SCG_ID = 3, ///< 隧道服务
WG_CTRL_SCG_ID = 4 ///< 隧道控制服务
} SCG_SVR_ID;
/**
* @brief
*
*/
typedef enum {
CRYPTO_NONE = 0, ///< 不加密
CRYPTO_BASE64 = 1, ///< BASE64 字符串编码
CRYPTO_AES128 = 2, ///< AES 128位秘钥 加密
CRYPTO_3DES = 3, ///< 3DES 加密
CRYPTO_AES256 = 4, ///< AES 256 位秘钥加密
CRYPTO_MAX,
} PROTO_CRYPTO_TYPE;
/**
* @brief
*
*/
typedef enum {
STATUS_DISCONNECTED = 0, ///< 连接已断开连接
STATUS_CONNECTING, ///< 连接正在进行连接
STATUS_CONNECTED, ///< 连接处于连接状态
STATUS_DISCONNECTING, ///< 连接正在断开连接
STATUS_HARDWARE_NOT_PRESENT, ///< 连接的硬件(例如网络接口卡 (NIC) )不存在
STATUS_HARDWARE_DISABLED, ///< 连接的硬件存在,但未启用
STATUS_HARDWARE_MALFUNCTION, ///< 连接的硬件中发生了故障
STATUS_MEDIA_DISCONNECTED, ///< 媒体(例如网络电缆)断开连接
STATUS_AUTHENTICATING, ///< 连接正在等待身份验证发生
STATUS_AUTHENTICATION_SUCCEEDED, ///< 身份验证在此连接上成功
STATUS_AUTHENTICATION_FAILED, ///< 此连接上身份验证失败
STATUS_INVALID_ADDRESS, ///< 地址无效
STATUS_CREDENTIALS_REQUIRED, ///< 需要安全凭据
STATUS_ACTION_REQUIRED, ///< 连接需要其它动作
STATUS_ACTION_REQUIRED_RETRY, ///< 重试连接其它动作
STATUS_CONNECT_FAILED, ///< 连接失败
} NET_CONNECT_STATUS;
/**
* @brief
*
*/
enum LOG_LEVEL {
LOG_TRACE = 0, ///< TRACE 日志等级
LOG_DEBUG, ///< DEBUG 日志等级
LOG_INFO, ///< INFO 日志等级
LOG_WARN, ///< WARN 日志等级
LOG_ERROR, ///< ERROR 日志等级
LOG_CRITICAL, ///< CRITICAL 日志等级
LOG_OFF ///< 关闭日志
};
/**
* @brief Hash
*
*/
typedef enum {
HASH_MD2 = 0, ///< MD2 HASH 算法
HASH_MD4, ///< MD4 HASH 算法
HASH_MD5, ///< MD5 HASH 算法
HASH_SHA1, ///< SHA1 HASH 算法
HASH_SHA256, ///< SHA256 HASH 算法
HASH_SHA384, ///< SHA384 HASH 算法
HASH_SHA512 ///< SHA512 HASH 算法
} HASH_TYPE;
/**
* @brief
*
*/
typedef enum {
ICS_SHARE_MODE = 0, ///< Internet Share Mode(ICS) 模式
NAT_SHARE_MODE = 1 ///< Net Address Translation(NAT) 模式
} NET_SHARE_MODE;
/**
*
* @brief
*/
typedef struct {
int vmId; ///< 用户虚拟机 ID
TCHAR vmName[MAX_PATH]; ///< 用户虚拟机名称
TCHAR svrPublicKey[64]; ///< 用户服务端公钥
TCHAR vmNetwork[MAX_IP_LEN]; ///< 用户虚拟机网络地址
TCHAR scgGateWay[MAX_PATH]; ///< 用户服务端接入网关
TCHAR scgTunnelGw[MAX_PATH]; ///< 用户隧道接入网关
} VM_CFG, *PVM_CFG;
/**
*
* @brief
*/
typedef struct {
int scgCtrlAppId; ///< 用户接入网关控制 ID
int scgTunnelAppId; ///< 用户接入网关隧道 ID
TCHAR cliPrivateKey[64]; ///< 用户客户端私钥
TCHAR cliPublicKey[64]; ///< 用户客户端公钥
TCHAR cliAddress[MAX_IP_LEN]; ///< 用户客户端隧道IP地址
PVM_CFG pVMConfig; ///< 用户虚拟机配置列表
int tolVM; ///< 用户虚拟机配置最大数
} USER_CLIENT_CONFIG, *PUSER_CLIENT_CONFIG;
typedef struct {
int svrListenPort; ///< 用户服务端监听端口
TCHAR svrPrivateKey[64]; ///< 用户服务端公钥
TCHAR svrAddress[MAX_IP_LEN]; ///< 用户服务端隧道 IP 地址
} USER_SERVER_CONFIG, *PUSER_SERVER_CONFIG;

View File

@ -0,0 +1,84 @@
#pragma once
#include <spdlog/spdlog.h>
#include "common.h"
#include <winsock2.h>
#if 0
/**
* @brief WireGuard
*/
typedef struct {
TCHAR wireguardPath[MAX_PATH]; ///< wireguard.exe 路径
BOOL wireguardExists; ///< wireguard.exe 是否存在
TCHAR wgPath[MAX_PATH]; ///< wg.exe 路径
BOOL wgExists; ///< wg.exe 是否存在
} WIREGUARD_CFG, *PWIREGUARD_CFG;
#endif
/**
* @brief WireGuard
*/
typedef struct {
TCHAR wgName[260]; ///< 网卡名称, Windows标识为 UUID
TCHAR wgIpaddr[MAX_IP_LEN]; ///< 网卡 IP 地址
TCHAR wgNetmask[MAX_IP_LEN]; ///< 网卡子网掩码
TCHAR wgCfgPath[MAX_PATH]; ///< 配置文件路径
} WGINTERFACE_CFG, *PWGINTERFACE_CFG;
/**
* @brief
*/
typedef struct {
TCHAR userName[MAX_PATH]; ///< 用户名
TCHAR userToken[MAX_PATH]; ///< 用户访问令牌
USER_CLIENT_CONFIG cliConfig; ///< 用户客户端配置
USER_SERVER_CONFIG svrConfig; ///< 用户服务端配置
} USER_CONFIG, *PUSER_CONFIG;
typedef struct {
TCHAR targetIp[MAX_IP_LEN];
UINT16 targetPort;
UINT16 proxyPort;
UINT16 scgGwPort;
TCHAR scgIpAddr[MAX_IP_LEN];
SOCKET udpProxySock;
SOCKET scgGwSock;
HANDLE hProxyTunnelThread;
HANDLE hProxySCGThread;
bool exitNow;
} SCG_PROXY_INFO, *PSCG_PROXY_INFO;
/**
* @brief SDK
*/
typedef struct {
TCHAR platformServerUrl[MAX_PATH]; ///< 管理平台IP地址
TCHAR configDirectory[MAX_PATH]; ///< 配置存放目录
TCHAR systemDirectory[MAX_PATH]; ///< 操作系统目录
TCHAR workDirectory[MAX_PATH]; ///< SDK 当前工作目录
bool isWorkServer; ///< SDK 当前模式 客户端/服务端
PROTO_CRYPTO_TYPE proCryptoType; ///< 协议加密类型
TCHAR proKeyBuf[256]; ///< 协议加密秘钥
BOOL enableLog; ///< 是否启用日志
spdlog::level::level_enum logLevel; ///< 日志等级
TCHAR cfgPath[MAX_PATH]; ///< 配置文件路径
WGINTERFACE_CFG wgServerCfg; ///< wireguard 服务端网络接口配置
WGINTERFACE_CFG wgClientCfg; ///< wireguard 客户端网络接口配置
USER_CONFIG userCfg; ///< 用户配置项
SCG_PROXY_INFO scgProxy; ///< SCG UDP 代理信息
int curConnVmId; ///< 当前连接的VM
TCHAR clientId[MAX_PATH]; ///< 客户端验证签名 ID
TCHAR clientSecret[MAX_PATH]; ///< 客户端验证签名秘钥
} SDK_CONFIG, *PSDK_CONFIG;
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
PSDK_CONFIG GetGlobalCfgInfo();
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

119
NetTunnelSDK/include/misc.h Normal file
View File

@ -0,0 +1,119 @@
#pragma once
#include "common.h"
#include <windows.h>
#define CFG_WIREGUARD_SECTION TEXT("WireGuard")
#define CFG_WIREGUARD_PATH TEXT("WireGuardExe")
#define CFG_WGCFG_PATH TEXT("WgCfgPath")
#define CFG_WG_PATH TEXT("WgExe")
typedef struct {
TCHAR path[MAX_PATH];
} FILE_PATH, *PFILE_PATH;
typedef struct {
PFILE_PATH pFilePath;
unsigned int nItems;
} FILE_LIST, *PFILE_LIST;
/**
* @brief IPv4
*/
typedef struct {
unsigned int prefix; ///< 网络前缀
TCHAR hostip[MAX_IP_LEN]; ///< IP 地址
TCHAR ip[MAX_IP_LEN]; ///< IP 地址
TCHAR network[MAX_IP_LEN]; ///< 网络地址
TCHAR broadcast[MAX_IP_LEN]; ///< 网络广播地址
TCHAR netmask[MAX_IP_LEN]; ///< 网络子网掩码
TCHAR hosts[64]; ///< number of hosts in text
TCHAR hostmin[MAX_IP_LEN]; ///< 最小网络主机 IP
TCHAR hostmax[MAX_IP_LEN]; ///< 最大网络主机 IP
} IP_INFO, *PIP_INFO;
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
void RemoveTailLineBreak(TCHAR *pInputStr, int strSize);
int RunCommand(TCHAR *pszCmd, TCHAR *pszResultBuffer, int dwResultBufferSize, unsigned long *pRetCode);
/**
* @brief IPv4 CIDR
* @param[in] pNetMask IPv4
* @return IPv4 CIDR
*/
int __cdecl NetmaskToCIDR(const TCHAR *pNetMask);
/**
* @brief CIDR IPv4
* @param[in] cidr CIDR
* @return CIDR
*/
const TCHAR *CIDRToNetmask(const UINT8 cidr);
void ShowWindowsErrorMessage(const TCHAR *pMsgHead);
void StringReplaceAll(TCHAR *pOrigin, const TCHAR *pOldStr, const TCHAR *pNewStr);
void StringRemoveAll(TCHAR *pOrigin, const TCHAR *pString);
TCHAR *binToHexString(TCHAR *p, const unsigned char *cp, unsigned int count);
int GetWindowsServiceStatus(const TCHAR *pSvrName, PDWORD pStatus);
/**
* @brief Unicode TCHAR
* @param[in] pWStr
* @param[out] pOutStr TCHAR
* @param[in] maxOutLen pOutStr
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - ERR_SUCCESS
*/
int WideCharToTChar(const WCHAR *pWStr, TCHAR *pOutStr, int maxOutLen);
/**
* @brief TCHAR Unicode
* @param[in] pTStr TCHAR
* @param[out] pOutStr WCHAR
* @param[in] maxOutLen pOutStr
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - ERR_SUCCESS
*/
int TCharToWideChar(const TCHAR *pTStr, WCHAR *pOutStr, int maxOutLen);
int FindFile(const TCHAR *pPath, PFILE_LIST pFileList, const bool exitWhenMatchOne);
/**
* @brief IPv4
* @param[in] pIpStr IPv4
* @param[in] pNetmask IPv4子网掩码
* @param[out] pInfo
* @return 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetIpV4InfoFromNetmask(const TCHAR *pIpStr, const TCHAR *pNetmask, PIP_INFO pInfo);
/**
* @brief IPv4
* @param[in] pIpStr IPv4 '/' CIDR以及子网掩码 example: 192.168.1.32/24, 192.168.1.32/255.255.255.0
* @param[out] pInfo
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetIpV4InfoFromCIDR(const TCHAR *pIpStr, PIP_INFO pInfo);
int GetIpV4InfoFromHostname(int family, const char *host, PIP_INFO pInfo);
int InitializeWireGuardLibrary();
void UnInitializeWireGuardLibrary();
void StopUDPProxyServer();
int CreateUDPProxyServer();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,332 @@
#pragma once
#include "sccsdk.h"
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
/**
* @brief IP地址
* @param[in] pIpAddr IP地址
* @param[out] pIfIndex
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_ITEM_UNEXISTS
* - -ERR_UN_SUPPORT
* - ERR_SUCCESS
*/
int GetInterfaceIfIndexByIpAddr(const TCHAR *pIpAddr, ULONG *pIfIndex);
/**
* @brief GUDI
* @param[in] pGUID GUID
* @param[out] ifName
* @param[out] pConnStatus
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_CREATE_COMMOBJECT COM
* - -ERR_SYS_CALL COM
* - -ERR_ITEM_UNEXISTS GUID
* - ERR_SUCCESS
*/
int GetInterfaceNameByGUID(const TCHAR *pGUID, TCHAR ifName[MAX_NETCARD_NAME], int* pConnStatus);
/**
* @brief
* @param[in] pInterfaceName
* @param[out] pIfIndex Index
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_SYS_CALL
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetInterfaceIfIndexByName(const TCHAR *pInterfaceName, int *pIfIndex);
/**
* @brief GUID
* @param[in] ifIndex
* @param[out] pGuid GUID
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_MEMORY_STR GUID
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetInterfaceGUIDByIfIndex(const int ifIndex, GUID *pGuid);
/**
* @brief GUID
* @param[in] pInterfaceName
* @param[out] pGuid GUID
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_MEMORY_STR GUID
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetInterfaceGUIDByName(const TCHAR *pInterfaceName, GUID *pGuid);
int WaitNetAdapterConnected(const TCHAR *pInterfaceName, int timeOutOfMs);
/**
* @brief NetworkCategory Private
* @param[in] pInterfaceName
* @param[out] pIsPrivate
* - TRUE Private
* - FALSE Public
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_CREATE_COMMOBJECT COM
* - -ERR_SYS_CALL COM
* - -ERR_ITEM_UNEXISTS
* - -ERR_MEMORY_STR
* - ERR_SUCCESS
*/
int GetNetConnectionNetworkCategory(const TCHAR *pInterfaceName, bool *pIsPrivate);
/**
* @brief / Windows
* @param[in] ifIndex
* @param[in] isEnable / Windows
* - TRUE
* - FALSE
* @param[in] isSetPrivate
* -TRUE
* -FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_CREATE_COMMOBJECT COM
* - -ERR_SYS_CALL COM
* - -ERR_ITEM_UNEXISTS GUID
* - -ERR_NET_UNCONNECT
* - ERR_SUCCESS
*/
int SetNetIntelnetConnectionSharing(int ifIndex, bool isEnable, bool isSetPrivate);
/**
* @brief
* @param[in] ifIndex
* @param[out] pIsEnable
* - TRUE
* - FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_CREATE_COMMOBJECT COM
* - -ERR_SYS_CALL COM
* - -ERR_ITEM_UNEXISTS GUID
* - -ERR_NET_UNCONNECT
* - -ERR_CALL_COMMOBJECT
* - ERR_SUCCESS
*/
int GetNetIntelnetConnectionSharing(int ifIndex, bool *pIsEnable);
/**
* @brief Private/Public
* @param[in] pInterfaceName pInterfaceName
* @param[in] isPrivate Category
* - TRUE Private
* - FALSE Public
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int SetNetConnectionNetworkCategory(const TCHAR *pInterfaceName, const bool isPrivate);
/**
* @brief
* @param[in] pIP IP
* @param[in] pMask
* @param[in] pGateway
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT IP地址转网络字节序网络地址失败
* - -ERR_NET_ADD_ROUTE
* - -ERR_NET_REMOVE_ROUTE
* - ERR_SUCCESS
*/
int AddRouteTable(const char *pIP, const char *pMask, const char *pGateway);
/**
* @brief Windows WireGuard NAT
* @param[in] pInterfaceName
* @param[in] pCidrIpaddr CIDR
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int SetNATRule(const TCHAR *pInterfaceName, const TCHAR *pCidrIpaddr);
/**
* @brief Windows WireGuard NAT
* @param pInterfaceName
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int RemoveNATRule(const TCHAR *pInterfaceName);
#if 0
/**
* @brief IP地址
* @param[in] pInterfaceName
* @param[in] pIpaddr IP
* @param[in] pNetmask
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int SetInterfaceIpAddress(const TCHAR *pInterfaceName, const TCHAR *pIpaddr, const TCHAR *pNetmask);
/**
* @brief Windows Hyper-V NAT转发功能
* @param[out] pEnabled Hyper-V , TRUE , FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int GetWindowsHyperVStatus(int *pEnabled);
/**
* @brief / Windows Hyper-V
* @param[in] enabled TRUE , FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int EnableWindowsHyperV(bool enabled);
/**
* @brief Private/Public
* @param[in] pInterfaceName
* @param[in] isPrivate
* - TRUE Private
* - FALSE Public
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int SetInterfacePrivate(const TCHAR *pInterfaceName, bool isPrivate);
/**
* @brief NetworkCategory Private
* @param[in] pInterfaceName
* @param[out] pIsPrivateMode
* - TRUE Private
* - FALSE Public
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_ITEM_UNEXISTS
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int IsInterfacePrivate(const TCHAR *pInterfaceName, bool *pIsPrivateMode);
/**
* @brief
* @param[in] pInterfaceName
* @param[out] pIndex
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int GetInterfaceIndexByName(const TCHAR *pInterfaceName, int *pIndex);
/**
* @brief
* @param[in] pInterfaceName
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int RemoveInterfaceIpAddress(const TCHAR *pInterfaceName);
/**
* @brief IP地址
* @param[in] pInterfaceName
* @param[in] pCidrIpaddr CIDR类型IP地址
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int SetInterfaceIpAddressFromCIDR(const TCHAR *pInterfaceName, const TCHAR *pCidrIpaddr);
/**
* @brief IP地址
* @param[in] pInterfaceName
* @param[in] pIpaddr IP
* @param[in] pNetmask
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_MEMORY_STR
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int SetInterfaceIpAddress(const TCHAR *pInterfaceName, const TCHAR *pIpaddr, const TCHAR *pNetmask);
/**
* @brief NAT功能是否开启
* @param[in] pInterfaceName
* @param[out] pIsEnabled NAT当前是否开启
* - TRUE NAT
* - FALSE NAT
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_ITEM_UNEXISTS
* - -ERR_CALL_SHELL
* - -ERR_PROCESS_RETURN
* - ERR_SUCCESS
*/
int IsNetConnectionSharingEnabled(const TCHAR *pInterfaceName, bool *pIsEnabled);
/**
* @brief WireGuard Windows PowerShell
* @return
* - TRUE
* - FALSE
*/
bool IsCustomNatPSCmdInstalled();
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,10 @@
//
// Created by HuangXin on 2023/8/22.
//
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
#define CPPHTTPLIB_OPENSSL_SUPPORT
// Windows 头文件
#include <windows.h>

View File

@ -0,0 +1,290 @@
#pragma once
#include "ProtocolBase.h"
#include "common.h"
#if !USER_REAL_PLATFORM
class PlatformReqServerCfgParms {
public:
std::string vmIp;
AIGC_JSON_HELPER(vmIp)
};
class PlatformReqClientCfgParms {
public:
std::string userName;
std::string token;
AIGC_JSON_HELPER(userName)
};
class PlatformRspUserSvrCfgParams {
public:
PlatformRspUserSvrCfgParams() {
this->svrHost = TEXT("");
this->svrPort = 0;
this->svrPriKey = TEXT("");
}
int svrPort;
std::string svrPriKey;
std::string svrHost;
AIGC_JSON_HELPER(svrPort, svrPriKey, svrHost)
};
class VitrualMathineInfo {
public:
VitrualMathineInfo() {
this->vmId = 0;
this->scgPort = 0;
this->vmName = TEXT("");
this->scgIp = TEXT("");
this->vmNetwork = TEXT("");
this->svrPubKey = TEXT("");
#if USED_PORTMAP_TUNNEL
this->portMapIp = TEXT("");
this->portMapPort = 0;
#endif
}
int vmId;
std::string vmName;
std::string svrPubKey;
std::string vmNetwork;
std::string scgIp;
int scgPort;
#if USED_PORTMAP_TUNNEL
std::string portMapIp;
int portMapPort;
AIGC_JSON_HELPER(vmId, vmName, svrPubKey, vmNetwork, scgIp, scgPort, portMapIp, portMapPort)
#else
AIGC_JSON_HELPER(vmId, vmName, svrPubKey, vmNetwork, scgIp, scgPort)
#endif
};
class PlatformRspUserClientCfgParams {
public:
PlatformRspUserClientCfgParams() {
this->scgTunnelAppId = WG_TUNNEL_SCG_ID;
this->scgCtrlAppId = WG_CTRL_SCG_ID;
this->cliHost = TEXT("");
}
int scgCtrlAppId;
int scgTunnelAppId;
std::string cliPriKey;
std::string cliPubKey;
std::string cliHost;
std::list<VitrualMathineInfo> vmInfoList;
AIGC_JSON_HELPER(scgCtrlAppId, scgTunnelAppId, cliPriKey, cliPubKey, vmInfoList, cliHost)
};
class PlatformRspServerCfgParams {
public:
std::string code;
std::string message;
PlatformRspUserSvrCfgParams data;
AIGC_JSON_HELPER(code, data)
};
class PlatformRspClientCfgParams {
public:
std::string code;
std::string message;
PlatformRspUserClientCfgParams data;
AIGC_JSON_HELPER(code, data)
};
#endif
class ReqClientCfgParams {
public:
std::string identifier;
AIGC_JSON_HELPER(identifier)
};
class ReqHeartParams {
public:
std::string message;
AIGC_JSON_HELPER(message)
AIGC_JSON_HELPER_DEFAULT(message = TEXT("PING"))
};
class RspHeartParams : public ResponseStatus {
public:
std::string message;
AIGC_JSON_HELPER(message)
AIGC_JSON_HELPER_BASE((ResponseStatus *)this)
AIGC_JSON_HELPER_DEFAULT(message = TEXT("PONG"))
};
class ReqGetUserCfgParams {
public:
std::string user;
std::string token;
AIGC_JSON_HELPER(user, token)
};
class RspUserSevrCfgParams {
public:
RspUserSevrCfgParams() {
this->svrAddress = TEXT("");
this->svrListenPort = 0;
this->svrPrivateKey = TEXT("");
}
int svrListenPort;
std::string svrPrivateKey;
std::string svrAddress;
AIGC_JSON_HELPER(svrListenPort, svrPrivateKey, svrAddress)
};
class ReqStartTunnelParams {
public:
bool isStart;
AIGC_JSON_HELPER(isStart)
};
class ReqUserSetCliCfgParams {
public:
std::string cliPublicKey;
std::string cliNetwork;
std::string cliTunnelAddr;
AIGC_JSON_HELPER(cliPublicKey, cliNetwork, cliTunnelAddr)
};
class RspUserSetCliCfgParams : public ResponseStatus {
public:
std::string svrNetwork;
AIGC_JSON_HELPER(svrNetwork)
AIGC_JSON_HELPER_BASE((ResponseStatus *)this)
};
class VitrualMathineCfg {
public:
VitrualMathineCfg() {
this->vmId = 0;
this->vmName = TEXT("");
this->scgGateway = TEXT("");
this->vmNetwork = TEXT("");
this->svrPublicKey = TEXT("");
#if USED_PORTMAP_TUNNEL
this->portMapIp = TEXT("");
this->portMapPort = 0;
#endif
}
int vmId;
std::string vmName;
std::string svrPublicKey;
std::string vmNetwork;
std::string scgGateway;
#if USED_PORTMAP_TUNNEL
std::string portMapIp;
int portMapPort;
AIGC_JSON_HELPER(vmId, vmName, svrPublicKey, vmNetwork, scgGateway, portMapIp, portMapPort)
#else
AIGC_JSON_HELPER(vmId, vmName, svrPublicKey, vmNetwork, scgGateway)
#endif
};
class RspUsrCliConfigParams {
public:
int scgCtrlAppId;
int scgTunnelAppId;
std::string cliPrivateKey;
std::string cliPublicKey;
std::string cliAddress;
std::list<VitrualMathineCfg> vmConfig;
AIGC_JSON_HELPER(scgCtrlAppId, scgTunnelAppId, cliPrivateKey, cliPublicKey, cliAddress, vmConfig)
};
#if USER_REAL_PLATFORM
#define GET_CLIENTCFG_PATH TEXT("/tunnel/getuserconfig")
#define GET_SERVERCFG_PATH TEXT("/tunnel/getserverconfig")
#else
#define GET_CLIENTCFG_PATH TEXT("/sc/open-portal/openapi/scc/cliTunnelCfg")
#define GET_SERVERCFG_PATH TEXT("/sc/open-portal/openapi/scc/svrTunnelCfg")
#endif
#define SET_CLIENTCFG_PATH TEXT("/tunnel/setconfig")
#define SET_CLIENTSTART_TUNNEL TEXT("/tunnel/start")
#define SET_CLIENTHEART_PATH TEXT("/tunnel/heart")
int InitControlServer(const TCHAR *pUserSvrUrl);
/**
* @brief RESTful POST
* @param[in] pUrlPath URL
* @param[in] pReq
* @param[in] pRsp
* @param[in] platformServer 访访
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_SYSTEM_UNINITIALIZE URL未初始化
* - -ERR_JSON_CREATE JSON
* - -ERR_HTTP_POST_DATA POST
* - -ERR_HTTP_SERVER_RSP 200
* - -ERR_READ_FILE
* - -ERR_JSON_DECODE JSON
* - ERR_SUCCESS
*/
template<class T1, class T2>
int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<T1> *pReq,
ProtocolResponse<T2> *pRsp,
bool platformServer);
extern template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqGetUserCfgParams> *pReq,
ProtocolResponse<RspUserSevrCfgParams> *pRsp,
bool platformServer);
extern template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqGetUserCfgParams> *pReq,
ProtocolResponse<RspUsrCliConfigParams> *pRsp,
bool platformServer);
extern template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqUserSetCliCfgParams> *pReq,
ProtocolResponse<RspUserSetCliCfgParams> *pRsp,
bool platformServer);
extern template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqStartTunnelParams> *pReq,
ProtocolResponse<ResponseStatus> *pRsp,
bool platformServer);
extern template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqHeartParams> *pReq,
ProtocolResponse<RspHeartParams> *pRsp,
bool platformServer);
#if !USER_REAL_PLATFORM
template<class T1, class T2> int PlatformProtolPostMessage(const TCHAR *pUrlPath, T1 *pReq, T2 *pRsp);
extern template int PlatformProtolPostMessage(const TCHAR *pUrlPath,
PlatformReqServerCfgParms *pReq,
PlatformRspServerCfgParams *pRsp);
extern template int PlatformProtolPostMessage(const TCHAR *pUrlPath,
PlatformReqClientCfgParms *pReq,
PlatformRspClientCfgParams *pRsp);
#if 0
template<class T1> int PlatformProtolGetMessage(const TCHAR *pUrlPath, T1 *pRsp);
extern template int PlatformProtolGetMessage(const TCHAR *pUrlPath,
PlatformRspUserClientCfgParams *pRsp);
#endif
#endif

View File

@ -0,0 +1,303 @@
#pragma once
#include <Windows.h>
#include "common.h"
#include "usrerr.h"
#ifdef NETTUNNELSDK_EXPORTS
#define SCCSDK_API __declspec(dllexport)
#else
#define SCCSDK_API __declspec(dllimport)
#endif
typedef void (*PTUNNEL_HEART_ROUTINE)(const TCHAR *pMessage, unsigned int timeStampOfSeconds);
typedef PTUNNEL_HEART_ROUTINE LPTUNNEL_HEART_ROUTINE;
/**
*
* @brief
*/
typedef struct {
int InterfaceIndex; ///< 网卡索引
NET_CONNECT_STATUS netConnStatus; ///< 网卡状态 @see NET_CONNECT_STATUS
TCHAR NetCardUUID[260]; ///< 网卡名称, Windows标识为 UUID
TCHAR NetCardName[MAX_NETCARD_NAME]; ///< 网卡名称
TCHAR NetCardDescription[132]; ///< 网卡描述
TCHAR NetCardIpaddr[MAX_IP_LEN]; ///< 网卡 IP 地址
TCHAR NetCardNetmask[MAX_IP_LEN]; ///< 网卡子网掩码
TCHAR NetCardGateway[MAX_IP_LEN]; ///< 网卡网关
TCHAR NetCardMacAddr[20]; ///< 网卡 MAC 地址
} NIC_CONTENT, *PNIC_CONTENT;
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
/**
* @brief SDK
* @param[in] pWorkDir
* @param[in] pSvrUrl URL example: http://localhost:2313, https://localhost:2313
* @param[in] pLogFile /
* @param[in] level
* @param[in] isWorkServer SDK
* - TRUE
* - FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_ITEM_EXISTS WireGuard
* - -ERR_SYS_CALL
* - -ERR_CREATE_FILE
* - -ERR_ITEM_UNEXISTS WireGuard
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl TunnelSDKInitEnv(const TCHAR *pWorkDir,
const TCHAR *pSvrUrl,
const TCHAR *pLogFile,
LOG_LEVEL level,
bool isWorkServer);
/**
* @brief SDK
*/
SCCSDK_API void __cdecl TunnelSDKUnInit();
/**
* @brief / SDK
* @param enLog
* - TRUE
* - FALSE
*/
SCCSDK_API void __cdecl TunnelLogEnable(bool enLog);
/**
* @brief WireGuard
* @param pTunnelName
* @param pIsRunning pIsRunning WireGuard
* - TRUE
* - FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_OPEN_SCM
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl GetWireGuardServiceStatus(const TCHAR *pTunnelName, bool *pIsRunning);
/**
* @brief /
* @param[out] pIsWorkServer
* - TRUE
* - FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl GetWireGuardWorkMode(bool *pIsWorkServer);
/**
* @brief WireGuard
* @param[in] pIfName WireGuard
* @param[out] pIsRunning WireGuard
* - TRUE
* - FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl IsWireGuardServerRunning(const TCHAR *pIfName, bool *pIsRunning);
/**
* @brief SCG
* @param isEnable TRUE: SCG , FALSE: SCG
* @param pSCGIpAddr SCG IP
* @param scgPort SCG
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl EnableSCGProxy(bool isEnable, const TCHAR *pSCGIpAddr, int scgPort);
/**
* @brief SCG
* @return TRUE: SCG , FALSE: SCG
*/
SCCSDK_API bool __cdecl UsedSCGProxy();
/**
* @brief
* @return @see NET_SHARE_MODE
*/
SCCSDK_API NET_SHARE_MODE __cdecl GetCurrentNetShareMode();
/**
* @brief
* @param shareMode @see NET_SHARE_MODE
*/
SCCSDK_API void __cdecl SetCurrentNetShareMode(NET_SHARE_MODE shareMode);
/**
* @brief
* @param[out] pInfo @see NIC_CONTENT
* @param[out] pItemCounts 32
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl GetAllNICInfo(PNIC_CONTENT *pInfo, int *pItemCounts);
/**
* @brief Internet
* @param[out] pIfIndex
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS Internet
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl GetInternetIfIndex(int *pIfIndex);
/**
* @brief Internet
* @param[in] ifIndex
* @param[in] pRet
* - TRUE Internet
* - FALSE Internet
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_GET_IPFOWARDTBL
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl IsInternetConnectAdapter(int ifIndex, bool *pRet);
/**
* @brief
* @param pClientId ID
* @param pClientSecret
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl EnableVerifySignature(const TCHAR *pClientId, const TCHAR *pClientSecret);
/**
* @brief
*/
SCCSDK_API void __cdecl DisableVerifySignature();
/**
* @brief
* @param pSvr
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_CREATE_THREAD 线
* - -ERR_SOCKET_BIND_PORT
* - -ERR_ITEM_EXISTS 线
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl CreateControlService(PUSER_SERVER_CONFIG pSvr);
/**
* @brief
* @param[in] pUserName
* @param[in] pToken 访
* @param[out] pSvrCfg
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CREATE_FILE
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl GetUserServerConfigure(const TCHAR *pUserName,
const TCHAR *pToken,
PUSER_SERVER_CONFIG *pSvrCfg);
/**
* @brief
* @param[in] pUserName
* @param[in] pToken 访
* @param[out] pCliCfg
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MEMORY_STR
* - -ERR_CREATE_FILE
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl GetUserClientConfigure(const TCHAR *pUserName,
const TCHAR *pToken,
PUSER_CLIENT_CONFIG *pCliCfg);
/**
* @brief
* @return 0: 0 @see USER_ERRNO
* - -ERROR_TIMEOUT
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl StopControlService();
/**
* @brief
* @param[in] vmId ID编号
* @param[in] pCliNetwork
* @return 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_SYSTEM_UNINITIALIZE
* - -ERR_MALLOC_MEMORY
* - -ERR_OPEN_FILE
* - -ERR_MEMORY_STR
* - -ERR_UN_SUPPORT
* - -ERR_JSON_CREATE JSON
* - -ERR_HTTP_POST_DATA POST
* - -ERR_HTTP_SERVER_RSP 200
* - -ERR_READ_FILE
* - -ERR_JSON_DECODE JSON
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl RemoteCtrlSvrCfgUserTunnel(int vmId, const TCHAR *pCliNetwork);
/**
* @brief / WireGuard
* @param[in] isStart / TRUE , FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_SYSTEM_UNINITIALIZE URL
* - -ERR_CREATE_FILE
* - -ERR_HTTP_POST_DATA POST
* - -ERR_HTTP_SERVER_RSP HTTP
* - -ERR_READ_FILE
* - -ERR_JSON_DECODE JSON
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl RemoteWireGuardControl(bool isStart);
/**
* @brief / WireGuard
* @param[in] isStart / TRUE , FALSE
* @param[in] setPrivateMode (Private)
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_NET_CATEGORY_MODE
* - -ERR_UN_SUPPORT
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl LocalWireGuardControl(bool isStart, bool setPrivateMode);
/**
* @brief /
* @param isStart / TRUE , FALSE
* @param lpHeartCbAddress @see PTUNNEL_HEART_ROUTINE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_CREATE_TIMER
* - -ERR_DELETE_TIMER
* - ERR_SUCCESS
*/
SCCSDK_API int __cdecl RemoteHeartControl(bool isStart, LPTUNNEL_HEART_ROUTINE lpHeartCbAddress);
/**
* @brief
* @param err
* @return , "UNKNOWN":
*/
SCCSDK_API const CHAR* __cdecl GetSDKErrorMessage(USER_ERRNO err);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,200 @@
#pragma once
#include "sccsdk.h"
typedef enum {
CHK_SYSTEM_INIT,
CHK_WIREGUARD_CONFIG,
CHK_WIREGUARD_SERVICE,
CHK_WG_INTERFACE_PRIVATE,
CHK_MAX
} CHECK_FUNCTION;
typedef struct {
CHECK_FUNCTION chk;
bool result;
TCHAR errMsg[MAX_PATH];
} CHK_RESULT, *PCHK_RESULT;
/**
* @brief WireGuard
*/
typedef struct {
TCHAR Name[64]; ///< WireGuard 网卡名称
TCHAR Address[32]; ///< WireGuard 本地网络IP地址
TCHAR PrivateKey[64]; ///< WireGuard 本机私钥
int ListenPort; ///< WireGuard 服务端监听端口
// 根据系统设计,不支持多个客户端同时连接
TCHAR CliPubKey[64]; ///< WireGuard 客户端公钥
TCHAR AllowNet[256]; ///< WireGuard 允许对端访问本地网络的配置
} WGSERVER_CONFIG, *PWGSERVER_CONFIG;
/**
* @brief WireGuard
*/
typedef struct {
TCHAR Name[64]; ///< WireGuard 网卡名称
TCHAR PrivateKey[64]; ///< WireGuard 本机私钥
TCHAR Address[32]; ///< WireGuard 本地网络IP地址
// Peer Server
TCHAR SvrPubKey[64]; ///< WireGuard 服务端公钥
TCHAR AllowNet[256]; ///< WireGuard 允许对端访问本地网络的配置
TCHAR ServerURL[256]; ///< WireGuard 服务端IP地址和端口
} WGCLIENT_CONFIG, *PWGCLIENT_CONFIG;
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
/**
* @brief CRYPTO_NONE
* @param[in] type @see PROTO_CRYPTO_TYPE
* @param[in] pProKey CRYPTO_NONE CRYPTO_BASE64
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - ERR_SUCCESS
*/
int SetProtocolEncryptType(const PROTO_CRYPTO_TYPE type, const TCHAR *pProKey);
/**
* @brief WireGuard
* @param[in] pWgConfig @see WGSERVER_CONFIG
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_OPEN_FILE
* - -ERR_MEMORY_STR
* - ERR_SUCCESS
*/
int WireGuardCreateServerConfig(const PWGSERVER_CONFIG pWgConfig);
/**
* @brief WireGuard
* @param[in] pWgConfig @see WGCLIENT_CONFIG
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_OPEN_FILE
* - -ERR_MEMORY_STR
* - ERR_SUCCESS
*/
int WireGuardCreateClientConfig(const PWGCLIENT_CONFIG pWgConfig);
/**
* @brief WireGuard
* @param pInterfaceName
* @param pWGConfigFilePath
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_OPEN_SCM
* - -ERR_OPEN_SERVICE
* - -ERR_CREATE_SERVICE
* - -ERR_CONFIG_SERVICE
* - -ERR_START_SERVICE
* - ERR_SUCCESS
*/
int CreateWireGuardService(const TCHAR *pInterfaceName, const TCHAR *pWGConfigFilePath);
int GetWireGuradTunnelInfo(const TCHAR *pTunnelName);
/**
* @brief WireGuard
* @param pTunnelName
* @param bIsWaitStop TRUE: , FALSE:
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_OPEN_SCM
* - -ERR_OPEN_SERVICE
* - -ERR_STOP_SERVICE
* - -ERR_DELETE_SERVICE
* - ERR_SUCCESS
*/
int RemoveGuardService(const TCHAR *pTunnelName, bool bIsWaitStop);
/**
* @brief / WireGuard
* @param[in] bInstall TRUE , FALSE
* @return 0: 0 @see USER_ERRNO
*/
int WireGuardInstallDefaultServerService(bool bInstall);
/**
* @brief WireGuard
* @param[in] pTunnelCfgPath
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_CALL_SHELL WireGuard
* - ERR_SUCCESS
*/
int WireGuardInstallServerService(const TCHAR *pTunnelCfgPath);
/**
* @brief WireGuard
* @param[in] pTunnelName
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_CALL_SHELL WireGuard
* - ERR_SUCCESS
*/
int WireGuardUnInstallServerService(const TCHAR *pTunnelName);
/**
* @brief WireGuard
* @param[out] pIsInstalled WireGuard
* - TRUE
* - FALSE
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_OPEN_SCM,
* - -ERR_OPEN_SERVICE,
* - -ERR_GET_SERVICESSTATUS,
* - ERR_SUCCESS
*/
int IsWireGuardServerInstalled(bool *pIsInstalled);
/**
* @brief Hash
* @param[in] type Hash @see HASH_TYPE
* @param[in] pPath Hash
* @param[out] outHash
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_OPEN_FILE
* - -ERR_BCRYPT_OPEN
* - -ERR_BCRYPT_GETPROPERTY
* - -ERR_BCRYPT_CREATEHASH Hash
* - -ERR_BCRYPT_HASHDATA Hash
* - -ERR_BCRYPT_FINISHHASH Hash
* - ERR_SUCCESS
*/
int CalcFileHash(HASH_TYPE type, const TCHAR *pPath, TCHAR outHash[]);
/**
* @brief HMAC HASH
* @param[in] type Hash @see HASH_TYPE
* @param[in] pHashData Hash
* @param[in] inSize Hash ()
* @param[in] pKey HMAC Hash
* @param[in] keySize HMAC Hash ()
* @param[out] outHash
* @param[in] outBase64 BASE64
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - -ERR_OPEN_FILE
* - -ERR_BCRYPT_OPEN
* - -ERR_BCRYPT_GETPROPERTY
* - -ERR_BCRYPT_CREATEHASH Hash
* - -ERR_BCRYPT_HASHDATA Hash
* - -ERR_BCRYPT_FINISHHASH Hash
* - ERR_SUCCESS
*/
int CalcHmacHash(HASH_TYPE type, PUCHAR pHashData, int inSize, PUCHAR pKey, int keySize, TCHAR outHash[], bool outBase64);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,54 @@
#pragma once
#include "sccsdk.h"
#define HEART_PERIOD_MS (3000)
/**
*
* @brief
*/
typedef struct {
int isCurrent; ///< 网卡 MAC 地址
TCHAR CfgPath[260]; ///< 配置文件路径
} USER_CFGFILE, *PUSER_CFGFILE;
#ifdef __cplusplus // If used by C++ code,
extern "C" {
// we need to export the C interface
#endif
/**
* @brief
* @param pUserSvrUrl URL
*/
void ConnectServerControlService(const TCHAR *pUserSvrUrl);
/**
* @brief WireGuard
* @param[in] pCliPrivateKey
* @param[in] pSvrPublicKey
* @param[in] pSvrNetwork 访
* @param[in] pCliNetwork
* @param[in] pSvrTunnelAddr
* @param[in] pSvrEndPoint
* @return 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_SYSTEM_UNINITIALIZE
* - -ERR_MALLOC_MEMORY
* - -ERR_OPEN_FILE
* - -ERR_MEMORY_STR
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int SetTunnelConfigure(const TCHAR *pCliPrivateKey,
const TCHAR *pSvrPublicKey,
const TCHAR *pSvrNetwork,
const TCHAR *pCliNetwork,
const TCHAR *pSvrTunnelAddr,
const TCHAR *pSvrEndPoint);
int GetUserConfigFiles(const TCHAR *pUserName, PUSER_CFGFILE* pCfgFile, int *pItems);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,69 @@
#pragma once
/**
* @brief SDK
*/
enum USER_ERRNO {
ERR_SUCCESS = 0, ///< 成功
ERR_INPUT_PARAMS, ///< 输入参数错误
ERR_UN_SUPPORT, ///< 不支持的操作
ERR_CALL_SHELL, ///< 调用Shell命令失败
ERR_ITEM_EXISTS, ///< 该内容已经存在
ERR_ITEM_UNEXISTS, ///< 该内容不存在
ERR_SYS_INIT, ///< 系统中断
ERR_SYS_CALL, ///< 系统调用
ERR_LOAD_LIBRARY, ///< 加载系统库失败
ERR_MAP_LIBRARY, ///< 加载系统库接口失败
ERR_SYS_TIMEOUT, ///< 系统超时
ERR_SYSTEM_UNINITIALIZE, ///< 系统未初始化
ERR_CREATE_FILE, ///< 创建文件/目录失败
ERR_OPEN_FILE, ///< 打开文件失败
ERR_READ_FILE, ///< 读取文件失败
ERR_WRITE_FILE, ///< 写入文件失败
ERR_FILE_NOT_EXISTS, ///< 文件不存在
ERR_FILE_LOCKED, ///< 文件被锁定
ERR_GET_FILE_SIZE, ///< 获取文件大小失败
ERR_FIND_FILE, ///< 查找文件失败
ERR_COPY_FILE, ///< 复制文件失败
ERR_OPEN_SCM, ///< 打开服务管理器设备失败
ERR_OPEN_SERVICE, ///< 打开服务失败
ERR_CREATE_SERVICE, ///< 创建服务失败
ERR_START_SERVICE, ///< 启动服务失败
ERR_STOP_SERVICE, ///< 停止服务失败
ERR_DELETE_SERVICE, ///< 删除服务失败
ERR_CONFIG_SERVICE, ///< 修改服务配置失败
ERR_GET_SERVICESSTATUS, ///< 获取服务状态失败
ERR_MALLOC_MEMORY, ///< 分配内存失败
ERR_MMAP_MEMORY, ///< 共享内存失败
ERR_MEMORY_STR, ///< 字符串操作失败
ERR_CREATE_PROCESS, ///< 创建进程失败
ERR_PROCESS_RETURN, ///< 进程调用返回失败
ERR_CREATE_THREAD, ///< 创建线程失败
ERR_CREATE_TIMER, ///< 创建定时器失败
ERR_DELETE_TIMER, ///< 销毁定时器失败
ERR_SOCKET_CREATE, ///< 创建 SOCKET 失败
ERR_SOCKET_BIND, ///< 绑定 SOCKET 端口失败
ERR_SOCKET_CONNECT, ///< 连接 TCP SOCKET 服务器失败
ERR_SOCKET_LISTEN, ///< TCP SOCKET 服务监听失败
ERR_SOCKET_BIND_PORT, ///< 绑定端口失败
ERR_SOCKET_SET_OPT, ///< 设置 SOCKET 参数失败
ERR_SOCKET_GET_OPT, ///< 读取 SOCKET 参数失败
ERR_BCRYPT_OPEN = 100, ///< 创建加密算法失败
ERR_BCRYPT_GETPROPERTY, ///< 获取加密算法属性失败
ERR_BCRYPT_CREATEHASH, ///< 创建 Hash 算法失败
ERR_BCRYPT_HASHDATA, ///< 计算 Hash 数据失败
ERR_BCRYPT_FINISHHASH, ///< 计算 Hash 结果失败
ERR_NET_UNCONNECT = 200, ///< 网络未连接
ERR_NET_CATEGORY_MODE, ///< 网络工作模式
ERR_NET_INTELNEL_ICS, ///< 共享 Intelnet 网络 ICS 共享失败
ERR_NET_WIREGUARD_ICS, ///< 共享 WireGuard 网络 ICS 共享失败
ERR_GET_IPFOWARDTBL = 300, ///< 获取系统 IP 转发表失败
ERR_CREATE_COMMOBJECT = 400, ///< 创建 COM 对象失败
ERR_CALL_COMMOBJECT, ///< 调用 COM 对象失败
ERR_JSON_CREATE = 500, ///< 创建 JSON 对象失败
ERR_JSON_DECODE, ///< 从 JSON 反序列化对象失败
ERR_HTTP_SERVER_RSP = 600, ///< HTTP 服务端返回错误
ERR_HTTP_POST_DATA, ///< 发送 POST 请求失败
ERR_NET_ADD_ROUTE, ///< 添加路由失败
ERR_NET_REMOVE_ROUTE, ///< 删除路由失败
};

View File

@ -0,0 +1,538 @@
#include "pch.h"
#include <strsafe.h>
#include <winsock2.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
#include <spdlog/spdlog.h>
#include "usrerr.h"
#include "misc.h"
#include "tunnel.h"
static const TCHAR *p2_table(unsigned pow) {
static const TCHAR *pow2[] = {
TEXT("1"),
TEXT("2"),
TEXT("4"),
TEXT("8"),
TEXT("16"),
TEXT("32"),
TEXT("64"),
TEXT("128"),
TEXT("256"),
TEXT("512"),
TEXT("1024"),
TEXT("2048"),
TEXT("4096"),
TEXT("8192"),
TEXT("16384"),
TEXT("32768"),
TEXT("65536"),
TEXT("131072"),
TEXT("262144"),
TEXT("524288"),
TEXT("1048576"),
TEXT("2097152"),
TEXT("4194304"),
TEXT("8388608"),
TEXT("16777216"),
TEXT("33554432"),
TEXT("67108864"),
TEXT("134217728"),
TEXT("268435456"),
TEXT("536870912"),
TEXT("1073741824"),
TEXT("2147483648"),
TEXT("4294967296"),
TEXT("8589934592"),
TEXT("17179869184"),
TEXT("34359738368"),
TEXT("68719476736"),
TEXT("137438953472"),
TEXT("274877906944"),
TEXT("549755813888"),
TEXT("1099511627776"),
TEXT("2199023255552"),
TEXT("4398046511104"),
TEXT("8796093022208"),
TEXT("17592186044416"),
TEXT("35184372088832"),
TEXT("70368744177664"),
TEXT("140737488355328"),
TEXT("281474976710656"),
TEXT("562949953421312"),
TEXT("1125899906842624"),
TEXT("2251799813685248"),
TEXT("4503599627370496"),
TEXT("9007199254740992"),
TEXT("18014398509481984"),
TEXT("36028797018963968"),
TEXT("72057594037927936"),
TEXT("144115188075855872"),
TEXT("288230376151711744"),
TEXT("576460752303423488"),
TEXT("1152921504606846976"),
TEXT("2305843009213693952"),
TEXT("4611686018427387904"),
TEXT("9223372036854775808"),
TEXT("18446744073709551616"),
TEXT("36893488147419103232"),
TEXT("73786976294838206464"),
TEXT("147573952589676412928"),
TEXT("295147905179352825856"),
TEXT("590295810358705651712"),
TEXT("1180591620717411303424"),
TEXT("2361183241434822606848"),
TEXT("4722366482869645213696"),
TEXT("9444732965739290427392"),
TEXT("18889465931478580854784"),
TEXT("37778931862957161709568"),
TEXT("75557863725914323419136"),
TEXT("151115727451828646838272"),
TEXT("302231454903657293676544"),
TEXT("604462909807314587353088"),
TEXT("1208925819614629174706176"),
TEXT("2417851639229258349412352"),
TEXT("4835703278458516698824704"),
TEXT("9671406556917033397649408"),
TEXT("19342813113834066795298816"),
TEXT("38685626227668133590597632"),
TEXT("77371252455336267181195264"),
TEXT("154742504910672534362390528"),
TEXT("309485009821345068724781056"),
TEXT("618970019642690137449562112"),
TEXT("1237940039285380274899124224"),
TEXT("2475880078570760549798248448"),
TEXT("4951760157141521099596496896"),
TEXT("9903520314283042199192993792"),
TEXT("19807040628566084398385987584"),
TEXT("39614081257132168796771975168"),
TEXT("79228162514264337593543950336"),
TEXT("158456325028528675187087900672"),
TEXT("316912650057057350374175801344"),
TEXT("633825300114114700748351602688"),
TEXT("1267650600228229401496703205376"),
TEXT("2535301200456458802993406410752"),
TEXT("5070602400912917605986812821504"),
TEXT("10141204801825835211973625643008"),
TEXT("20282409603651670423947251286016"),
TEXT("40564819207303340847894502572032"),
TEXT("81129638414606681695789005144064"),
TEXT("162259276829213363391578010288128"),
TEXT("324518553658426726783156020576256"),
TEXT("649037107316853453566312041152512"),
TEXT("1298074214633706907132624082305024"),
TEXT("2596148429267413814265248164610048"),
TEXT("5192296858534827628530496329220096"),
TEXT("10384593717069655257060992658440192"),
TEXT("20769187434139310514121985316880384"),
TEXT("41538374868278621028243970633760768"),
TEXT("83076749736557242056487941267521536"),
TEXT("166153499473114484112975882535043072"),
TEXT("332306998946228968225951765070086144"),
TEXT("664613997892457936451903530140172288"),
TEXT("1329227995784915872903807060280344576"),
TEXT("2658455991569831745807614120560689152"),
TEXT("5316911983139663491615228241121378304"),
TEXT("10633823966279326983230456482242756608"),
TEXT("21267647932558653966460912964485513216"),
TEXT("42535295865117307932921825928971026432"),
TEXT("85070591730234615865843651857942052864"),
TEXT("170141183460469231731687303715884105728"),
};
if (pow <= 127) {
return pow2[pow];
}
return TEXT("");
}
static int vasprintf(TCHAR **strp, const TCHAR *fmt, va_list ap) {
// _vscprintf tells you how big the buffer needs to be
const int len = _vscprintf(fmt, ap);
if (len == -1) {
return -1;
}
const size_t size = static_cast<size_t>(len) + 1;
const auto str = static_cast<TCHAR *>(malloc(size));
if (!str) {
return -1;
}
// _vsprintf_s is the "secure" version of vsprintf
const int r = vsprintf_s(str, len + 1, fmt, ap);
if (r == -1) {
free(str);
return -1;
}
*strp = str;
return r;
}
static int asprintf(TCHAR **strp, const TCHAR *fmt, ...) {
va_list ap;
va_start(ap, fmt);
const int r = vasprintf(strp, fmt, ap);
va_end(ap);
return r;
}
static int bit_count(unsigned int i) {
int c = 0;
unsigned int seen_one = 0;
while (i > 0) {
if (i & 1) {
seen_one = 1;
c++;
} else {
if (seen_one) {
return -1;
}
}
i >>= 1;
}
return c;
}
/**
* @brief creates a netmask from a specified number of bits
* This function converts a prefix length to a netmask. As CIDR (classless
* internet domain internet domain routing) has taken off, more an more IP
* addresses are being specified in the format address/prefix
* (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
* need to see what netmask corresponds to the prefix part of the address, this
* is the function. See also @ref mask2prefix.
* @param prefix prefix is the number of bits to create a mask for.
* @return a network mask, in network byte order.
*/
unsigned int prefix2mask(int prefix) {
if (prefix) {
return htonl(~((1 << (32 - prefix)) - 1));
} else {
return htonl(0);
}
}
/**
* @brief calculates the number of bits masked off by a netmask.
* This function calculates the significant bits in an IP address as specified by
* a netmask. See also @ref prefix2mask.
* @param mask is the netmask, specified as an struct in_addr in network byte order.
* @return the number of significant bits.
*/
int mask2prefix(IN_ADDR mask) {
return bit_count(ntohl(mask.s_addr));
}
static int ipv4_mask_to_int(const char *prefix) {
int ret;
IN_ADDR in;
ret = inet_pton(AF_INET, prefix, &in);
if (ret == 0) {
return -1;
}
return mask2prefix(in);
}
/**
* @brief calculate broadcast address given an IP address and a prefix length.
* @param addr an IP address in network byte order.
* @param prefix a prefix length.
* @return the calculated broadcast address for the network, in network byte order.
*/
static IN_ADDR calc_broadcast(IN_ADDR addr, int prefix) {
IN_ADDR mask;
IN_ADDR broadcast;
mask.s_addr = prefix2mask(prefix);
memset(&broadcast, 0, sizeof(broadcast));
broadcast.s_addr = (addr.s_addr & mask.s_addr) | ~mask.s_addr;
return broadcast;
}
/**
* @brief calculates the network address for a specified address and prefix.
* @param addr an IP address, in network byte order
* @param prefix the network prefix
* @return the base address of the network that addr is associated with, in
* network byte order.
*/
static IN_ADDR calc_network(IN_ADDR addr, int prefix) {
IN_ADDR mask;
IN_ADDR network;
mask.s_addr = prefix2mask(prefix);
memset(&network, 0, sizeof(network));
network.s_addr = addr.s_addr & mask.s_addr;
return network;
}
static TCHAR *ipv4_prefix_to_hosts(TCHAR *hosts, unsigned hosts_size, unsigned prefix) {
if (prefix >= 31) {
StringCbPrintf(hosts, hosts_size, TEXT("%s"), p2_table(32 - prefix));
} else {
unsigned int tmp;
tmp = (1 << (32 - prefix)) - 2;
StringCbPrintf(hosts, hosts_size, TEXT("%u"), tmp);
}
return hosts;
}
static int str_to_prefix(int *ipv6, const char *prefixStr, unsigned fix) {
int prefix;
if (!(*ipv6) && strchr(prefixStr, '.')) { /* prefix is 255.x.x.x */
prefix = ipv4_mask_to_int(prefixStr);
} else {
prefix = strtol(prefixStr, nullptr, 10);
}
if (fix && (prefix > 32 && !(*ipv6))) {
*ipv6 = 1;
}
if (prefix < 0 || (((*ipv6) && prefix > 128) || (!(*ipv6) && prefix > 32))) {
return -1;
}
return prefix;
}
static int GetIpV4Info(const TCHAR *pIpStr, int prefix, PIP_INFO pInfo, unsigned int flags) {
IN_ADDR ip, netmask, network, broadcast, minhost, maxhost;
TCHAR namebuf[INET_ADDRSTRLEN + 1];
TCHAR *ipStr = _strdup(pIpStr);
memset(pInfo, 0, sizeof(*pInfo));
if (inet_pton(AF_INET, ipStr, &ip) <= 0) {
SPDLOG_ERROR(TEXT("ipcalc: bad IPv4 address: {0}"), ipStr);
free(ipStr);
return -ERR_UN_SUPPORT;
}
/* Handle CIDR entries such as 172/8 */
if (prefix >= 0) {
auto tmp = const_cast<TCHAR *>(ipStr);
int i;
for (i = 3; i > 0; i--) {
tmp = strchr(tmp, '.');
if (!tmp) {
break;
} else {
tmp++;
}
}
tmp = nullptr;
for (; i > 0; i--) {
if (asprintf(&tmp, "%s.0", ipStr) == -1) {
SPDLOG_ERROR(TEXT("Memory allocation failure"));
free(ipStr);
return -ERR_MALLOC_MEMORY;
}
ipStr = tmp;
}
} else { // assume good old days classful Internet
prefix = 32;
}
if (prefix > 32) {
SPDLOG_ERROR(TEXT("ipcalc: bad IPv4 prefix: {0}"), prefix);
free(ipStr);
return -ERR_UN_SUPPORT;
}
if (inet_ntop(AF_INET, &ip, namebuf, sizeof(namebuf)) == 0) {
SPDLOG_ERROR(TEXT("ipcalc: error calculating the IPv4 network"));
free(ipStr);
return -ERR_UN_SUPPORT;
}
StringCbCopy(pInfo->ip, MAX_IP_LEN, namebuf);
netmask.s_addr = prefix2mask(prefix);
memset(namebuf, '\0', sizeof(namebuf));
if (inet_ntop(AF_INET, &netmask, namebuf, INET_ADDRSTRLEN) == nullptr) {
SPDLOG_ERROR(TEXT("inet_ntop error"));
free(ipStr);
return -ERR_UN_SUPPORT;
}
StringCbCopy(pInfo->netmask, MAX_IP_LEN, namebuf);
pInfo->prefix = prefix;
broadcast = calc_broadcast(ip, prefix);
memset(namebuf, '\0', sizeof(namebuf));
if (inet_ntop(AF_INET, &broadcast, namebuf, INET_ADDRSTRLEN) == nullptr) {
SPDLOG_ERROR(TEXT("inet_ntop error"));
free(ipStr);
return -ERR_UN_SUPPORT;
}
StringCbCopy(pInfo->broadcast, MAX_IP_LEN, namebuf);
network = calc_network(ip, prefix);
memset(namebuf, '\0', sizeof(namebuf));
if (inet_ntop(AF_INET, &network, namebuf, INET_ADDRSTRLEN) == nullptr) {
SPDLOG_ERROR(TEXT("inet_ntop error"));
free(ipStr);
return -ERR_UN_SUPPORT;
}
StringCbCopy(pInfo->network, MAX_IP_LEN, namebuf);
if (prefix < 32) {
memcpy(&minhost, &network, sizeof(minhost));
if (prefix <= 30) {
minhost.s_addr = htonl(ntohl(minhost.s_addr) | 1);
}
if (inet_ntop(AF_INET, &minhost, namebuf, INET_ADDRSTRLEN) == nullptr) {
SPDLOG_ERROR(TEXT("inet_ntop error"));
free(ipStr);
return -ERR_UN_SUPPORT;
}
StringCbCopy(pInfo->hostmin, MAX_IP_LEN, namebuf);
memcpy(&maxhost, &network, sizeof(minhost));
maxhost.s_addr |= ~netmask.s_addr;
if (prefix <= 30) {
maxhost.s_addr = htonl(ntohl(maxhost.s_addr) - 1);
}
if (inet_ntop(AF_INET, &maxhost, namebuf, sizeof(namebuf)) == 0) {
SPDLOG_ERROR(TEXT("ipcalc: error calculating the IPv4 network"));
free(ipStr);
return -ERR_UN_SUPPORT;
}
StringCbCopy(pInfo->hostmax, MAX_IP_LEN, namebuf);
} else {
StringCbCopy(pInfo->hostmin, MAX_IP_LEN, pInfo->network);
StringCbCopy(pInfo->hostmax, MAX_IP_LEN, pInfo->network);
}
ipv4_prefix_to_hosts(pInfo->hosts, sizeof(pInfo->hosts), prefix);
free(ipStr);
return ERR_SUCCESS;
}
/**
* @brief IPv4
* @param[in] pIpStr IPv4 '/' CIDR以及子网掩码 example: 192.168.1.32/24, 192.168.1.32/255.255.255.0
* @param[out] pInfo
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetIpV4InfoFromCIDR(const TCHAR *pIpStr, PIP_INFO pInfo) {
int ret, prefix, familyIPv6 = 0;
TCHAR *prefixStr;
TCHAR *ipStr = _strdup(pIpStr);
if (pIpStr == nullptr || lstrlen(pIpStr) < MIN_IP_LEN || lstrlen(pIpStr) >= MAX_IP_LEN) {
SPDLOG_ERROR(TEXT("Input pIpStr format error: {}."), pIpStr);
return -ERR_INPUT_PARAMS;
}
if (pInfo == nullptr) {
SPDLOG_ERROR(TEXT("Input pInfo is NULL."));
return -ERR_INPUT_PARAMS;
}
if (strchr(ipStr, '/') != nullptr) {
prefixStr = static_cast<TCHAR *>(strchr(ipStr, '/'));
*prefixStr = '\0'; /* fix up ipStr */
prefixStr++;
} else {
SPDLOG_ERROR(TEXT("Input pIpStr isn't CIDR format: {}."), pIpStr);
free(ipStr);
return -ERR_INPUT_PARAMS;
}
if (strchr(prefixStr, '.') != nullptr) {
prefix = ipv4_mask_to_int(prefixStr);
} else {
prefix = str_to_prefix(&familyIPv6, prefixStr, 0);
}
ret = GetIpV4Info(ipStr, prefix, pInfo, 0);
free(ipStr);
return ret;
}
/**
* @brief IPv4
* @param[in] pIpStr IPv4
* @param[in] pNetmask IPv4子网掩码
* @param[out] pInfo
* @return 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int GetIpV4InfoFromNetmask(const TCHAR *pIpStr, const TCHAR *pNetmask, PIP_INFO pInfo) {
int prefix;
if (pIpStr == nullptr || lstrlen(pIpStr) < MIN_IP_LEN || lstrlen(pIpStr) >= MAX_IP_LEN) {
SPDLOG_ERROR(TEXT("Input pIpStr format error: {}."), pIpStr);
return -ERR_INPUT_PARAMS;
}
if (pNetmask == nullptr || lstrlen(pNetmask) < MIN_IP_LEN || lstrlen(pNetmask) >= MAX_IP_LEN) {
SPDLOG_ERROR(TEXT("Input pNetmask format error: {}."), pNetmask);
return -ERR_INPUT_PARAMS;
}
if (pInfo == nullptr) {
SPDLOG_ERROR(TEXT("Input pInfo is NULL."));
return -ERR_INPUT_PARAMS;
}
prefix = ipv4_mask_to_int(pNetmask);
return GetIpV4Info(pIpStr, prefix, pInfo, 0);
}
int GetIpV4InfoFromHostname(int family, const char *host, PIP_INFO pInfo) {
addrinfo *res, *rp;
addrinfo hints {};
int err;
static char ipname[64];
void *addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
err = getaddrinfo(host, nullptr, &hints, &res);
if (err != 0) {
return -ERR_INPUT_PARAMS;
}
for (rp = res; rp != nullptr; rp = rp->ai_next) {
if (rp->ai_family == AF_INET) {
addr = (&reinterpret_cast<sockaddr_in *>(rp->ai_addr)->sin_addr);
} else {
addr = (&reinterpret_cast<sockaddr_in6 *>(rp->ai_addr)->sin6_addr);
}
if (inet_ntop(rp->ai_family, addr, ipname, sizeof(ipname)) != nullptr) {
freeaddrinfo(res);
StringCbCopy(pInfo->hostip, MAX_IP_LEN, ipname);
return ERR_SUCCESS;
}
}
freeaddrinfo(res);
return ERR_ITEM_EXISTS;
}

335
NetTunnelSDK/misc/misc.cpp Normal file
View File

@ -0,0 +1,335 @@
#include "pch.h"
#include "misc.h"
#include "sccsdk.h"
#include <shlwapi.h>
#include <strsafe.h>
#include <spdlog/spdlog.h>
#include <magic_enum.hpp>
TCHAR *binToHexString(TCHAR *p, const unsigned char *cp, unsigned int count) {
static const TCHAR hex_asc[] = TEXT("0123456789abcdef");
while (count) {
const unsigned char c = *cp++;
/* put lowercase hex digits */
*p++ = static_cast<TCHAR>(0x20 | hex_asc[c >> 4]);
*p++ = static_cast<TCHAR>(0x20 | hex_asc[c & 0xf]);
count--;
}
return p;
}
void RemoveTailLineBreak(TCHAR *pInputStr, int strSize) {
size_t length;
if (pInputStr) {
if (StringCbLength(pInputStr, strSize, &length) == S_OK && length > 0) {
if (pInputStr[length - 2] == '\r' && pInputStr[length - 1] == '\n') {
pInputStr[length - 2] = pInputStr[length - 1] = 0;
} else if (pInputStr[length - 1] == '\n') {
pInputStr[length - 1] = 0;
}
}
}
}
int RunCommand(TCHAR *pszCmd, TCHAR *pszResultBuffer, int dwResultBufferSize, unsigned long *pRetCode) {
BOOL bRet;
HANDLE hReadPipe = nullptr;
HANDLE hWritePipe = nullptr;
DWORD retCode;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES securityAttributes;
if (pszCmd == nullptr) {
SPDLOG_ERROR(TEXT("Input params Error: [{0}]"), pszCmd);
return -ERR_INPUT_PARAMS;
}
if (pszResultBuffer && dwResultBufferSize > 0) {
memset(pszResultBuffer, 0, dwResultBufferSize);
}
memset(&si, 0, sizeof(STARTUPINFO));
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
// 设定管道的安全属性
securityAttributes.bInheritHandle = TRUE;
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = nullptr;
// 创建匿名管道
bRet = ::CreatePipe(&hReadPipe, &hWritePipe, &securityAttributes, 0);
if (FALSE == bRet) {
SPDLOG_ERROR(TEXT("CreatePipe Error"));
return -ERR_SYS_CALL;
}
// 设置新进程参数
si.cb = sizeof(si);
si.hStdError = hWritePipe;
si.hStdOutput = hWritePipe;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
// 创建新进程执行命令, 将执行结果写入匿名管道中
bRet = ::CreateProcess(nullptr, (pszCmd), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi);
if (FALSE == bRet) {
SPDLOG_ERROR(TEXT("CreateProcess Error"));
return -ERR_CREATE_PROCESS;
}
// 等待命令执行结束
//::WaitForSingleObject(pi.hThread, INFINITE);
::WaitForSingleObject(pi.hThread, 3000);
::WaitForSingleObject(pi.hProcess, 3000);
if (pszResultBuffer) {
// 从匿名管道中读取结果到输出缓冲区
::RtlZeroMemory(pszResultBuffer, dwResultBufferSize);
::ReadFile(hReadPipe, pszResultBuffer, dwResultBufferSize, nullptr, nullptr);
}
// 获取调用程序返回值
if (pRetCode) {
if (GetExitCodeProcess(pi.hProcess, &retCode)) {
*pRetCode = retCode;
}
}
// 关闭句柄, 释放内存
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
::CloseHandle(hWritePipe);
::CloseHandle(hReadPipe);
RemoveTailLineBreak(pszResultBuffer, dwResultBufferSize);
//pszResultBuffer[dwResultBufferSize - 1] = 0;
return ERR_SUCCESS;
}
void ShowWindowsErrorMessage(const TCHAR *pMsgHead) {
LPVOID buf;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
nullptr,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&buf,
0,
nullptr)) {
SPDLOG_ERROR(TEXT("{0} Error({1}): {2}"), pMsgHead, GetLastError(), buf);
LocalFree(buf);
} else {
SPDLOG_ERROR(TEXT("{0} Unknown Error{1}."), pMsgHead, GetLastError());
}
}
void StringReplaceAll(TCHAR *pOrigin, const TCHAR *pOldStr, const TCHAR *pNewStr) {
using namespace std;
const int maxSize = lstrlen(pOrigin);
auto src = string(pOrigin);
for (string::size_type pos(0); pos != string::npos; pos += lstrlen(pNewStr)) {
if ((pos = src.find(pOldStr, pos)) != string::npos) {
src.replace(pos, lstrlen(pOldStr), pNewStr);
} else {
break;
}
}
memset(pOrigin, 0, maxSize);
StringCbCopyA(pOrigin, maxSize, src.c_str());
}
void StringRemoveAll(TCHAR *pOrigin, const TCHAR *pString) {
StringReplaceAll(pOrigin, pString, "");
}
int FindFile(const TCHAR *pPath, PFILE_LIST pFileList, const bool exitWhenMatchOne) {
std::vector<TCHAR *> pathList;
TCHAR rootPath[MAX_PATH];
HANDLE hFind;
WIN32_FIND_DATA ffd;
hFind = FindFirstFile(pPath, &ffd);
if (INVALID_HANDLE_VALUE == hFind) {
return ERR_ITEM_UNEXISTS;
}
StringCbCopy(rootPath, MAX_PATH, pPath);
PathRemoveFileSpec(rootPath);
do {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) {
continue;
}
} else {
TCHAR tmp[MAX_PATH];
PathCombine(tmp, rootPath, ffd.cFileName);
pathList.push_back(_strdup(tmp));
if (exitWhenMatchOne) {
break;
}
}
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
if (GetLastError() != ERROR_NO_MORE_FILES) {
return -ERR_FIND_FILE;
}
pFileList->pFilePath = static_cast<PFILE_PATH>(HeapAlloc(GetProcessHeap(), 0, pathList.size() * sizeof(FILE_PATH)));
if (pFileList->pFilePath == nullptr) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), pathList.size() * sizeof(FILE_PATH));
return -ERR_MALLOC_MEMORY;
}
pFileList->nItems = static_cast<unsigned int>(pathList.size());
memset(pFileList->pFilePath, 0, pathList.size() * sizeof(FILE_PATH));
for (size_t i = 0; i < pathList.size(); i++) {
StringCbCopy(pFileList->pFilePath[i].path, MAX_PATH, pathList.at(i));
}
for (auto iter = pathList.begin(); iter != pathList.end(); ++iter) {
if (*iter != nullptr) {
free(*iter);
(*iter) = nullptr;
}
}
pathList.clear();
std::vector<TCHAR *> tmpSwapVector;
tmpSwapVector.swap(pathList);
return ERR_SUCCESS;
}
int GetWindowsServiceStatus(const TCHAR *pSvrName, PDWORD pStatus) {
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded = 0;
if (pSvrName == nullptr || lstrlen(pSvrName) == 0) {
SPDLOG_ERROR(TEXT("Input pSvrName params error"));
return -ERR_INPUT_PARAMS;
}
if (pStatus == nullptr) {
SPDLOG_ERROR(TEXT("Input pStatus params error"));
return -ERR_INPUT_PARAMS;
}
// Get a handle to the SCM database.
schSCManager = OpenSCManager(nullptr, // local computer
nullptr, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (nullptr == schSCManager) {
SPDLOG_ERROR(TEXT("OpenSCManager failed {0}"), GetLastError());
return -ERR_OPEN_SCM;
}
// Get a handle to the service.
schService = OpenService(schSCManager, // SCM database
pSvrName, // name of service
SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS); // full access
if (schService == nullptr) {
SPDLOG_ERROR(TEXT("OpenService failed {0}"), GetLastError());
CloseServiceHandle(schSCManager);
return -ERR_OPEN_SERVICE;
}
// Check the status in case the service is not stopped.
if (!QueryServiceStatusEx(schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
reinterpret_cast<LPBYTE>(&ssStatus), // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // size needed if buffer is too small
{
SPDLOG_ERROR(TEXT("QueryServiceStatusEx failed {0}"), GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return -ERR_GET_SERVICESSTATUS;
} else {
*pStatus = ssStatus.dwCurrentState;
}
return ERR_SUCCESS;
}
int WideCharToTChar(const WCHAR *pWStr, TCHAR *pOutStr, int maxOutLen) {
if constexpr (sizeof(TCHAR) == sizeof(WCHAR)) {
if (wcslen(pWStr) * sizeof(WCHAR) >= maxOutLen) {
SPDLOG_ERROR(TEXT("Output buffer is to short: {0} need {1}"), maxOutLen, wcslen(pWStr) * sizeof(WCHAR));
return -ERR_INPUT_PARAMS;
}
memcpy(pOutStr, pWStr, wcslen(pWStr));
} else {
int len = WideCharToMultiByte(CP_ACP, 0, pWStr, static_cast<int>(wcslen(pWStr)), nullptr, 0, nullptr, nullptr);
if (len >= maxOutLen) {
SPDLOG_ERROR(TEXT("Output buffer is to short: {0} need {1}"), maxOutLen, len);
return -ERR_INPUT_PARAMS;
}
WideCharToMultiByte(CP_ACP, 0, pWStr, static_cast<int>(wcslen(pWStr)), pOutStr, len, nullptr, nullptr);
pOutStr[len] = 0;
return ERR_SUCCESS;
}
}
int TCharToWideChar(const TCHAR *pTStr, WCHAR *pOutStr, int maxOutLen) {
if constexpr (sizeof(TCHAR) == sizeof(WCHAR)) {
if (lstrlen(pTStr) * sizeof(WCHAR) >= maxOutLen) {
SPDLOG_ERROR(TEXT("Output buffer is to short: {0} need {1}"), maxOutLen, lstrlen(pTStr) * sizeof(WCHAR));
return -ERR_INPUT_PARAMS;
}
memcpy(pOutStr, pTStr, lstrlen(pTStr));
} else {
int len = MultiByteToWideChar(CP_ACP, 0, pTStr, lstrlen(pTStr), nullptr, 0);
//int len = WideCharToMultiByte(CP_ACP, 0, pWStr, static_cast<int>(wcslen(pWStr)), nullptr, 0, nullptr, nullptr);
if (len >= maxOutLen) {
SPDLOG_ERROR(TEXT("Output buffer is to short: {0} need {1}"), maxOutLen, len);
return -ERR_INPUT_PARAMS;
}
MultiByteToWideChar(CP_ACP, 0, pTStr, lstrlen(pTStr), pOutStr, len);
pOutStr[len] = 0;
return ERR_SUCCESS;
}
}
static std::unordered_map<USER_ERRNO, std::string> g_UserErrorMap;
const CHAR *GetSDKErrorMessage(USER_ERRNO err) {
std::unordered_map<USER_ERRNO, std::string>::iterator iter;
if (g_UserErrorMap.empty()) {
constexpr auto color_entries = magic_enum::enum_entries<USER_ERRNO>();
for (auto colorEntry : color_entries) {
g_UserErrorMap.emplace(colorEntry.first, std::string(colorEntry.second));
}
}
if ((iter = g_UserErrorMap.find(err)) != g_UserErrorMap.end()) {
return iter->second.c_str();
} else {
return "UNKNOWN";
}
}

View File

@ -0,0 +1,338 @@
#include "pch.h"
#include "tunnel.h"
#include <spdlog/spdlog.h>
#include <objbase.h>
#include "globalcfg.h"
#include "httplib.h"
#include "misc.h"
#include "network.h"
#include "protocol.h"
#include "usrerr.h"
#include "user.h"
#include <strsafe.h>
static HANDLE g_ControlSvrThread = nullptr;
static httplib::Server g_httpServer;
static USER_SERVER_CONFIG g_UserSvrCfg;
/**
* @brief
* @param pUserSvrUrl URL
*/
void ConnectServerControlService(const TCHAR *pUserSvrUrl) {
InitControlServer(pUserSvrUrl);
}
static void HttpResponseError(httplib::Response &pRes, int errCode, const TCHAR *pErrMessage) {
ProtocolResponse<ResponseStatus> rsp;
std::string json;
if (errCode != ERR_SUCCESS) {
rsp.msgContent.errCode = errCode;
}
if (pErrMessage && lstrlen(pErrMessage) > 0) {
rsp.msgContent.errMessage = pErrMessage;
} else {
if (errCode == ERR_SUCCESS) {
rsp.msgContent.errMessage = TEXT("OK");
}
}
if (aigc::JsonHelper::ObjectToJson(rsp, json)) {
pRes.set_content(json, TEXT("application/json"));
} else {
SPDLOG_ERROR(TEXT("ProtocolResponse<ResponseStatus> to json error"));
}
}
int CreateControlService(PUSER_SERVER_CONFIG pSvr) {
static TCHAR g_CliNetwork[MAX_IP_LEN] = {};
static WGSERVER_CONFIG g_curCliConfig = {};
static std::mutex g_InterfaceMutex;
DWORD dwStatus = 0;
// HTTP 服务已经运行
if (g_httpServer.is_running()) {
return ERR_SUCCESS;
}
// 线程已经运行
if (g_ControlSvrThread && GetExitCodeThread(g_ControlSvrThread, &dwStatus) && dwStatus == STILL_ACTIVE) {
return -ERR_ITEM_EXISTS;
}
if (pSvr == nullptr) {
SPDLOG_ERROR(TEXT("Input pSvr params error"));
return -ERR_INPUT_PARAMS;
}
if (pSvr->svrListenPort <= 0 || pSvr->svrListenPort >= 65535) {
SPDLOG_ERROR(TEXT("Input svrListenPort params error {0}"), pSvr->svrListenPort);
return -ERR_INPUT_PARAMS;
}
if (lstrlen(pSvr->svrPrivateKey) != lstrlen(TEXT("4PPcnW3wYewNpoXjNoY3hQuCnzTNq/E9hhfU9/U6QmY="))) {
SPDLOG_ERROR(TEXT("Input svrPrivateKey params length error {0}"), pSvr->svrPrivateKey);
return -ERR_INPUT_PARAMS;
}
if (lstrlen(pSvr->svrAddress) == 0) {
SPDLOG_ERROR(TEXT("Input svrAddress params error {0}"), pSvr->svrAddress);
return -ERR_INPUT_PARAMS;
}
// 保存参数
memcpy(&g_UserSvrCfg, pSvr, sizeof(USER_SERVER_CONFIG));
g_httpServer.set_exception_handler([](const auto &req, auto &res, std::exception_ptr ep) {
const auto fmt = TEXT("<h1>Error 500</h1><p>%s</p>");
char buf[BUFSIZ];
try {
std::rethrow_exception(ep);
}
catch (std::exception &e) {
StringCbPrintf(buf, BUFSIZ, fmt, e.what());
}
catch (...) { // See the following NOTE
StringCbPrintf(buf, BUFSIZ, fmt, TEXT("Unknown Exception"));
}
res.set_content(buf, TEXT("text/html"));
res.status = 500;
});
g_httpServer.set_error_handler([](const auto &req, auto &res) {
const auto fmt = TEXT("<p>Error Status: <span style='color:red;'>%d</span></p>");
char buf[BUFSIZ];
StringCbPrintf(buf, BUFSIZ, fmt, res.status);
res.set_content(buf, TEXT("text/html"));
});
g_httpServer.Post(SET_CLIENTHEART_PATH, [](const httplib::Request &req, httplib::Response &res) {
ProtocolResponse<RspHeartParams> rsp;
std::string json;
rsp.msgContent.errCode = ERR_SUCCESS;
rsp.msgContent.errMessage = TEXT("OK");
if (aigc::JsonHelper::ObjectToJson(rsp, json)) {
res.set_content(json, TEXT("application/json"));
} else {
SPDLOG_ERROR(TEXT("ProtocolResponse<ResponseStatus> to json error"));
}
});
g_httpServer.Post(SET_CLIENTSTART_TUNNEL, [](const httplib::Request &req, httplib::Response &res) {
ProtocolRequest<ReqStartTunnelParams> reqData;
if (aigc::JsonHelper::JsonToObject(reqData, req.body)) {
int ret;
bool isSvrStart = false;
g_InterfaceMutex.lock();
// Because of COM return CO_E_FIRST
CoInitialize(nullptr);
// 判断先前是否启动过服务
if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &isSvrStart)) != ERR_SUCCESS) {
// 返回获取系统服务错误,是否未安装
HttpResponseError(res, ret, TEXT("Not found WireGuard application in system"));
SPDLOG_ERROR(TEXT("IsWireGuardServerInstalled error: {0}"), ret);
g_InterfaceMutex.unlock();
return;
}
// 当前服务状态和需要执行的操作不同
if (isSvrStart != reqData.msgContent.isStart) {
if (reqData.msgContent.isStart) {
IP_INFO cliInfo;
IP_INFO tunnelInfo;
int retry = 3;
// 启动服务
ret = WireGuardInstallDefaultServerService(true);
if (ret != ERR_SUCCESS) {
// 返回启动服务失败
SPDLOG_ERROR(TEXT("WireGuardInstallDefaultServerService error: {0}"), ret);
HttpResponseError(res, ret, TEXT("Start WireGuard Tunnel Service error."));
g_InterfaceMutex.unlock();
return;
}
// 添加路由
if ((ret = GetIpV4InfoFromCIDR(g_CliNetwork, &cliInfo)) != ERR_SUCCESS) {
// 返回启动服务失败
SPDLOG_ERROR(TEXT("GetIpV4InfoFromCIDR ({1}) error: {0}"), ret, g_CliNetwork);
HttpResponseError(res, ret, TEXT("Parse IpAddress error."));
g_InterfaceMutex.unlock();
return;
}
if ((ret = GetIpV4InfoFromCIDR(g_UserSvrCfg.svrAddress, &tunnelInfo)) != ERR_SUCCESS) {
// 返回启动服务失败
SPDLOG_ERROR(TEXT("GetIpV4InfoFromCIDR ({1}) error: {0}"), ret, g_UserSvrCfg.svrAddress);
HttpResponseError(res, ret, TEXT("Parse tunnel ip address error."));
g_InterfaceMutex.unlock();
return;
}
do {
ret = AddRouteTable(cliInfo.ip, cliInfo.netmask, tunnelInfo.ip);
Sleep(1000);
} while (ret != ERR_SUCCESS && retry--);
if (ret != ERR_SUCCESS) {
// 返回启动服务失败
SPDLOG_ERROR(TEXT("Add Route {1}/{2} gateway {3} error: {0}"),
ret,
cliInfo.ip,
cliInfo.netmask,
tunnelInfo.ip);
HttpResponseError(res, ret, TEXT("Parse tunnel ip address error."));
g_InterfaceMutex.unlock();
return;
}
} else {
if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
// 返回停止服务失败
HttpResponseError(res, ret, TEXT("Stop pre running WireGuard service error"));
SPDLOG_ERROR(TEXT("WireGuardUnInstallServerService error: {0}"), ret);
g_InterfaceMutex.unlock();
return;
}
}
}
if (reqData.msgContent.isStart) {
SPDLOG_INFO(TEXT("Tunnel Service Start Now ......: {0}"), GetGlobalCfgInfo()->userCfg.userName);
} else {
SPDLOG_INFO(TEXT("Tunnel Service Stoped: {0}"), GetGlobalCfgInfo()->userCfg.userName);
}
HttpResponseError(res, ERR_SUCCESS, nullptr);
g_InterfaceMutex.unlock();
}
});
g_httpServer.Post(SET_CLIENTCFG_PATH, [](const httplib::Request &req, httplib::Response &res) {
ProtocolRequest<ReqUserSetCliCfgParams> reqData;
if (aigc::JsonHelper::JsonToObject(reqData, req.body)) {
int ret;
bool isSvrStart = false;
ProtocolResponse<RspUserSetCliCfgParams> rsp;
std::string json;
g_InterfaceMutex.lock();
// Because of COM return CO_E_FIRST
CoInitialize(nullptr);
// 判断先前是否启动过服务
if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &isSvrStart)) != ERR_SUCCESS) {
// 返回获取系统服务错误,是否未安装
HttpResponseError(res, ret, TEXT("Not found WireGuard application in system"));
SPDLOG_ERROR(TEXT("IsWireGuardServerInstalled error: {0}"), ret);
g_InterfaceMutex.unlock();
return;
}
if (isSvrStart) {
SPDLOG_DEBUG(TEXT("WireGuardUnInstallServerService: {0}"), GetGlobalCfgInfo()->userCfg.userName);
if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
// 返回停止服务失败
HttpResponseError(res, ret, TEXT("Stop pre running WireGuard service error"));
SPDLOG_ERROR(TEXT("WireGuardUnInstallServerService error: {0}"), ret);
g_InterfaceMutex.unlock();
return;
}
}
memset(&g_curCliConfig, 0, sizeof(WGSERVER_CONFIG));
g_curCliConfig.ListenPort = g_UserSvrCfg.svrListenPort - 1;
StringCbCopy(g_curCliConfig.Name, 64, GetGlobalCfgInfo()->userCfg.userName);
StringCbCopy(g_curCliConfig.Address, 32, g_UserSvrCfg.svrAddress);
StringCbCopy(g_curCliConfig.PrivateKey, 64, g_UserSvrCfg.svrPrivateKey);
StringCbCopy(g_curCliConfig.CliPubKey, 64, reqData.msgContent.cliPublicKey.c_str());
StringCbCopy(g_CliNetwork, MAX_IP_LEN, reqData.msgContent.cliNetwork.c_str());
StringCbPrintf(g_curCliConfig.AllowNet,
256,
TEXT("%s,%s"),
reqData.msgContent.cliNetwork.c_str(),
reqData.msgContent.cliTunnelAddr.c_str());
// 创建 WireGuard 配置文件
ret = WireGuardCreateServerConfig(&g_curCliConfig);
if (ret != ERR_SUCCESS) {
// 返回写入 WireGuard 配置文件错误
HttpResponseError(res, ret, TEXT("Create WireGuard service configure file error"));
SPDLOG_ERROR(TEXT("WireGuardCreateServerConfig error: {0}"), ret);
g_InterfaceMutex.unlock();
return;
}
// 返回当前隧道信息
rsp.msgContent.errCode = ERR_SUCCESS;
rsp.msgContent.errMessage = TEXT("OK");
rsp.msgContent.svrNetwork = g_UserSvrCfg.svrAddress;
if (aigc::JsonHelper::ObjectToJson(rsp, json)) {
res.set_content(json, TEXT("application/json"));
} else {
SPDLOG_ERROR(TEXT("ProtocolResponse<RspUserSetCliCfgParams> to json error"));
HttpResponseError(res, ERR_JSON_CREATE, TEXT("ProtocolResponse<RspUserSetCliCfgParams> to json error"));
}
g_InterfaceMutex.unlock();
}
});
SPDLOG_DEBUG(TEXT("Start HTTP Service at {0}"), pSvr->svrListenPort);
if (!g_httpServer.bind_to_port(TEXT("0.0.0.0"), pSvr->svrListenPort)) {
SPDLOG_ERROR(TEXT("Start HTTP Service at {0} error"), pSvr->svrListenPort);
return -ERR_SOCKET_BIND_PORT;
}
g_ControlSvrThread = CreateThread(
nullptr, // Thread attributes
0, // Stack size (0 = use default)
[](LPVOID lpParameter) {
if (!g_httpServer.listen_after_bind()) {
SPDLOG_ERROR(TEXT("Start HTTP Service at {0} error"));
}
SPDLOG_DEBUG(TEXT("Http service exit....."));
return static_cast<DWORD>(0);
}, // Thread start address
nullptr, // Parameter to pass to the thread
0, // Creation flags
nullptr); // Thread id
if (g_ControlSvrThread == nullptr) {
// Thread creation failed.
// More details can be retrieved by calling GetLastError()
return -ERR_CREATE_THREAD;
}
g_httpServer.wait_until_ready();
return ERR_SUCCESS;
}
int StopControlService() {
if (g_httpServer.is_running()) {
g_httpServer.stop();
}
if (g_ControlSvrThread) {
// Wait for thread to finish execution
if (WaitForSingleObject(g_ControlSvrThread, 10 * 1000) == WAIT_TIMEOUT) {
SPDLOG_ERROR(TEXT("Waitting HTTP Service clost timeout"));
return -ERROR_TIMEOUT;
}
CloseHandle(g_ControlSvrThread);
g_ControlSvrThread = nullptr;
}
return ERR_SUCCESS;
}

View File

@ -0,0 +1,285 @@
#include "pch.h"
#include <strsafe.h>
#include <spdlog/spdlog.h>
#include "usrerr.h"
#include "misc.h"
#if !USED_PORTMAP_TUNNEL
#include "globalcfg.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <spdlog/fmt/bin_to_hex.h>
#define SCG_UDP_HEAD_SIZE (11)
#endif
void StopUDPProxyServer() {
#if !USED_PORTMAP_TUNNEL
const PSCG_PROXY_INFO pProxy = &GetGlobalCfgInfo()->scgProxy;
pProxy->exitNow = true;
if (pProxy->hProxyTunnelThread) {
if (WaitForSingleObject(pProxy->hProxyTunnelThread, 10 * 1000) == WAIT_TIMEOUT) {
SPDLOG_ERROR(TEXT("Waitting HTTP Service clost timeout"));
}
closesocket(pProxy->udpProxySock);
}
if (pProxy->hProxySCGThread) {
if (WaitForSingleObject(pProxy->hProxySCGThread, 10 * 1000) == WAIT_TIMEOUT) {
SPDLOG_ERROR(TEXT("Waitting HTTP Service clost timeout"));
}
closesocket(pProxy->scgGwSock);
}
#endif
}
#if !USED_PORTMAP_TUNNEL
static DWORD UDPProxvRemoteThread(LPVOID lpParameter) {
const auto pPeerSock = static_cast<sockaddr_in *>(lpParameter);
const PSCG_PROXY_INFO pProxy = &GetGlobalCfgInfo()->scgProxy;
while (pPeerSock && !pProxy->exitNow) {
sockaddr_in remoteWgAddr {};
TCHAR ipAddr[MAX_IP_LEN];
int addrSize = sizeof(SOCKADDR);
char recvBuf[1500];
int iRecvBytes;
// 代理服务 In
iRecvBytes = recvfrom(pProxy->scgGwSock,
recvBuf,
1500,
0,
reinterpret_cast<SOCKADDR *>(&remoteWgAddr),
&addrSize);
memset(ipAddr, 0, MAX_IP_LEN);
InetNtop(AF_INET, &remoteWgAddr.sin_addr.s_addr, ipAddr, MAX_IP_LEN);
SPDLOG_TRACE(TEXT(">>> Scoket In {1} Recv {0} bytes from {2}:{3}"),
iRecvBytes,
pProxy->scgGwSock,
ipAddr,
ntohs(remoteWgAddr.sin_port));
if (iRecvBytes != SOCKET_ERROR) {
int sendBytes = sendto(pProxy->udpProxySock,
recvBuf,
iRecvBytes,
0,
reinterpret_cast<SOCKADDR *>(pPeerSock),
sizeof(SOCKADDR));
memset(ipAddr, 0, MAX_IP_LEN);
InetNtop(AF_INET, &pPeerSock->sin_addr.s_addr, ipAddr, MAX_IP_LEN);
SPDLOG_TRACE(TEXT("<<< Scoket In Send {0} bytes to {2}:{3}"),
sendBytes,
pProxy->udpProxySock,
ipAddr,
ntohs(pPeerSock->sin_port));
} else {
SPDLOG_ERROR(TEXT(">>> Scoket In {1} Recv {0} bytes from {2}:{3} error: {4}"),
iRecvBytes,
pProxy->scgGwSock,
ipAddr,
ntohs(remoteWgAddr.sin_port),
WSAGetLastError());
}
Sleep(100);
}
return 0;
}
static DWORD UDPProxyRecvThread(LPVOID lpParameter) {
bool isRemoteInit = false;
sockaddr_in localWgAddr {};
sockaddr_in scgAddr {};
unsigned char recvBuf[1500 + SCG_UDP_HEAD_SIZE];
std::array<UINT8, 1511> arr;
const PSCG_PROXY_INFO pProxy = &GetGlobalCfgInfo()->scgProxy;
const auto svrId = static_cast<UINT8>(GetGlobalCfgInfo()->userCfg.cliConfig.scgTunnelAppId);
char *pRecBuf = reinterpret_cast<char *>(&recvBuf[SCG_UDP_HEAD_SIZE]);
scgAddr.sin_family = AF_INET;
scgAddr.sin_port = htons(pProxy->scgGwPort);
InetPton(AF_INET, pProxy->scgIpAddr, &scgAddr.sin_addr.s_addr);
// 构建 SCG UDP 包头
recvBuf[0] = 0x01; // VERSION
recvBuf[1] = 0x09; // Length
recvBuf[2] = 0xF0; // ++++++ INFO[0] TYPE
recvBuf[3] = 0x04; // INFO[0] LENGTH
recvBuf[4] = 0; // INFO[0] VMID[0]
recvBuf[5] = 0; // INFO[0] VMID[1]
recvBuf[6] = 0; // INFO[0] VMID[2]
recvBuf[7] = 0; // INFO[0] VMID[3]
recvBuf[8] = 0xF1; // INFO[1] TYPE
recvBuf[9] = 0x01; // INFO[1] LENGTH
recvBuf[10] = svrId; // ------ INFO[1] SCG Service ID
pProxy->exitNow = false;
while (!pProxy->exitNow) {
TCHAR ipAddr[MAX_IP_LEN];
int addrSize = sizeof(SOCKADDR);
int iRecvBytes;
// 代理服务 Out
iRecvBytes = recvfrom(pProxy->udpProxySock,
pRecBuf,
1500,
0,
reinterpret_cast<SOCKADDR *>(&localWgAddr),
&addrSize);
InetNtop(AF_INET, &localWgAddr.sin_addr.s_addr, ipAddr, MAX_IP_LEN);
SPDLOG_TRACE(TEXT(">>> Scoket Out {1} Recv {0} bytes from {2}:{3}"),
iRecvBytes,
pProxy->udpProxySock,
ipAddr,
ntohs(localWgAddr.sin_port));
if (iRecvBytes >= (1450 - SCG_UDP_HEAD_SIZE)) {
SPDLOG_WARN(TEXT("!Maybe MTU overflow: Current package {0} bytes, UDP MTU 1450, SCG Head Used {1} bytes"),
iRecvBytes,
SCG_UDP_HEAD_SIZE);
}
if (iRecvBytes != SOCKET_ERROR) {
int sendBytes;
const unsigned int id = htonl(GetGlobalCfgInfo()->curConnVmId);
unsigned char vmid[4];
memcpy(vmid, &id, 4);
if (!isRemoteInit) {
HANDLE handle;
isRemoteInit = true;
// 创建远端接收线程
handle = CreateThread(nullptr, // Thread attributes
0, // Stack size (0 = use default)
UDPProxvRemoteThread, // Thread start address
&localWgAddr, // Parameter to pass to the thread
0, // Creation flags
nullptr); // Thread id
if (handle == nullptr) {
SPDLOG_ERROR("Create Thread failed with error = {0}", GetLastError());
closesocket(pProxy->udpProxySock);
closesocket(pProxy->scgGwSock);
pProxy->exitNow = true;
return -ERR_CREATE_THREAD;
}
pProxy->hProxySCGThread = handle;
}
recvBuf[4] = vmid[0]; // INFO[0] VMID[0]
recvBuf[5] = vmid[1]; // INFO[0] VMID[1]
recvBuf[6] = vmid[2]; // INFO[0] VMID[2]
recvBuf[7] = vmid[3]; // INFO[0] VMID[3]
// 增加SCG包头数据长度
iRecvBytes += 11;
if (GetGlobalCfgInfo()->logLevel == spdlog::level::trace) {
const auto start = std::begin(recvBuf);
std::copy_n(start, iRecvBytes, std::begin(arr));
SPDLOG_TRACE(TEXT("UDP Proxy SCG({1}/0x{2:X}) Payload: {0:Xa}"),
spdlog::to_hex(start, start + iRecvBytes, 16),
svrId,
id);
}
sendBytes = sendto(pProxy->scgGwSock,
reinterpret_cast<char *>(recvBuf),
iRecvBytes,
0,
reinterpret_cast<SOCKADDR *>(&scgAddr),
sizeof(SOCKADDR));
memset(ipAddr, 0, MAX_IP_LEN);
InetNtop(AF_INET, &scgAddr.sin_addr.s_addr, ipAddr, MAX_IP_LEN);
SPDLOG_TRACE(TEXT("<<< Scoket Out Send {0} bytes to {2}:{3}"),
sendBytes,
pProxy->scgGwSock,
ipAddr,
ntohs(scgAddr.sin_port));
}
Sleep(100);
}
return 0;
}
#endif
int CreateUDPProxyServer() {
#if !USED_PORTMAP_TUNNEL
HANDLE handle;
int ret;
int addrSize = sizeof(sockaddr_in);
sockaddr_in server {};
sockaddr_in bindAddr {};
SOCKET sock;
const PSCG_PROXY_INFO pProxy = &GetGlobalCfgInfo()->scgProxy;
// 创建本地 SOCKET 代理服务器
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
SPDLOG_ERROR("Create UDP Socket failed with error = {0}", WSAGetLastError());
return -ERR_SOCKET_CREATE;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(0);
if (bind(sock, reinterpret_cast<SOCKADDR *>(&server), sizeof(SOCKADDR)) == SOCKET_ERROR) {
closesocket(sock);
SPDLOG_ERROR("Bind local UDP Socket failed with error = {0}", WSAGetLastError());
return -ERR_SOCKET_BIND;
}
if ((ret = getsockname(sock, reinterpret_cast<SOCKADDR *>(&bindAddr), &addrSize)) != 0) {
closesocket(sock);
SPDLOG_ERROR("Get UDP Socket bind port failed with error = {0}, {1}", WSAGetLastError(), ret);
return -ERR_SOCKET_BIND;
}
// 保存 UDP 代理服务器信息
pProxy->udpProxySock = sock;
pProxy->proxyPort = ntohs(bindAddr.sin_port);
SPDLOG_DEBUG(TEXT("Proxy Server socket {0} bind {1} prot"), sock, pProxy->proxyPort);
// 创建SCG SOCKET 连接客户端服务
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
SPDLOG_ERROR("Create UDP Socket failed with error = {0}", WSAGetLastError());
closesocket(pProxy->udpProxySock);
return -ERR_SOCKET_CREATE;
}
pProxy->scgGwSock = sock;
// 创建代理服务发送线程
handle = CreateThread(nullptr, // Thread attributes
0, // Stack size (0 = use default)
UDPProxyRecvThread, // Thread start address
nullptr, // Parameter to pass to the thread
0, // Creation flags
nullptr); // Thread id
if (handle == nullptr) {
SPDLOG_ERROR("Create Thread failed with error = {0}", GetLastError());
closesocket(pProxy->udpProxySock);
closesocket(pProxy->scgGwSock);
return -ERR_CREATE_THREAD;
}
pProxy->hProxyTunnelThread = handle;
#endif
return ERR_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,444 @@
#include "pch.h"
#include "tunnel.h"
#include "protocol.h"
#include "globalcfg.h"
#include "httplib.h"
#include "misc.h"
#include "usrerr.h"
#include <strsafe.h>
#include <spdlog/fmt/bin_to_hex.h>
#define HTTP_JSON_CONTENT TEXT("application/json")
static httplib::Client *g_httpCtx = nullptr;
static httplib::Client *g_tunnelHttpCtx = nullptr;
int InitControlServer(const TCHAR *pUserSvrUrl) {
if (g_tunnelHttpCtx) {
delete g_tunnelHttpCtx;
g_tunnelHttpCtx = nullptr;
}
if (UsedSCGProxy()) {
TCHAR scgProxyUrl[MAX_PATH];
StringCbPrintf(scgProxyUrl, MAX_PATH, TEXT("http://127.0.0.1:%d"), GetGlobalCfgInfo()->scgProxy.scgGwPort);
SPDLOG_DEBUG(TEXT("Control Server Used Proxy: {0} --> {1}"), pUserSvrUrl, scgProxyUrl);
g_tunnelHttpCtx = new httplib::Client(scgProxyUrl);
} else {
g_tunnelHttpCtx = new httplib::Client(pUserSvrUrl);
SPDLOG_DEBUG(TEXT("Control Server Unused Proxy: {0}"), pUserSvrUrl);
}
if (g_tunnelHttpCtx) {
g_tunnelHttpCtx->set_connection_timeout(0, 1000000); // 1 second
g_tunnelHttpCtx->set_read_timeout(5, 0); // 5 seconds
g_tunnelHttpCtx->set_write_timeout(5, 0); // 5 seconds
g_tunnelHttpCtx->set_keep_alive(true);
g_tunnelHttpCtx->set_post_connect_cb([](socket_t sock) {
if (UsedSCGProxy()) {
int ret;
unsigned char vmid[4];
unsigned char *p;
const unsigned int id = htonl(GetGlobalCfgInfo()->curConnVmId);
const auto svrId = static_cast<UINT8>(GetGlobalCfgInfo()->userCfg.cliConfig.scgCtrlAppId);
unsigned char scgProxy[] = {0x01, // VERSION
0x09, // Length
0xF0, // ++++++ INFO[0] TYPE
0x04, // INFO[0] LENGTH
0, // INFO[0] VMID[0]
0, // INFO[0] VMID[1]
0, // INFO[0] VMID[2]
0, // INFO[0] VMID[3]
0xF1, // INFO[1] TYPE
0x01, // INFO[1] LENGTH
svrId}; // ------ INFO[1] SCG Service ID
p = scgProxy;
memcpy(vmid, &id, 4);
scgProxy[4] = vmid[0];
scgProxy[5] = vmid[1];
scgProxy[6] = vmid[2];
scgProxy[7] = vmid[3];
if (GetGlobalCfgInfo()->logLevel == spdlog::level::trace) {
std::array<unsigned char, sizeof(scgProxy)> arr;
std::copy(std::begin(scgProxy), std::end(scgProxy), std::begin(arr));
SPDLOG_DEBUG(TEXT("TCP Proxy SCG Payload: {0:Xa}"), spdlog::to_hex(arr));
}
ret = send(sock, reinterpret_cast<const char *>(p), sizeof(scgProxy), 0);
while (ret < static_cast<int>(sizeof(scgProxy))) {
p += ret;
ret += send(sock, reinterpret_cast<const char *>(p), sizeof(scgProxy), 0);
}
SPDLOG_DEBUG(TEXT("Service Connected To SCG Server({1}/{2}): {0}"),
sock,
GetGlobalCfgInfo()->curConnVmId,
svrId);
}
});
}
SPDLOG_DEBUG(TEXT("Connect to Tunnel Control Service: {0}"), pUserSvrUrl);
return ERR_SUCCESS;
}
template<class T> int CreateProtocolRequest(T *pReqParams, TCHAR **pOutJson) {
std::string json;
if (!g_httpCtx && lstrlen(GetGlobalCfgInfo()->platformServerUrl) > 0) {
g_httpCtx = new httplib::Client(GetGlobalCfgInfo()->platformServerUrl);
if (g_httpCtx) {
g_httpCtx->set_connection_timeout(0, 300000); // 300 milliseconds
g_httpCtx->set_read_timeout(5, 0); // 5 seconds
g_httpCtx->set_write_timeout(5, 0); // 5 seconds
g_httpCtx->set_keep_alive(true);
g_httpCtx->enable_server_certificate_verification(false);
}
}
if (aigc::JsonHelper::ObjectToJson(*pReqParams, json)) {
*pOutJson = _strdup(json.c_str());
return ERR_SUCCESS;
}
return -ERR_JSON_CREATE;
}
template<class T> int DecodeProtocolResponse(T *pResponse, const TCHAR *pJson) {
if (aigc::JsonHelper::JsonToObject(*pResponse, pJson)) {
return ERR_SUCCESS;
}
return -ERR_JSON_DECODE;
}
template<class T1, class T2>
int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<T1> *pReq,
ProtocolResponse<T2> *pRsp,
bool platformServer) {
int ret;
httplib::Result res;
TCHAR *pJson = nullptr;
if (lstrlen(GetGlobalCfgInfo()->platformServerUrl) == 0) {
SPDLOG_ERROR(TEXT("Platform Server URL uninitialize."));
return -ERR_SYSTEM_UNINITIALIZE;
}
if (pReq == nullptr) {
SPDLOG_ERROR(TEXT("Input pToken params error"));
SPDLOG_ERROR(TEXT("Input ProtocolRequest<T1> *pReq params error"));
return -ERR_INPUT_PARAMS;
}
if (pRsp == nullptr) {
SPDLOG_ERROR(TEXT("Input ProtocolResponse<T2> *pRsp params error"));
return -ERR_INPUT_PARAMS;
}
ret = CreateProtocolRequest(pReq, &pJson);
if (ret != ERR_SUCCESS) {
if (pJson) {
free(pJson);
}
return ret;
}
if (platformServer) {
std::string timestamp = std::to_string(time(nullptr)) + "000";
TCHAR hashValeu[MAX_PATH] = {0};
TCHAR hashBuf[1024] = {};
StringCbPrintf(hashBuf,
1024,
TEXT("%s|%s|%s|%s"),
GetGlobalCfgInfo()->clientId,
GetGlobalCfgInfo()->clientSecret,
timestamp.c_str(),
pJson);
if (lstrlen(GetGlobalCfgInfo()->clientSecret) > 0 &&
CalcHmacHash(HASH_SHA256,
reinterpret_cast<PUCHAR>(hashBuf),
lstrlen(hashBuf),
reinterpret_cast<PUCHAR>(GetGlobalCfgInfo()->clientSecret),
lstrlen(GetGlobalCfgInfo()->clientSecret),
hashValeu,
true) == ERR_SUCCESS) {
const httplib::Headers headers = {
{"gzs-client-id", GetGlobalCfgInfo()->clientId},
{"gzs-sign", hashValeu },
{"gzs-timestamp", timestamp },
};
res = g_httpCtx->Post(pUrlPath, headers, pJson, HTTP_JSON_CONTENT);
} else {
res = g_httpCtx->Post(pUrlPath, pJson, HTTP_JSON_CONTENT);
}
} else {
if (g_tunnelHttpCtx == nullptr) {
free(pJson);
SPDLOG_ERROR(TEXT("Server Control Service don't connected(g_tunnelHttpCtx is not initialize)."));
return -ERR_SYSTEM_UNINITIALIZE;
}
res = g_tunnelHttpCtx->Post(pUrlPath, pJson, HTTP_JSON_CONTENT);
}
if (res.error() != httplib::Error::Success) {
SPDLOG_ERROR(TEXT("[{0}]:Post Data {1} error: {2}"), pUrlPath, pJson, httplib::to_string(res.error()));
free(pJson);
return -ERR_HTTP_POST_DATA;
}
if (res->status != 200) {
SPDLOG_ERROR(TEXT("[{0}]:Post Data {1} server return HTTP error: {2}"), pUrlPath, pJson, res->status);
free(pJson);
return -ERR_HTTP_SERVER_RSP;
}
SPDLOG_DEBUG(TEXT("+++++ Http Request {0}\n---- Http Response {1}"), pJson, res->body.c_str());
free(pJson);
if (lstrlen(res->body.c_str()) == 0) {
SPDLOG_ERROR(TEXT("Server response empty message"));
return -ERR_READ_FILE;
}
if (DecodeProtocolResponse(pRsp, res->body.c_str()) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Decode JSON {0} to ProtocolResponse<{1}> error"), res->body, typeid(T2).name());
return -ERR_JSON_DECODE;
}
return ERR_SUCCESS;
}
#if 0
template<class T1> int PlatformProtolGetMessage(const TCHAR *pUrlPath, T1 *pRsp) {
httplib::Result res;
TCHAR *pJson = nullptr;
std::string timestamp = std::to_string(time(nullptr)) + "000";
TCHAR hashValeu[MAX_PATH] = {0};
TCHAR hashBuf[1024] = {};
if (lstrlen(GetGlobalCfgInfo()->platformServerUrl) == 0) {
SPDLOG_ERROR(TEXT("Platform Server URL uninitialize."));
return -ERR_SYSTEM_UNINITIALIZE;
}
if (pRsp == nullptr) {
SPDLOG_ERROR(TEXT("Input ProtocolResponse<T2> *pRsp params error"));
return -ERR_INPUT_PARAMS;
}
StringCbPrintf(hashBuf,
1024,
TEXT("%s|%s|%s|%s"),
GetGlobalCfgInfo()->clientId,
GetGlobalCfgInfo()->clientSecret,
timestamp.c_str(),
pJson);
if (lstrlen(GetGlobalCfgInfo()->clientSecret) > 0 &&
CalcHmacHash(HASH_SHA256,
reinterpret_cast<PUCHAR>(hashBuf),
lstrlen(hashBuf),
reinterpret_cast<PUCHAR>(GetGlobalCfgInfo()->clientSecret),
lstrlen(GetGlobalCfgInfo()->clientSecret),
hashValeu,
true) == ERR_SUCCESS) {
const httplib::Headers headers = {
{"gzs-client-id", GetGlobalCfgInfo()->clientId},
{"gzs-sign", hashValeu },
{"gzs-timestamp", timestamp },
};
res = g_httpCtx->Get(pUrlPath, headers);
} else {
res = g_httpCtx->Get(pUrlPath);
}
if (res.error() != httplib::Error::Success) {
SPDLOG_ERROR(TEXT("[{0}]:Post Data {1} error: {2}"), pUrlPath, pJson, httplib::to_string(res.error()));
free(pJson);
return -ERR_HTTP_POST_DATA;
}
if (res->status != 200) {
SPDLOG_ERROR(TEXT("[{0}]:Post Data {1} server return HTTP error: {2}"), pUrlPath, pJson, res->status);
free(pJson);
return -ERR_HTTP_SERVER_RSP;
}
SPDLOG_DEBUG(TEXT("+++++ Http Request {0}\n---- Http Response {1}"), pJson, res->body.c_str());
free(pJson);
if (lstrlen(res->body.c_str()) == 0) {
SPDLOG_ERROR(TEXT("Server response empty message"));
return -ERR_READ_FILE;
}
if (DecodeProtocolResponse(pRsp, res->body.c_str()) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Decode JSON {0} to ProtocolResponse<{1}> error"), res->body, typeid(T1).name());
return -ERR_JSON_DECODE;
}
return ERR_SUCCESS;
}
#endif
template<class T1, class T2> int PlatformProtolPostMessage(const TCHAR *pUrlPath, T1 *pReq, T2 *pRsp) {
int ret;
httplib::Result res;
TCHAR *pJson = nullptr;
std::string timestamp = std::to_string(time(nullptr)) + "000";
TCHAR hashValeu[MAX_PATH] = {0};
TCHAR hashBuf[1024] = {};
if (lstrlen(GetGlobalCfgInfo()->platformServerUrl) == 0) {
SPDLOG_ERROR(TEXT("Platform Server URL uninitialize."));
return -ERR_SYSTEM_UNINITIALIZE;
}
if (pReq == nullptr) {
SPDLOG_ERROR(TEXT("Input pToken params error"));
SPDLOG_ERROR(TEXT("Input ProtocolRequest<T1> *pReq params error"));
return -ERR_INPUT_PARAMS;
}
if (pRsp == nullptr) {
SPDLOG_ERROR(TEXT("Input ProtocolResponse<T2> *pRsp params error"));
return -ERR_INPUT_PARAMS;
}
ret = CreateProtocolRequest(pReq, &pJson);
if (ret != ERR_SUCCESS) {
if (pJson) {
free(pJson);
}
return ret;
}
StringCbPrintf(hashBuf,
1024,
TEXT("%s|%s|%s|%s"),
GetGlobalCfgInfo()->clientId,
GetGlobalCfgInfo()->clientSecret,
timestamp.c_str(),
pJson);
if (lstrlen(GetGlobalCfgInfo()->clientSecret) > 0 &&
CalcHmacHash(HASH_SHA256,
reinterpret_cast<PUCHAR>(hashBuf),
lstrlen(hashBuf),
reinterpret_cast<PUCHAR>(GetGlobalCfgInfo()->clientSecret),
lstrlen(GetGlobalCfgInfo()->clientSecret),
hashValeu,
true) == ERR_SUCCESS) {
if (typeid(T1) == typeid(PlatformReqClientCfgParms)) {
const auto *p = reinterpret_cast<PlatformReqClientCfgParms *>(pReq);
const httplib::Headers headers = {
{"gzs-client-id", GetGlobalCfgInfo()->clientId },
{"gzs-sign", hashValeu },
{"gzs-timestamp", timestamp },
{"Authorization", ("Bearer " + p->token).c_str()},
};
res = g_httpCtx->Post(pUrlPath, headers, pJson, HTTP_JSON_CONTENT);
} else {
const httplib::Headers headers = {
{"gzs-client-id", GetGlobalCfgInfo()->clientId},
{"gzs-sign", hashValeu },
{"gzs-timestamp", timestamp },
};
res = g_httpCtx->Post(pUrlPath, headers, pJson, HTTP_JSON_CONTENT);
}
} else {
if (typeid(T1) == typeid(PlatformReqClientCfgParms)) {
const auto *p = reinterpret_cast<PlatformReqClientCfgParms *>(pReq);
const httplib::Headers headers = {
{"Authorization", ("Bearer " + p->token).c_str()},
};
res = g_httpCtx->Post(pUrlPath, headers, pJson, HTTP_JSON_CONTENT);
} else {
res = g_httpCtx->Post(pUrlPath, pJson, HTTP_JSON_CONTENT);
}
}
SPDLOG_DEBUG(TEXT("+++++ Http Request {0}\n---- Http Response {1}"), pJson, res->body.c_str());
if (res.error() != httplib::Error::Success) {
SPDLOG_ERROR(TEXT("[{0}]:Post Data {1} error: {2}"), pUrlPath, pJson, httplib::to_string(res.error()));
free(pJson);
return -ERR_HTTP_POST_DATA;
}
if (res->status != 200) {
SPDLOG_ERROR(TEXT("[{0}]:Post Data {1} server return HTTP error: {2}"), pUrlPath, pJson, res->status);
free(pJson);
return -ERR_HTTP_SERVER_RSP;
}
free(pJson);
if (lstrlen(res->body.c_str()) == 0) {
SPDLOG_ERROR(TEXT("Server response empty message"));
return -ERR_READ_FILE;
}
if (DecodeProtocolResponse(pRsp, res->body.c_str()) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Decode JSON {0} to ProtocolResponse<{1}> error"), res->body, typeid(T2).name());
return -ERR_JSON_DECODE;
}
return ERR_SUCCESS;
}
template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqGetUserCfgParams> *pReq,
ProtocolResponse<RspUserSevrCfgParams> *pRsp,
bool platformServer);
template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqGetUserCfgParams> *pReq,
ProtocolResponse<RspUsrCliConfigParams> *pRsp,
bool platformServer);
template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqUserSetCliCfgParams> *pReq,
ProtocolResponse<RspUserSetCliCfgParams> *pRsp,
bool platformServer);
template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqStartTunnelParams> *pReq,
ProtocolResponse<ResponseStatus> *pRsp,
bool platformServer);
template int ProtolPostMessage(const TCHAR *pUrlPath,
ProtocolRequest<ReqHeartParams> *pReq,
ProtocolResponse<RspHeartParams> *pRsp,
bool platformServer);
#if !USER_REAL_PLATFORM
template int PlatformProtolPostMessage(const TCHAR *pUrlPath,
PlatformReqServerCfgParms *pReq,
PlatformRspServerCfgParams *pRsp);
template int PlatformProtolPostMessage(const TCHAR *pUrlPath,
PlatformReqClientCfgParms *pReq,
PlatformRspClientCfgParams *pRsp);
//template int PlatformProtolGetMessage(const TCHAR *pUrlPath, PlatformRspUserClientCfgParams *pRsp);
#endif

View File

@ -0,0 +1,335 @@
#include "pch.h"
#include "usrerr.h"
#include "globalcfg.h"
#include "tunnel.h"
#include "wireguard.h"
#include "misc.h"
#include <shlwapi.h>
#include <strsafe.h>
#include <spdlog/spdlog.h>
static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter;
static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter;
static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter;
static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID;
static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion;
static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver;
static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger;
static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging;
static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState;
static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState;
static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration;
static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration;
typedef struct {
WIREGUARD_INTERFACE Interface;
WIREGUARD_PEER RemoteServer;
WIREGUARD_ALLOWED_IP Allow1;
WIREGUARD_ALLOWED_IP Allow2;
} WG_CONFIG_INFO;
static HMODULE g_WireGarudModule;
int InitializeWireGuardLibrary() {
TCHAR dllPath[MAX_PATH];
StringCbPrintf(dllPath, MAX_PATH, TEXT("%s\\wireguard.dll"), GetGlobalCfgInfo()->workDirectory);
if (!PathFileExists(dllPath)) {
SPDLOG_ERROR(TEXT("WireGuard DLL Not Found: {0}"), dllPath);
return -ERR_ITEM_UNEXISTS;
}
g_WireGarudModule = LoadLibraryEx(dllPath,
nullptr,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!g_WireGarudModule) {
DWORD errCode = GetLastError();
SPDLOG_ERROR(TEXT("LoadLibraryEx WireGuard DLL error: {0}"), errCode);
return -ERR_LOAD_LIBRARY;
}
#define X(Name) ((*(FARPROC *)&(Name) = GetProcAddress(g_WireGarudModule, #Name)) == nullptr)
if (X(WireGuardCreateAdapter) || X(WireGuardOpenAdapter) || X(WireGuardCloseAdapter) ||
X(WireGuardGetAdapterLUID) || X(WireGuardGetRunningDriverVersion) || X(WireGuardDeleteDriver) ||
X(WireGuardSetLogger) || X(WireGuardSetAdapterLogging) || X(WireGuardGetAdapterState) ||
X(WireGuardSetAdapterState) || X(WireGuardGetConfiguration) || X(WireGuardSetConfiguration))
#undef X
{
SPDLOG_ERROR(TEXT("Map WireGuard DLL EntryPoint error: {0}"), GetLastError());
FreeLibrary(g_WireGarudModule);
return -ERR_MAP_LIBRARY;
}
return ERR_SUCCESS;
}
void UnInitializeWireGuardLibrary() {
if (g_WireGarudModule) {
FreeLibrary(g_WireGarudModule);
}
}
int GetWireGuradTunnelInfo(const TCHAR *pTunnelName) {
WIREGUARD_ADAPTER_HANDLE Adapter;
int ret;
WCHAR wstrName[MAX_PATH];
if ((ret = TCharToWideChar(pTunnelName, wstrName, MAX_PATH)) != ERR_SUCCESS) {
return ret;
}
Adapter = WireGuardOpenAdapter(wstrName);
if (Adapter) {
WG_CONFIG_INFO config;
DWORD Bytes = sizeof(WG_CONFIG_INFO);
if (!WireGuardGetConfiguration(Adapter, &config.Interface, &Bytes)) {
SPDLOG_ERROR("Failed to get configuration: {0}", GetLastError());
}
}
return ERR_SUCCESS;
}
int GetWireGuardServiceStatus(const TCHAR *pTunnelName, bool *pIsRunning) {
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR svrName[MAX_PATH];
if (pTunnelName == nullptr || lstrlen(pTunnelName) == 0) {
SPDLOG_ERROR(TEXT("Input pTunnelName error: {0}"), pTunnelName);
return -ERR_INPUT_PARAMS;
}
if (pIsRunning == nullptr) {
SPDLOG_ERROR(TEXT("Input pIsRunning params error"));
return -ERR_INPUT_PARAMS;
}
*pIsRunning = false;
StringCbPrintf(svrName, MAX_PATH, TEXT("WireGuardTunnel$%s"), pTunnelName);
// Get a handle to the SCM database.
schSCManager = OpenSCManager(nullptr, // local computer
nullptr, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (nullptr == schSCManager) {
SPDLOG_ERROR(TEXT("OpenSCManager failed ({0})"), GetLastError());
return -ERR_OPEN_SCM;
}
// Get a handle to the service.
schService = OpenService(schSCManager, // SCM database
svrName, // name of service
SERVICE_ALL_ACCESS); // full access
CloseServiceHandle(schService);
// 如果服务不存在则直接返回
if (schService != nullptr) {
*pIsRunning = true;
}
return ERR_SUCCESS;
}
int RemoveGuardService(const TCHAR *pTunnelName, bool bIsWaitStop) {
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR svrName[MAX_PATH];
SERVICE_STATUS svrStatus;
if (pTunnelName == nullptr || lstrlen(pTunnelName) == 0) {
SPDLOG_ERROR(TEXT("Input pTunnelName error: {0}"), pTunnelName);
return -ERR_INPUT_PARAMS;
}
StringCbPrintf(svrName, MAX_PATH, TEXT("WireGuardTunnel$%s"), pTunnelName);
// Get a handle to the SCM database.
schSCManager = OpenSCManager(nullptr, // local computer
nullptr, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (nullptr == schSCManager) {
SPDLOG_ERROR(TEXT("OpenSCManager failed ({0})"), GetLastError());
return -ERR_OPEN_SCM;
}
// Get a handle to the service.
schService = OpenService(schSCManager, // SCM database
svrName, // name of service
SERVICE_ALL_ACCESS); // full access
// 如果服务不存在则直接返回
if (schService == nullptr) {
CloseServiceHandle(schSCManager);
return ERR_SUCCESS;
}
if (ControlService(schService, SERVICE_CONTROL_STOP, &svrStatus) == 0) {
DWORD errCode = GetLastError();
if (errCode != ERROR_SERVICE_CANNOT_ACCEPT_CTRL && errCode != ERROR_SERVICE_NOT_ACTIVE) {
SPDLOG_ERROR(TEXT("Stop Service {1} failed ({0})"), errCode, svrName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return -ERR_STOP_SERVICE;
}
}
for (int i = 0; bIsWaitStop && i < 10; i++) {
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded = 0;
if (QueryServiceStatusEx(schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
reinterpret_cast<LPBYTE>(&ssStatus), // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // size needed if buffer is too small
{
// 服务已经停止
if (ssStatus.dwCurrentState == SERVICE_STOPPED) {
break;
}
}
//SPDLOG_ERROR(TEXT("Stop Service {1} retry times ({0})"), i + 1, svrName);
Sleep(1000);
}
if (!DeleteService(schService) && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) {
SPDLOG_ERROR(TEXT("Delete Service {1} failed ({0})"), GetLastError(), svrName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return -ERR_DELETE_SERVICE;
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return ERR_SUCCESS;
}
int CreateWireGuardService(const TCHAR *pInterfaceName, const TCHAR *pWGConfigFilePath) {
//Service Name: "WireGuardTunnel$SomeTunnelName"
//Display Name: "Some Service Name"
//Service Type: SERVICE_WIN32_OWN_PROCESS
//Start Type: StartAutomatic
//Error Control: ErrorNormal,
//Dependencies: [ "Nsi", "TcpIp" ]
//Sid Type: SERVICE_SID_TYPE_UNRESTRICTED
//Executable: "C:\path\to\example\vpnclient.exe /service configfile.conf"
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR svrName[MAX_PATH];
TCHAR displayName[MAX_PATH];
TCHAR svrPath[MAX_PATH];
TCHAR execParams[MAX_PATH * 2];
if (pInterfaceName == nullptr || lstrlen(pInterfaceName) == 0) {
SPDLOG_ERROR(TEXT("Input pInterfaceName error: {0}"), pInterfaceName);
return -ERR_INPUT_PARAMS;
}
if (pWGConfigFilePath == nullptr || lstrlen(pWGConfigFilePath) == 0) {
SPDLOG_ERROR(TEXT("Input pGUID error: {0}"), pWGConfigFilePath);
return -ERR_INPUT_PARAMS;
}
if (!PathFileExists(pWGConfigFilePath)) {
SPDLOG_ERROR(TEXT("WireGuard Configure File Not Exist: {0}"), pWGConfigFilePath);
return -ERR_ITEM_UNEXISTS;
}
StringCbPrintf(svrName, MAX_PATH, TEXT("WireGuardTunnel$%s"), pInterfaceName);
StringCbPrintf(displayName, MAX_PATH, TEXT("WireGuard Tunnel Service %s"), pInterfaceName);
StringCbPrintf(svrPath, MAX_PATH, TEXT("%s\\NetTunnelSvr.exe"), GetGlobalCfgInfo()->workDirectory);
StringCbPrintf(execParams, MAX_PATH * 2, TEXT("\"%s\" /service \"%s\""), svrPath, pWGConfigFilePath);
//SPDLOG_DEBUG(TEXT("Params: {0}"), execParams);
if (!PathFileExists(svrPath)) {
SPDLOG_ERROR(TEXT("WireGuard Service Not Exist: {0}"), svrPath);
return -ERR_ITEM_UNEXISTS;
}
// Get a handle to the SCM database.
schSCManager = OpenSCManager(nullptr, // local computer
nullptr, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (nullptr == schSCManager) {
SPDLOG_ERROR(TEXT("OpenSCManager failed ({0})"), GetLastError());
return -ERR_OPEN_SCM;
}
// Get a handle to the service.
schService = OpenService(schSCManager, // SCM database
svrName, // name of service
SERVICE_ALL_ACCESS); // full access
// 如果服务已经存在则关闭
if (schService != nullptr) {
int ret;
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
ret = RemoveGuardService(pInterfaceName, true);
if (ret != ERR_SUCCESS) {
return ret;
}
}
schService = CreateService(schSCManager,
svrName,
displayName,
SC_MANAGER_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
execParams,
nullptr,
nullptr,
TEXT("Nsi\0TcpIp"),
nullptr,
nullptr);
if (schService == nullptr) {
SPDLOG_ERROR(TEXT("Create Service {1} failed ({0})"), GetLastError(), svrName);
CloseServiceHandle(schSCManager);
return -ERR_CREATE_SERVICE;
} else {
SERVICE_SID_INFO info;
SERVICE_DESCRIPTIONA desc;
info.dwServiceSidType = SERVICE_SID_TYPE_UNRESTRICTED;
if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_SERVICE_SID_INFO, &info)) {
SPDLOG_ERROR(TEXT("Change Service {1} SERVICE_CONFIG_SERVICE_SID_INFO Configure failed ({0})"),
GetLastError(),
svrName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return -ERR_CONFIG_SERVICE;
}
desc.lpDescription = TEXT(const_cast<LPSTR>("SCC Tunnel Service over WireGuard"));
if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &desc)) {
SPDLOG_ERROR(TEXT("Change Service {1} SERVICE_CONFIG_DESCRIPTION Configure failed ({0})"),
GetLastError(),
svrName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return -ERR_CONFIG_SERVICE;
}
if (!StartService(schService, 0, nullptr)) {
SPDLOG_ERROR(TEXT("Start Service {1} failed ({0})"), GetLastError(), svrName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return -ERR_START_SERVICE;
}
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return ERR_SUCCESS;
}

View File

@ -0,0 +1,326 @@
#include "pch.h"
#include "tunnel.h"
#include <shlobj_core.h>
#include <strsafe.h>
#include <spdlog/sinks/wincolor_sink.h>
#include <spdlog/sinks/dup_filter_sink.h>
#include <spdlog/sinks/daily_file_sink.h>
#include <dbghelp.h>
#include "globalcfg.h"
#include "misc.h"
#include "user.h"
#include <shlwapi.h>
#include <winsock2.h>
#pragma comment(lib, "Dbghelp.lib")
#define CONFIG_FILE_NAME TEXT("tunnelsdk.ini")
static SDK_CONFIG g_globalConfig;
PSDK_CONFIG GetGlobalCfgInfo() {
return &g_globalConfig;
}
static spdlog::level::level_enum logLevelToSpdlogLevel(LOG_LEVEL level) {
switch (level) {
case LOG_TRACE:
return spdlog::level::level_enum::trace;
case LOG_DEBUG:
return spdlog::level::level_enum::debug;
case LOG_INFO:
return spdlog::level::level_enum::info;
case LOG_WARN:
return spdlog::level::level_enum::warn;
case LOG_ERROR:
return spdlog::level::level_enum::err;
case LOG_CRITICAL:
return spdlog::level::level_enum::critical;
case LOG_OFF:
return spdlog::level::level_enum::off;
}
return spdlog::level::level_enum::info;
}
static void InitTunnelSDKLog(const TCHAR *pLogFile, LOG_LEVEL level) {
TCHAR buf[MAX_PATH] = {0};
if (pLogFile && strlen(pLogFile) > 0 && !PathIsRelative(pLogFile)) {
TCHAR tmpPath[MAX_PATH];
StringCbCopy(tmpPath, MAX_PATH, pLogFile);
PathRemoveFileSpec(tmpPath);
MakeSureDirectoryPathExists(tmpPath);
StringCbCopy(buf, MAX_PATH, pLogFile);
} else {
StringCbPrintf(buf, MAX_PATH, TEXT("%s\\tunnelsdklog.log"), g_globalConfig.workDirectory);
}
g_globalConfig.enableLog = TRUE;
g_globalConfig.logLevel = logLevelToSpdlogLevel(level);
const auto dupFileFilter = std::make_shared<spdlog::sinks::dup_filter_sink_st>(std::chrono::seconds(5));
const auto dupStdFilter = std::make_shared<spdlog::sinks::dup_filter_sink_st>(std::chrono::seconds(5));
//std::make_shared<spdlog::sinks::rotating_file_sink_mt>(buf, 1024 * 1024 * 5, 10)->
dupFileFilter->add_sink(std::make_shared<spdlog::sinks::daily_file_sink_mt>(buf, 2, 30));
//dupFileFilter->add_sink(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(buf, 1024 * 1024 * 5, 10));
dupStdFilter->add_sink(std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>());
std::vector<spdlog::sink_ptr> sinks {dupStdFilter, dupFileFilter};
auto logger = std::make_shared<spdlog::logger>(TEXT("tunnelSDK"), sinks.begin(), sinks.end());
spdlog::set_default_logger(logger);
spdlog::set_level(g_globalConfig.logLevel);
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l][%s:%#] %v");
spdlog::flush_every(std::chrono::seconds(1));
#if 0
std::cout << "TRACE: " << logger->should_log(spdlog::level::trace) << std::endl;
std::cout << "DEBUG: " << logger->should_log(spdlog::level::debug) << std::endl;
std::cout << "INFO: " << logger->should_log(spdlog::level::info) << std::endl;
std::cout << "WARN: " << logger->should_log(spdlog::level::warn) << std::endl;
std::cout << "ERROR: " << logger->should_log(spdlog::level::err) << std::endl;
std::cout << "CRITICAL: " << logger->should_log(spdlog::level::critical) << std::endl;
#endif
SPDLOG_INFO(TEXT("Log({1}): {0}"), buf, static_cast<int>(level));
}
int TunnelSDKInitEnv(const TCHAR *pWorkDir,
const TCHAR *pSvrUrl,
const TCHAR *pLogFile,
LOG_LEVEL level,
bool isWorkServer) {
int ret;
size_t length;
WSADATA WsaData;
CoInitialize(nullptr);
CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr,
EOAC_NONE, nullptr);
WSAStartup(MAKEWORD(2, 2), &WsaData);
memset(&g_globalConfig, 0, sizeof(SDK_CONFIG));
g_globalConfig.isWorkServer = isWorkServer;
g_globalConfig.scgProxy.scgGwPort = 0;
if (pWorkDir == nullptr) {
// 获取当前文件默认路径
GetModuleFileName(nullptr, g_globalConfig.workDirectory, MAX_PATH);
PathRemoveFileSpec(g_globalConfig.workDirectory);
} else {
if (StringCbLength(pWorkDir, MAX_PATH, &length) == S_OK && length == 0 || PathIsRelative(pWorkDir)) {
// 获取当前文件默认路径
GetModuleFileName(nullptr, g_globalConfig.workDirectory, MAX_PATH);
PathRemoveFileSpec(g_globalConfig.workDirectory);
} else {
MakeSureDirectoryPathExists(pWorkDir);
StringCbCopy(g_globalConfig.workDirectory, MAX_PATH, pWorkDir);
}
}
// 初始化日志
InitTunnelSDKLog(pLogFile, level);
// 创建配置文件存储目录
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_NO_ALIAS, NULL, 0, g_globalConfig.configDirectory))) {
SPDLOG_ERROR(TEXT("Get Windows system directory error."));
return -ERR_SYS_CALL;
}
StringCbCat(g_globalConfig.configDirectory, MAX_PATH, "\\NetTunnel");
SPDLOG_DEBUG(TEXT("Configure directory: {0}."), g_globalConfig.configDirectory);
SPDLOG_DEBUG(TEXT("Platform Server: {}, Work Module: {}"), pSvrUrl, isWorkServer ? TEXT("SERVER") : TEXT("Client"));
// 如果配置目录不存在则自动创建
if (!PathFileExists(g_globalConfig.configDirectory)) {
if (!CreateDirectory(g_globalConfig.configDirectory, nullptr)) {
SPDLOG_ERROR(TEXT("Create configure directory '{0}' error."), g_globalConfig.configDirectory);
return -ERR_CREATE_FILE;
}
}
StringCbCopy(g_globalConfig.platformServerUrl, MAX_IP_LEN, pSvrUrl);
if (FAILED(SHGetFolderPath(NULL, CSIDL_WINDOWS | CSIDL_FLAG_NO_ALIAS, NULL, 0, g_globalConfig.systemDirectory))) {
SPDLOG_ERROR(TEXT("Get Windows system directory error."));
return -ERR_SYS_CALL;
}
StringCbPrintf(g_globalConfig.cfgPath, MAX_PATH, TEXT("%s\\%s"), g_globalConfig.workDirectory, CONFIG_FILE_NAME);
if ((ret = InitializeWireGuardLibrary()) == ERR_SUCCESS) {
return ret;
}
#if 0
if (FindWireguardExe(nullptr, 0) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("WireGuard not found, Please install WireGuard first or set the WireGuard Path."));
return -ERR_ITEM_UNEXISTS;
}
#endif
return ERR_SUCCESS;
}
void TunnelSDKUnInit() {
RemoteWireGuardControl(false);
LocalWireGuardControl(false, false);
UnInitializeWireGuardLibrary();
CoFreeUnusedLibraries();
WSACleanup();
}
void DisableVerifySignature() {
memset(g_globalConfig.clientId, 0, MAX_PATH);
memset(g_globalConfig.clientSecret, 0, MAX_PATH);
}
int EnableVerifySignature(const TCHAR *pClientId, const TCHAR *pClientSecret) {
if (pClientId == nullptr || lstrlen(pClientId) == 0 || lstrlen(pClientId) >= MAX_PATH) {
SPDLOG_ERROR(TEXT("Input pClientId params error: {0}"), pClientId);
return -ERR_INPUT_PARAMS;
}
if (pClientSecret == nullptr || lstrlen(pClientSecret) == 0 || lstrlen(pClientSecret) >= MAX_PATH) {
SPDLOG_ERROR(TEXT("Input pClientSecret params error: {0}"), pClientSecret);
return -ERR_INPUT_PARAMS;
}
DisableVerifySignature();
StringCbCopy(g_globalConfig.clientId, MAX_PATH, pClientId);
StringCbCopy(g_globalConfig.clientSecret, MAX_PATH, pClientSecret);
return ERR_SUCCESS;
}
int EnableSCGProxy(bool isEnable, const TCHAR *pSCGIpAddr, int scgPort) {
if (pSCGIpAddr == nullptr || lstrlen(pSCGIpAddr) == 0 || lstrlen(pSCGIpAddr) >= MAX_IP_LEN) {
SPDLOG_ERROR(TEXT("Input pInterfaceName params error: {0}"), pSCGIpAddr);
return -ERR_INPUT_PARAMS;
}
memset(g_globalConfig.scgProxy.scgIpAddr, 0, MAX_IP_LEN);
if (isEnable) {
IP_INFO ipInfo;
int ret;
if ((ret = GetIpV4InfoFromHostname(AF_INET, pSCGIpAddr, &ipInfo)) != ERR_SUCCESS) {
return ret;
}
g_globalConfig.userCfg.cliConfig.scgCtrlAppId = WG_CTRL_SCG_ID;
g_globalConfig.userCfg.cliConfig.scgTunnelAppId = WG_TUNNEL_SCG_ID;
StringCbCopy(g_globalConfig.scgProxy.scgIpAddr, MAX_IP_LEN, ipInfo.hostip);
g_globalConfig.scgProxy.scgGwPort = static_cast<UINT16>(scgPort);
CreateUDPProxyServer();
} else {
StopUDPProxyServer();
g_globalConfig.scgProxy.scgGwPort = 0;
}
return ERR_SUCCESS;
}
bool UsedSCGProxy() {
return (g_globalConfig.scgProxy.scgGwPort > 0);
}
void TunnelLogEnable(bool enLog) {
if (enLog) {
spdlog::set_level(g_globalConfig.logLevel);
} else {
spdlog::set_level(spdlog::level::level_enum::off);
}
}
int SetProtocolEncryptType(const PROTO_CRYPTO_TYPE type, const TCHAR *pProKey) {
if (type > CRYPTO_BASE64 && type < CRYPTO_MAX) {
if (pProKey == nullptr || strlen(pProKey) < MIN_IP_LEN) {
return -ERR_INPUT_PARAMS;
}
}
g_globalConfig.proCryptoType = type;
StringCbCopy(g_globalConfig.proKeyBuf, 256, pProKey);
SPDLOG_DEBUG(TEXT("Protocol crypto type: {0} with key [{1}]"), static_cast<int>(type),
pProKey ? pProKey : TEXT(""));
return ERR_SUCCESS;
}
//int CheckSystemMinDepend(CHECK_FUNCTION chkItem, TCHAR* pErrMsg, errMsg[MAX_PATH], );
int CheckSystemMinRequired(CHK_RESULT chkResult[CHK_MAX]) {
for (int i = 0; i < CHK_MAX; i++) {
const PCHK_RESULT pChk = &chkResult[i];
pChk->chk = static_cast<CHECK_FUNCTION>(i);
pChk->result = true;
memset(pChk->errMsg, 0, MAX_PATH);
switch (pChk->chk) {
case CHK_SYSTEM_INIT:
if (lstrlen(g_globalConfig.configDirectory) == 0) {
pChk->result = false;
StringCbCopy(pChk->errMsg, MAX_PATH,
TEXT("错误: SDK 未初始化,请先调用 TunnelSDKInitEnv 接口执行初始化操作。"));
SPDLOG_ERROR(pChk->errMsg);
}
break;
case CHK_WIREGUARD_CONFIG: {
TCHAR cfgVal[MAX_PATH];
GetPrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, TEXT(""), cfgVal, MAX_PATH,
GetGlobalCfgInfo()->cfgPath);
if (!PathFileExists(cfgVal)) {
pChk->result = false;
StringCbCopy(pChk->errMsg, MAX_PATH,
TEXT("错误: 未找到 WireGuard 配置文件,请先调用 WireGuardInstallServerService 或者 "
"WireGuardCreateClientConfig 接口创建合法的 WireGuard 配置文件。"));
SPDLOG_ERROR(pChk->errMsg);
}
} break;
case CHK_WIREGUARD_SERVICE: {
int ret;
bool bInstall;
ret = IsWireGuardServerInstalled(&bInstall);
if (ret != ERR_SUCCESS) {
pChk->result = false;
StringCbPrintf(pChk->errMsg, MAX_PATH,
TEXT("错误: 获取系统 WireGuard 服务安装状态异常, 错误码:{0}。"), ret);
SPDLOG_ERROR(pChk->errMsg);
}
if (!bInstall) {
pChk->result = false;
StringCbCopy(pChk->errMsg, MAX_PATH,
TEXT("错误:系统 WireGuard 服务未安装,请调用 WireGuardInstallServerService 接口安装 "
"WireGuard 服务。"));
SPDLOG_ERROR(pChk->errMsg);
}
} break;
case CHK_WG_INTERFACE_PRIVATE:
if (!chkResult[CHK_WIREGUARD_SERVICE].chk) {
pChk->result = false;
StringCbCopy(pChk->errMsg, MAX_PATH,
TEXT("错误:系统 WireGuard 服务未安装,请调用 WireGuardInstallServerService 接口安装 "
"WireGuard 服务。"));
SPDLOG_ERROR(pChk->errMsg);
}
break;
case CHK_MAX:
break;
}
}
return ERR_SUCCESS;
}

View File

@ -0,0 +1,774 @@
#include "pch.h"
#include "tunnel.h"
#include "usrerr.h"
#include <strsafe.h>
#include <tchar.h>
#include <shlwapi.h>
#include "globalcfg.h"
#include "misc.h"
#include "network.h"
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "Winmm.lib")
static NET_SHARE_MODE g_CurShareMode = ICS_SHARE_MODE;
NET_SHARE_MODE GetCurrentNetShareMode() {
return g_CurShareMode;
}
void SetCurrentNetShareMode(NET_SHARE_MODE shareMode) {
g_CurShareMode = shareMode;
}
int GetWireGuardWorkMode(bool *pIsWorkServer) {
if (pIsWorkServer == nullptr) {
SPDLOG_ERROR(TEXT("Input pIsWorkServer params error"));
return -ERR_INPUT_PARAMS;
}
*pIsWorkServer = GetGlobalCfgInfo()->isWorkServer;
return ERR_SUCCESS;
}
int WireGuardInstallDefaultServerService(bool bInstall) {
TCHAR cfgVal[MAX_PATH];
GetPrivateProfileString(CFG_WIREGUARD_SECTION,
CFG_WGCFG_PATH,
TEXT(""),
cfgVal,
MAX_PATH,
GetGlobalCfgInfo()->cfgPath);
if (lstrlen(cfgVal) > 0) {
if (PathFileExists(cfgVal)) {
int ret;
TCHAR svrName[MAX_PATH];
StringCbCopy(svrName, MAX_PATH, cfgVal);
PathStripPath(svrName);
PathRemoveExtension(svrName);
if (bInstall) {
ret = WireGuardInstallServerService(cfgVal); //CreateWireGuardService(svrName, cfgVal);
} else {
ret = RemoveGuardService(svrName, true);
}
if (bInstall && ret == ERR_SUCCESS) {
int retry = 10;
do {
ret = WaitNetAdapterConnected(svrName, 1000);
} while (ret != ERR_SUCCESS && retry--);
}
return ret;
} else {
SPDLOG_ERROR(TEXT("WireGuard configure file [{0}] not found"), cfgVal);
return -ERR_FILE_NOT_EXISTS;
}
} else {
SPDLOG_ERROR(TEXT("Configure [{0}] = {1} not found"), CFG_WGCFG_PATH, cfgVal);
return -ERR_ITEM_UNEXISTS;
}
}
int WireGuardInstallServerService(const TCHAR *pTunnelCfgPath) {
// 卸载服务
TCHAR svrName[MAX_PATH];
int ret;
StringCbCopy(svrName, MAX_PATH, pTunnelCfgPath);
PathStripPath(svrName);
PathRemoveExtension(svrName);
if (pTunnelCfgPath == nullptr || lstrlen(pTunnelCfgPath) == 0) {
SPDLOG_ERROR(TEXT("Input pTunnelCfgPath params error"));
return -ERR_INPUT_PARAMS;
}
if (!PathFileExists(pTunnelCfgPath)) {
SPDLOG_ERROR(TEXT("WireGuard configure file {0} unexists."), pTunnelCfgPath);
return -ERR_ITEM_UNEXISTS;
}
if ((ret = CreateWireGuardService(svrName, pTunnelCfgPath)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Create WireGuard Service Error({0}): {1}, {2} "), ret, svrName, pTunnelCfgPath);
return ret;
}
return ERR_SUCCESS;
}
int WireGuardUnInstallServerService(const TCHAR *pTunnelName) {
// 卸载服务
int ret;
if (pTunnelName == nullptr || lstrlen(pTunnelName) == 0) {
SPDLOG_ERROR(TEXT("Input pTunnelName params error"));
return -ERR_INPUT_PARAMS;
}
if ((ret = RemoveGuardService(pTunnelName, true)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Stop WireGuard Service Error: {0}"), ret);
return ret;
}
return ERR_SUCCESS;
}
int IsWireGuardServerInstalled(bool *pIsInstalled) {
DWORD dwStatus;
int ret;
if (pIsInstalled == nullptr) {
SPDLOG_ERROR(TEXT("Input pIsInstalled params error"));
return -ERR_INPUT_PARAMS;
}
*pIsInstalled = false;
ret = GetWindowsServiceStatus(TEXT("WireGuard"), &dwStatus);
if (ret == ERR_SUCCESS) {
switch (dwStatus) {
case SERVICE_CONTINUE_PENDING:
case SERVICE_RUNNING:
case SERVICE_START_PENDING:
*pIsInstalled = true;
break;
default:
*pIsInstalled = false;
break;
}
}
return ret;
}
int IsWireGuardServerRunning(const TCHAR *pIfName, bool *pIsRunning) {
return GetWireGuardServiceStatus(pIfName, pIsRunning);
}
int WireGuardCreateClientConfig(const PWGCLIENT_CONFIG pWgConfig) {
const size_t bufSize = 4096 * sizeof(TCHAR);
const TCHAR cfgFormat[] = TEXT(
"[Interface]\nPrivateKey = %s\nAddress = %s\n\n[Peer]\nPublicKey = %s\nAllowedIPs = %s\nEndpoint = "
"%s\nPersistentKeepalive = 30\n");
TCHAR cfgPath[MAX_PATH];
size_t length;
HANDLE hFile;
TCHAR *pBuf;
#pragma region
if (pWgConfig == nullptr) {
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->Name, 64, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Name error: {0}"), pWgConfig->Name);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->Address, 32, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Address error: {0}"), pWgConfig->Address);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->PrivateKey, 64, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Private key error: {0}"), pWgConfig->PrivateKey);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->SvrPubKey, 64, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Server Public key error: {0}"), pWgConfig->SvrPubKey);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->AllowNet, 256, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Allow Client Network error: {0}"), pWgConfig->AllowNet);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->ServerURL, 256, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Server Network error: {0}"), pWgConfig->ServerURL);
return -ERR_INPUT_PARAMS;
}
#pragma endregion 参数检查
pBuf = static_cast<TCHAR *>(malloc(bufSize));
if (pBuf == nullptr) {
SPDLOG_ERROR(TEXT("Malloc {1} bytes memory error: {0}"), GetLastError(), bufSize);
return -ERR_MALLOC_MEMORY;
}
memset(pBuf, 0, bufSize);
StringCbPrintf(cfgPath,
MAX_PATH,
"%s\\%s",
GetGlobalCfgInfo()->configDirectory,
GetGlobalCfgInfo()->userCfg.userName);
// 如果当前用户配置目录不存在则自动创建
if (!PathFileExists(cfgPath)) {
if (!CreateDirectory(cfgPath, nullptr)) {
SPDLOG_ERROR(TEXT("Create configure directory '{0}' error."), cfgPath);
return -ERR_CREATE_FILE;
}
}
StringCbPrintf(cfgPath,
MAX_PATH,
"%s\\%s\\%s.conf",
GetGlobalCfgInfo()->configDirectory,
GetGlobalCfgInfo()->userCfg.userName,
pWgConfig->Name);
hFile = CreateFile(cfgPath, // name of the write
GENERIC_WRITE | GENERIC_READ, // open for writing
FILE_SHARE_READ, // do not share
nullptr, // default security
CREATE_ALWAYS, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
nullptr); // no attr. template
if (hFile == INVALID_HANDLE_VALUE) {
SPDLOG_ERROR(TEXT("CreatFile [{0}] error: {1}"), cfgPath, GetLastError());
free(pBuf);
return -ERR_OPEN_FILE;
}
// 保存到配置文件中
WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, cfgPath, GetGlobalCfgInfo()->cfgPath);
if (FAILED(StringCbPrintf(pBuf,
bufSize,
cfgFormat,
pWgConfig->PrivateKey,
pWgConfig->Address,
pWgConfig->SvrPubKey,
pWgConfig->AllowNet,
pWgConfig->ServerURL))) {
SPDLOG_ERROR(TEXT("Format string error: {0}"), GetLastError());
free(pBuf);
::CloseHandle(hFile);
return -ERR_MEMORY_STR;
}
if (FAILED(StringCbLength(pBuf, bufSize, &length))) {
SPDLOG_ERROR(TEXT("Get string \'{0}\' length error: {1}"), pBuf, GetLastError());
free(pBuf);
::CloseHandle(hFile);
return -ERR_MEMORY_STR;
}
SPDLOG_DEBUG(TEXT("WG Client Configure:\n{0}"), pBuf);
if (!WriteFile(hFile, // open file handle
pBuf, // start of data to write
static_cast<DWORD>(length), // number of bytes to write
nullptr, // number of bytes that were written
nullptr)) {
SPDLOG_ERROR(TEXT("WriteFile [{0}] error: {1}"), cfgPath, GetLastError());
free(pBuf);
::CloseHandle(hFile);
return -ERR_OPEN_FILE;
}
StringCbCopy(GetGlobalCfgInfo()->wgClientCfg.wgName, 260, pWgConfig->Name);
StringCbCopy(GetGlobalCfgInfo()->wgClientCfg.wgIpaddr, MAX_IP_LEN, pWgConfig->Address);
StringCbCopy(GetGlobalCfgInfo()->wgClientCfg.wgCfgPath, MAX_PATH, cfgPath);
::CloseHandle(hFile);
return ERR_SUCCESS;
}
int WireGuardCreateServerConfig(const PWGSERVER_CONFIG pWgConfig) {
const size_t bufSize = 4096 * sizeof(TCHAR);
const TCHAR cfgFormat[] = TEXT(
"[Interface]\nAddress = %s\nListenPort = %d\nPrivateKey = %s\n\n[Peer]\nPublicKey = %s\nAllowedIPs = %s\n");
TCHAR cfgPath[MAX_PATH];
size_t length;
HANDLE hFile;
TCHAR *pBuf;
#pragma region
if (pWgConfig == nullptr) {
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->Name, 64, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Name error: {0}"), pWgConfig->Name);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->Address, 32, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Address error: {0}"), pWgConfig->Address);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->PrivateKey, 64, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Private key error: {0}"), pWgConfig->PrivateKey);
return -ERR_INPUT_PARAMS;
}
if (pWgConfig->ListenPort <= 1024 || pWgConfig->ListenPort >= 65535) {
SPDLOG_ERROR(TEXT("WireGuard Listen port error: {0}, should be in arrange (1024, 65535)"),
pWgConfig->ListenPort);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->CliPubKey, 64, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Client Public key error: {0}"), pWgConfig->CliPubKey);
return -ERR_INPUT_PARAMS;
}
if (FAILED(StringCbLength(pWgConfig->AllowNet, 256, &length)) || 0 == length) {
SPDLOG_ERROR(TEXT("WireGuard Allow Client Network error: {0}"), pWgConfig->AllowNet);
return -ERR_INPUT_PARAMS;
}
#pragma endregion 参数检查
pBuf = static_cast<TCHAR *>(malloc(bufSize));
if (pBuf == nullptr) {
SPDLOG_ERROR(TEXT("Malloc {1} bytes memory error: {0}"), GetLastError(), bufSize);
return -ERR_MALLOC_MEMORY;
}
memset(pBuf, 0, bufSize);
StringCbPrintf(cfgPath,
MAX_PATH,
"%s\\%s",
GetGlobalCfgInfo()->configDirectory,
GetGlobalCfgInfo()->userCfg.userName);
// 如果当前用户配置目录不存在则自动创建
if (!PathFileExists(cfgPath)) {
if (!CreateDirectory(cfgPath, nullptr)) {
SPDLOG_ERROR(TEXT("Create configure directory '{0}' error."), cfgPath);
return -ERR_CREATE_FILE;
}
}
StringCbPrintf(cfgPath,
MAX_PATH,
"%s\\%s\\%s.conf",
GetGlobalCfgInfo()->configDirectory,
GetGlobalCfgInfo()->userCfg.userName,
pWgConfig->Name);
hFile = CreateFile(cfgPath, // name of the write
GENERIC_WRITE | GENERIC_READ, // open for writing
FILE_SHARE_READ, // do not share
nullptr, // default security
CREATE_ALWAYS, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
nullptr); // no attr. template
if (hFile == INVALID_HANDLE_VALUE) {
SPDLOG_ERROR(TEXT("CreatFile [{0}] error: {1}"), cfgPath, GetLastError());
free(pBuf);
return -ERR_OPEN_FILE;
}
// 清空文件
SetFilePointer(hFile, 0, nullptr, FILE_BEGIN);
SetEndOfFile(hFile);
WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, cfgPath, GetGlobalCfgInfo()->cfgPath);
if (FAILED(StringCbPrintf(pBuf,
bufSize,
cfgFormat,
pWgConfig->Address,
pWgConfig->ListenPort,
pWgConfig->PrivateKey,
pWgConfig->CliPubKey,
pWgConfig->AllowNet))) {
SPDLOG_ERROR(TEXT("Format string error: {0}"), GetLastError());
free(pBuf);
::CloseHandle(hFile);
return -ERR_MEMORY_STR;
}
if (FAILED(StringCbLength(pBuf, bufSize, &length))) {
SPDLOG_ERROR(TEXT("Get string \'{0}\' length error: {1}"), pBuf, GetLastError());
free(pBuf);
::CloseHandle(hFile);
return -ERR_MEMORY_STR;
}
SPDLOG_DEBUG(TEXT("WG Server Configure:\n{0}"), pBuf);
if (FALSE ==
WriteFile(hFile, // open file handle
pBuf, // start of data to write
static_cast<DWORD>(length), // number of bytes to write
nullptr, // number of bytes that were written
nullptr)) // no overlapped structure)
{
SPDLOG_ERROR(TEXT("WriteFile [{0}] error: {1}"), cfgPath, GetLastError());
free(pBuf);
::CloseHandle(hFile);
return -ERR_OPEN_FILE;
}
::CloseHandle(hFile);
StringCbCopy(GetGlobalCfgInfo()->wgServerCfg.wgName, 260, pWgConfig->Name);
StringCbCopy(GetGlobalCfgInfo()->wgServerCfg.wgIpaddr, MAX_IP_LEN, pWgConfig->Address);
StringCbCopy(GetGlobalCfgInfo()->wgServerCfg.wgCfgPath, MAX_PATH, cfgPath);
return ERR_SUCCESS;
}
#if 0
/**
* @brief WireGuard
* @param[out] pPubKey
* @param[in] pubkeySize ()
* @param[out] pPrivKey
* @param[in] privKeySize ()
* @return 0: 0 @see USER_ERRNO
* - -ERR_ITEM_UNEXISTS WireGuard
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int GenerateWireguardKeyPairs(TCHAR *pPubKey, int pubkeySize, TCHAR *pPrivKey, int privKeySize) {
int ret;
DWORD retCode;
TCHAR cmdBuffer[MAX_PATH];
TCHAR cmdResult[MAX_PATH];
PSDK_CONFIG pCfg = GetGlobalCfgInfo();
// WireGuard 不存在或者未配置目录
if (!pCfg->wireguardCfg.wgExists || !pCfg->wireguardCfg.wireguardExists) {
return -ERR_ITEM_UNEXISTS;
}
memset(cmdBuffer, 0, MAX_PATH);
memset(cmdResult, 0, MAX_PATH);
StringCbPrintf(cmdBuffer, MAX_PATH, TEXT("cmd.exe /C \"%s\" genkey"), pCfg->wireguardCfg.wgPath);
if ((ret = RunCommand(cmdBuffer, cmdResult, MAX_PATH, &retCode)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Run command [{0}] error: {1}"), cmdBuffer, ret);
return -ERR_CALL_SHELL;
}
SPDLOG_DEBUG(TEXT("Run command [{0}] resutl \'{1}\'"), cmdBuffer, cmdResult);
StringCbCopy(pPrivKey, privKeySize, cmdResult);
memset(cmdBuffer, 0, MAX_PATH);
StringCbPrintf(cmdBuffer,
MAX_PATH,
TEXT("cmd.exe /C echo %s | \"%s\" pubkey"),
cmdResult,
pCfg->wireguardCfg.wgPath);
memset(cmdResult, 0, MAX_PATH);
if ((ret = RunCommand(cmdBuffer, cmdResult, MAX_PATH, &retCode)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Run command [{0}] error: {1}"), cmdBuffer, ret);
return -ERR_CALL_SHELL;
}
StringCbCopy(pPubKey, pubkeySize, cmdResult);
SPDLOG_DEBUG(TEXT("Run command [{0}] resutl \'{1}\'"), cmdBuffer, cmdResult);
return ERR_SUCCESS;
}
/**
* @brief wireguard.exe
* @param[in] pPath wireguard.exe
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_ITEM_UNEXISTS
* - ERR_SUCCESS
*/
int SetWireguardPath(const TCHAR *pPath) {
if (pPath == nullptr) {
return -ERR_INPUT_PARAMS;
}
if (PathFileExists(pPath)) {
TCHAR wgPath[MAX_PATH];
SPDLOG_DEBUG(TEXT("Used configure file:{0}"), GetGlobalCfgInfo()->cfgPath);
WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WIREGUARD_PATH, pPath, GetGlobalCfgInfo()->cfgPath);
SPDLOG_DEBUG(TEXT("Save configure: {1} --> {0}"), pPath, CFG_WIREGUARD_PATH);
StringCbCopy(wgPath, MAX_PATH, pPath);
if (TCHAR *pIndex = _tcsrchr(wgPath, '\\')) {
*pIndex = 0;
StringCbCat(wgPath, MAX_PATH, "\\wg.exe");
WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WG_PATH, wgPath, GetGlobalCfgInfo()->cfgPath);
SPDLOG_DEBUG(TEXT("Save configure: {1} --> {0}"), wgPath, CFG_WG_PATH);
}
return ERR_SUCCESS;
} else {
SPDLOG_ERROR(TEXT("WireGuard not found: {0}"), pPath);
return -ERR_ITEM_UNEXISTS;
}
}
/**
* @brief WireGuard
* @param[out] pFullPath wireguard.exe
* @param[in] maxSize pFullPath
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_MALLOC_MEMORY
* - -ERR_FILE_NOT_EXISTS
* - ERR_SUCCESS
*/
int FindWireguardExe(TCHAR *pFullPath, int maxSize) {
TCHAR path[MAX_PATH];
TCHAR wireguardPath[MAX_PATH];
DWORD dwRet;
LPSTR pEnvBuf;
TCHAR *token, *p = nullptr;
GetPrivateProfileString(CFG_WIREGUARD_SECTION,
CFG_WIREGUARD_PATH,
TEXT(""),
wireguardPath,
MAX_PATH,
GetGlobalCfgInfo()->cfgPath);
if (PathFileExists(wireguardPath)) {
if (pFullPath && maxSize > 0) {
StringCbCopy(pFullPath, maxSize, wireguardPath);
}
StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wireguardPath, MAX_PATH, wireguardPath);
GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE;
SPDLOG_DEBUG(TEXT("Ini found WireGuard at: {0}"), wireguardPath);
GetPrivateProfileString(CFG_WIREGUARD_SECTION,
CFG_WG_PATH,
TEXT(""),
wireguardPath,
MAX_PATH,
GetGlobalCfgInfo()->cfgPath);
if (PathFileExists(wireguardPath)) {
StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wgPath, MAX_PATH, wireguardPath);
GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE;
SPDLOG_DEBUG(TEXT("Ini found WireGuard Tools at: {0}"), wireguardPath);
}
return ERR_SUCCESS;
}
StringCbCopy(wireguardPath, MAX_PATH, GetGlobalCfgInfo()->systemDirectory);
PathStripToRoot(wireguardPath);
StringCbCat(wireguardPath, MAX_PATH, TEXT("Program Files\\WireGuard\\wireguard.exe"));
if (PathFileExists(wireguardPath)) {
// 保存路径到配置文件
SetWireguardPath(wireguardPath);
GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE;
PathRemoveFileSpec(wireguardPath);
StringCbCat(wireguardPath, MAX_PATH, TEXT("\\wg.exe"));
if (PathFileExists(wireguardPath)) {
GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE;
}
return ERR_SUCCESS;
}
// 从环境变量中查找
pEnvBuf = static_cast<LPSTR>(malloc(WINENVBUF_SIZE));
if (nullptr == pEnvBuf) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), WINENVBUF_SIZE);
return -ERR_MALLOC_MEMORY;
}
dwRet = GetEnvironmentVariable(TEXT("path"), pEnvBuf, WINENVBUF_SIZE);
if (0 == dwRet) {
DWORD dwErr;
dwErr = GetLastError();
if (ERROR_ENVVAR_NOT_FOUND == dwErr) {
SPDLOG_DEBUG(TEXT("Environment variable path does not exist."));
free(pEnvBuf);
return -ERR_FILE_NOT_EXISTS;
}
} else if (WINENVBUF_SIZE < dwRet) {
const auto pBuf = static_cast<LPSTR>(realloc(pEnvBuf, dwRet * sizeof(CHAR)));
if (nullptr == pBuf) {
SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), dwRet * sizeof(CHAR));
free(pEnvBuf);
return -ERR_MALLOC_MEMORY;
}
pEnvBuf = pBuf;
dwRet = GetEnvironmentVariable("path", pEnvBuf, dwRet);
if (!dwRet) {
SPDLOG_ERROR(TEXT("GetEnvironmentVariable failed (%d)"), GetLastError());
free(pEnvBuf);
return -ERR_FILE_NOT_EXISTS;
}
}
token = strtok_s(pEnvBuf, TEXT(";"), &p);
while (token != nullptr) {
memset(path, 0, MAX_PATH);
StringCbPrintfA(path, MAX_PATH, TEXT("%s\\wireguard.exe"), token);
if (PathFileExists(path)) {
if (pFullPath && maxSize > 0) {
StringCbCopy(pFullPath, maxSize, path);
}
// 保存路径到配置文件
SetWireguardPath(path);
SPDLOG_DEBUG(TEXT("Path Environment found WireGuard at: {0}"), path);
StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wireguardPath, MAX_PATH, wireguardPath);
GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE;
memset(path, 0, MAX_PATH);
StringCbPrintf(path, MAX_PATH, TEXT("%s\\wg.exe"), token);
SPDLOG_DEBUG(TEXT("Find WireGuard tools at: {0}"), path);
if (PathFileExists(path)) {
StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wgPath, MAX_PATH, path);
GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE;
SPDLOG_DEBUG(TEXT("Path Environment found WireGuard tools at: {0}"), path);
}
//TODO: throw exception by C# call, why??????
//CloseHandle(hFind);
free(pEnvBuf);
return ERR_SUCCESS;
}
token = strtok_s(nullptr, TEXT(";"), &p);
}
free(pEnvBuf);
return -ERR_FILE_NOT_EXISTS;
}
/**
* @brief Windows NAT PowerShell
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_OPEN_FILE
* - -ERR_MEMORY_STR
* - -ERR_ITEM_UNEXISTS
* - -ERR_CALL_SHELL
* - ERR_SUCCESS
*/
int InstallWindowsNATCommand() {
TCHAR psCmdPath[MAX_PATH];
// 如果已经安装则退出
if (IsCustomNatPSCmdInstalled()) {
return ERR_SUCCESS;
}
StringCbPrintf(psCmdPath,
MAX_PATH,
TEXT("%s\\system32\\WindowsPowerShell\\v1.0\\Modules\\wireguard\\wireguard.psm1"),
GetGlobalCfgInfo()->systemDirectory);
const HANDLE hFile = CreateFile(psCmdPath,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ,
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
SPDLOG_ERROR("CreatFile [{0}] error: {1}", psCmdPath, GetLastError());
return -ERR_OPEN_FILE;
}
const HMODULE hMod = GetModuleHandle(TEXT("NetTunnelSDK.dll"));
if (nullptr == hMod) {
SPDLOG_ERROR(TEXT("Load NetTunnelSDK.dll module error"));
::CloseHandle(hFile);
return -ERR_ITEM_UNEXISTS;
}
const HRSRC hRsrc = FindResource(hMod, MAKEINTRESOURCE(PSCMD_RES_ID), TEXT("TXT"));
if (nullptr == hRsrc) {
SPDLOG_ERROR(TEXT("Donot found resource {0} of type {1}"), PSCMD_RES_ID, TEXT("TXT"));
::CloseHandle(hFile);
return -ERR_ITEM_UNEXISTS;
}
const DWORD resSize = SizeofResource(hMod, hRsrc);
if (resSize == 0) {
SPDLOG_ERROR(TEXT("Resource {0} of type {1} is empty"), PSCMD_RES_ID, TEXT("TXT"));
::CloseHandle(hFile);
return -ERR_ITEM_UNEXISTS;
}
const HGLOBAL hGlobal = LoadResource(hMod, hRsrc);
if (hGlobal == hRsrc) {
SPDLOG_ERROR(TEXT("Load resource {0} of type {1} error"), PSCMD_RES_ID, TEXT("TXT"));
::CloseHandle(hFile);
return -ERR_ITEM_UNEXISTS;
}
if (const LPVOID pBuffer = LockResource(hGlobal)) {
if (!WriteFile(hFile, // open file handle
pBuffer, // start of data to write
static_cast<DWORD>(resSize), // number of bytes to write
nullptr, // number of bytes that were written
nullptr)) {
SPDLOG_ERROR("WriteFile [{0}] error: {1}", psCmdPath, GetLastError());
GlobalUnlock(hGlobal);
::CloseHandle(hFile);
return -ERR_OPEN_FILE;
}
}
GlobalUnlock(hGlobal);
::CloseHandle(hFile);
return ERR_SUCCESS;
}
int WireGuardNetConnectionSharingEnable() {
int ret;
DWORD retCode;
TCHAR cmdResult[MAX_PATH] = {};
TCHAR cmdBuf[] = TEXT("PowerShell -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass Invoke-Command -ArgumentList 'wg_cli' -ScriptBlock {param($IFNAME);$netShare = New-Object -ComObject HNetCfg.HNetShare;"
"$privateConnection = $netShare.EnumEveryConnection |? { $netShare.NetConnectionProps.Invoke($_).Name -eq 'wg_cli' };"
"$privateConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($privateConnection);"
"Write-Output $privateConfig}");
if ((ret = RunCommand(cmdBuf, cmdResult, MAX_PATH, &retCode)) != ERR_SUCCESS) {
SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuf, ret);
return -ERR_CALL_SHELL;
}
SPDLOG_DEBUG("Run command [{0}] resutl \'{1}\' return {2}", cmdBuf, cmdResult, retCode);
return ERR_SUCCESS;
}
#endif

View File

@ -0,0 +1,685 @@
#include "pch.h"
#include "tunnel.h"
#include "usrerr.h"
#include "globalcfg.h"
#include "httplib.h"
#include "misc.h"
#include "network.h"
#include "protocol.h"
#include "user.h"
#include <shlwapi.h>
#include <strsafe.h>
static HANDLE g_HeartTimerQueue = nullptr;
static LPTUNNEL_HEART_ROUTINE g_lpHeartCb = nullptr;
int RemoteHeartControl(bool isStart, LPTUNNEL_HEART_ROUTINE lpHeartCbAddress) {
if (isStart && lpHeartCbAddress == nullptr) {
SPDLOG_ERROR(TEXT("Input lpHeartCbAddress params nullptr"));
return -ERR_INPUT_PARAMS;
}
g_lpHeartCb = lpHeartCbAddress;
if (isStart) {
if (!g_HeartTimerQueue) {
HANDLE hTimer = nullptr;
// Create the timer queue.
g_HeartTimerQueue = CreateTimerQueue();
if (nullptr == g_HeartTimerQueue) {
SPDLOG_ERROR(TEXT("CreateTimerQueue failed ({0})"), GetLastError());
return -ERR_CREATE_TIMER;
}
// Set a timer to call the timer routine in 10 seconds.
if (!CreateTimerQueueTimer(
&hTimer,
g_HeartTimerQueue,
[](PVOID lpParam, BOOLEAN TimerOrWaitFired) {
int ret;
ProtocolRequest<ReqHeartParams> req;
ProtocolResponse<RspHeartParams> rsp;
ret = ProtolPostMessage(SET_CLIENTHEART_PATH, &req, &rsp, false);
if (g_lpHeartCb && ret) {
g_lpHeartCb(rsp.msgContent.message.c_str(), rsp.timeStamp);
}
},
nullptr,
0,
HEART_PERIOD_MS,
WT_EXECUTEDEFAULT)) {
SPDLOG_ERROR(TEXT("CreateTimerQueueTimer failed ({0})"), GetLastError());
return -ERR_CREATE_TIMER;
}
}
} else {
if (g_HeartTimerQueue) {
if (!DeleteTimerQueue(g_HeartTimerQueue)) {
SPDLOG_ERROR(TEXT("DeleteTimerQueue failed ({0})"), GetLastError());
g_HeartTimerQueue = nullptr;
return -ERR_DELETE_TIMER;
}
g_HeartTimerQueue = nullptr;
}
}
return ERR_SUCCESS;
}
int RemoteWireGuardControl(bool isStart) {
int ret;
ProtocolRequest<ReqStartTunnelParams> req;
ProtocolResponse<ResponseStatus> rsp;
req.msgContent.isStart = isStart;
ret = ProtolPostMessage(SET_CLIENTSTART_TUNNEL, &req, &rsp, false);
if (ret != ERR_SUCCESS) {
return ret;
}
if (rsp.msgContent.errCode != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Service Response error({0}): {1}"), rsp.msgContent.errCode, rsp.msgContent.errMessage);
return rsp.msgContent.errCode;
}
return ERR_SUCCESS;
}
int LocalWireGuardControl(bool isStart, bool setPrivateMode) {
int ret;
bool chkStatus = false;
int ifInetlnetIndex, ifWireGuardIndex;
// 获取 Intelnet 网络网卡 Index
if ((ret = GetInternetIfIndex(&ifInetlnetIndex)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetInternetIfIndex error: {0}"), ret);
return ret;
}
// 判断先前是否启动过服务
if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &chkStatus)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call IsWireGuardServerInstalled error: {0}"), ret);
return ret;
}
// 先停止以前启动的隧道服务
if (chkStatus) {
if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
// 返回停止服务失败
SPDLOG_ERROR(TEXT("Call WireGuardUnInstallServerService error: {0}"), ret);
return ret;
}
}
// 检查 Internet 网络共享状态
if ((ret = GetNetIntelnetConnectionSharing(ifInetlnetIndex, &chkStatus)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
// 关闭 Intelnet 网络连接共享
if (chkStatus) {
if ((ret = SetNetIntelnetConnectionSharing(ifInetlnetIndex, false, false)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
}
if (isStart) {
// 启动服务
ret = WireGuardInstallDefaultServerService(true);
if (ret != ERR_SUCCESS) {
// 返回启动服务失败
SPDLOG_ERROR(TEXT("Call WireGuardInstallDefaultServerService error: {0}"), ret);
return ret;
}
if (GetCurrentNetShareMode() == ICS_SHARE_MODE) {
// 获取 WireGuard 隧道网络网卡 Index
if ((ret = GetInterfaceIfIndexByName(GetGlobalCfgInfo()->userCfg.userName, &ifWireGuardIndex)) !=
ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetInterfaceIfIndexByName error: {0}"), ret);
return ret;
}
// 启动 WireGard 网络 ICS 服务为私有网络
if ((ret = SetNetIntelnetConnectionSharing(ifWireGuardIndex, true, true)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
// 启动 Intelnet 网络 ICS 服务为公共网络
if ((ret = SetNetIntelnetConnectionSharing(ifInetlnetIndex, true, false)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
// 校验 ICS 共享状态
// 检查 WireGuard 网络共享状态
if ((ret = GetNetIntelnetConnectionSharing(ifWireGuardIndex, &chkStatus)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
if (!chkStatus) {
SPDLOG_ERROR(TEXT("WireGuard network ICS error"));
return -ERR_NET_WIREGUARD_ICS;
}
// 检查 WireGuard 网络共享状态
if ((ret = GetNetIntelnetConnectionSharing(ifInetlnetIndex, &chkStatus)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
if (!chkStatus) {
SPDLOG_ERROR(TEXT("Internet network ICS error"));
return -ERR_NET_WIREGUARD_ICS;
}
SPDLOG_INFO(TEXT("Net Share Service Work now on ICS mode: {0}"), GetGlobalCfgInfo()->userCfg.userName);
} else if (GetCurrentNetShareMode() == NAT_SHARE_MODE) {
IP_INFO ipInfo;
TCHAR ipNat[MAX_IP_LEN];
GetIpV4InfoFromCIDR(GetGlobalCfgInfo()->userCfg.cliConfig.cliAddress, &ipInfo);
StringCbPrintf(ipNat, MAX_IP_LEN, TEXT("%s/%d"), ipInfo.hostmax, ipInfo.prefix);
// 检查 WireGuard 网络共享状态
if ((ret = SetNATRule(GetGlobalCfgInfo()->userCfg.userName, ipNat)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
SPDLOG_INFO(TEXT("Net Share Service Work now on NAT mode: {0}_nat --> {1}"),
GetGlobalCfgInfo()->userCfg.userName,
ipNat);
} else {
SPDLOG_ERROR(TEXT("Not support Net Share Type: {0}"), static_cast<int>(GetCurrentNetShareMode()));
return -ERR_UN_SUPPORT;
}
} else {
if (GetCurrentNetShareMode() == NAT_SHARE_MODE) {
// 检查 WireGuard 网络共享状态
if ((ret = RemoveNATRule(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call RemoveNATRule error: {0}"), ret);
return ret;
}
}
SPDLOG_INFO(TEXT("Net Share Service Stoped: {0}"), GetGlobalCfgInfo()->userCfg.userName);
}
return ERR_SUCCESS;
}
int RemoteCtrlSvrCfgUserTunnel(int vmId, const TCHAR *pCliNetwork) {
const PUSER_CONFIG pUser = &GetGlobalCfgInfo()->userCfg;
const PUSER_CLIENT_CONFIG pUserCfg = &pUser->cliConfig;
for (int i = 0; i < pUserCfg->tolVM; i++) {
if (pUserCfg->pVMConfig[i].vmId == vmId) {
IP_INFO ipInfo = {};
int ret;
ProtocolRequest<ReqUserSetCliCfgParams> req;
ProtocolResponse<RspUserSetCliCfgParams> rsp;
req.msgContent.cliPublicKey = pUserCfg->cliPublicKey;
req.msgContent.cliNetwork = pCliNetwork;
GetIpV4InfoFromCIDR(pUserCfg->cliAddress, &ipInfo);
req.msgContent.cliTunnelAddr = ipInfo.ip;
GetGlobalCfgInfo()->curConnVmId = vmId;
SPDLOG_DEBUG(TEXT("Current VMID: {0}"), vmId);
// 连接到服务端控制服务
InitControlServer(pUserCfg->pVMConfig[i].scgGateWay);
// 发送本地配置参数到控制服务
ret = ProtolPostMessage(SET_CLIENTCFG_PATH, &req, &rsp, false);
if (ret != ERR_SUCCESS) {
return ret;
}
if (rsp.msgContent.errCode != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Service Response error({0}): {1}"),
rsp.msgContent.errCode,
rsp.msgContent.errMessage);
return rsp.msgContent.errCode;
}
// 返回成功配置本地参数
ret = SetTunnelConfigure(pUserCfg->cliPrivateKey,
pUserCfg->pVMConfig[i].svrPublicKey,
pUserCfg->pVMConfig[i].vmNetwork,
pUserCfg->cliAddress,
rsp.msgContent.svrNetwork.c_str(),
pUserCfg->pVMConfig[i].scgTunnelGw);
if (ret != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("SetTunnelConfigure Error: {0}"), ret);
return ret;
}
return ERR_SUCCESS;
}
}
return -ERR_ITEM_UNEXISTS;
}
int SetTunnelConfigure(const TCHAR *pCliPrivateKey,
const TCHAR *pSvrPublicKey,
const TCHAR *pSvrNetwork,
const TCHAR *pCliNetwork,
const TCHAR *pSvrTunnelAddr,
const TCHAR *pSvrEndPoint) {
int ret;
bool isSvrStart = false;
int ifInetlnetIndex;
IP_INFO tunnelInfo = {};
IP_INFO svrInfo = {};
WGCLIENT_CONFIG cliCfg = {};
#pragma region
if (pCliPrivateKey == nullptr || lstrlen(pCliPrivateKey) == 0) {
SPDLOG_ERROR(TEXT("Input pCliPrivateKey error: {0}"), pCliPrivateKey);
return -ERR_INPUT_PARAMS;
}
if (pSvrPublicKey == nullptr || lstrlen(pSvrPublicKey) == 0) {
SPDLOG_ERROR(TEXT("Input pSvrPublicKey error: {0}"), pSvrPublicKey);
return -ERR_INPUT_PARAMS;
}
if (pSvrNetwork == nullptr || lstrlen(pSvrNetwork) == 0) {
SPDLOG_ERROR(TEXT("Input pSvrNetwork error: {0}"), pSvrNetwork);
return -ERR_INPUT_PARAMS;
}
if (pCliNetwork == nullptr || lstrlen(pCliNetwork) == 0) {
SPDLOG_ERROR(TEXT("Input pCliNetwork error: {0}"), pCliNetwork);
return -ERR_INPUT_PARAMS;
}
if (pSvrTunnelAddr == nullptr || lstrlen(pSvrTunnelAddr) == 0) {
SPDLOG_ERROR(TEXT("Input pSvrTunnelAddr error: {0}"), pSvrTunnelAddr);
return -ERR_INPUT_PARAMS;
}
if (pSvrEndPoint == nullptr || lstrlen(pSvrEndPoint) == 0) {
SPDLOG_ERROR(TEXT("Input pSvrEndPoint error: {0}"), pSvrEndPoint);
return -ERR_INPUT_PARAMS;
}
#pragma endregion 参数检查
// 判断先前是否启动过服务
if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &isSvrStart)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("IsWireGuardServerInstalled error: {0}"), ret);
return ret;
}
// 停止先前隧道网络
if (isSvrStart) {
SPDLOG_DEBUG(TEXT("WireGuardUnInstallServerService: {0}"), GetGlobalCfgInfo()->userCfg.userName);
if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
// 返回停止服务失败
SPDLOG_ERROR(TEXT("WireGuardUnInstallServerService error: {0}"), ret);
return ret;
}
}
// 获取 Intelnet 网络网卡 Index
if ((ret = GetInternetIfIndex(&ifInetlnetIndex)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetInternetIfIndex error: {0}"), ret);
return ret;
}
if (GetCurrentNetShareMode() == ICS_SHARE_MODE) {
// 检查 Internet 网络共享状态
if ((ret = GetNetIntelnetConnectionSharing(ifInetlnetIndex, &isSvrStart)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
// 关闭 Intelnet 网络连接共享
if (isSvrStart) {
if ((ret = SetNetIntelnetConnectionSharing(ifInetlnetIndex, false, false)) != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
return ret;
}
}
}
ret = GetIpV4InfoFromCIDR(pSvrTunnelAddr, &tunnelInfo);
if (ret != ERR_SUCCESS) {
return ret;
}
ret = GetIpV4InfoFromCIDR(pSvrNetwork, &svrInfo);
if (ret != ERR_SUCCESS) {
return ret;
}
memset(&cliCfg, 0, sizeof(WGCLIENT_CONFIG));
StringCbCopy(cliCfg.Name, 64, GetGlobalCfgInfo()->userCfg.userName);
StringCbCopy(cliCfg.PrivateKey, 64, pCliPrivateKey);
StringCbCopy(cliCfg.Address, 32, pCliNetwork);
StringCbCopy(cliCfg.SvrPubKey, 64, pSvrPublicKey);
if (UsedSCGProxy()) {
StringCbPrintf(cliCfg.ServerURL, 256, TEXT("127.0.0.1:%d"), GetGlobalCfgInfo()->scgProxy.proxyPort);
} else {
StringCbCopy(cliCfg.ServerURL, 256, pSvrEndPoint);
}
StringCbPrintf(cliCfg.AllowNet,
256,
TEXT("%s/%d,%s/%d"),
tunnelInfo.network,
tunnelInfo.prefix,
svrInfo.network,
svrInfo.prefix);
ret = WireGuardCreateClientConfig(&cliCfg);
if (ret != ERR_SUCCESS) {
return ret;
}
return ERR_SUCCESS;
}
int GetUserServerConfigure(const TCHAR *pUserName, const TCHAR *pToken, PUSER_SERVER_CONFIG *pSvrCfg) {
int ret;
PUSER_CONFIG pUser = &GetGlobalCfgInfo()->userCfg;
PUSER_SERVER_CONFIG pUserCfg = &pUser->svrConfig;
#if USER_REAL_PLATFORM
ProtocolRequest<ReqGetUserCfgParams> req;
ProtocolResponse<RspUserSevrCfgParams> rsp;
#else
PlatformReqServerCfgParms req;
PlatformRspServerCfgParams rsp;
#endif
if (pSvrCfg == nullptr) {
SPDLOG_ERROR(TEXT("Input pSvrCfg params error"));
return -ERR_INPUT_PARAMS;
}
if (pToken == nullptr || lstrlen(pToken) == 0) {
SPDLOG_ERROR(TEXT("Input pToken params error: {0}"), pToken);
return -ERR_INPUT_PARAMS;
}
if (pUserName && lstrlen(pUserName) > 0) {
memset(pUser->userName, 0, MAX_PATH);
StringCbCopy(pUser->userName, MAX_PATH, pUserName);
} else {
StringCbCopy(pUser->userName, MAX_PATH, TEXT("tunnel_svr"));
}
StringCbCopy(pUser->userToken, MAX_PATH, pToken);
#if USER_REAL_PLATFORM
req.msgContent.token = pToken;
req.msgContent.user = pUser->userName;
ret = ProtolPostMessage(GET_SERVERCFG_PATH, &req, &rsp, true);
if (ret != ERR_SUCCESS) {
return ret;
}
pUserCfg->svrListenPort = rsp.msgContent.svrListenPort;
StringCbCopy(pUserCfg->svrPrivateKey, 64, rsp.msgContent.svrPrivateKey.c_str());
StringCbCopy(pUserCfg->svrAddress, MAX_IP_LEN, rsp.msgContent.svrAddress.c_str());
#else
req.vmIp = pToken;
ret = PlatformProtolPostMessage(GET_SERVERCFG_PATH, &req, &rsp);
if (ret != ERR_SUCCESS) {
return ret;
}
ret = strtol(rsp.code.c_str(), nullptr, 10);
if (ret != 0) {
SPDLOG_ERROR(TEXT("Server response error code: {0}"), ret);
return -ERR_HTTP_SERVER_RSP;
}
pUserCfg->svrListenPort = rsp.data.svrPort;
StringCbCopy(pUserCfg->svrPrivateKey, 64, rsp.data.svrPriKey.c_str());
StringCbCopy(pUserCfg->svrAddress, MAX_IP_LEN, rsp.data.svrHost.c_str());
#endif
*pSvrCfg = pUserCfg;
return ERR_SUCCESS;
}
int GetUserClientConfigure(const TCHAR *pUserName, const TCHAR *pToken, PUSER_CLIENT_CONFIG *pCliCfg) {
PUSER_CONFIG pUser = &GetGlobalCfgInfo()->userCfg;
PUSER_CLIENT_CONFIG pUserCfg = &pUser->cliConfig;
TCHAR userPath[MAX_PATH];
int ret;
#if USER_REAL_PLATFORM
ProtocolRequest<ReqGetUserCfgParams> req;
ProtocolResponse<RspUsrCliConfigParams> rsp;
#else
PlatformReqClientCfgParms req;
PlatformRspClientCfgParams rsp;
#endif
if (pUserName == nullptr || lstrlen(pUserName) == 0) {
SPDLOG_ERROR(TEXT("Input pUserName params error: {0}"), pUserName);
return -ERR_INPUT_PARAMS;
}
if (pToken == nullptr || lstrlen(pToken) == 0) {
SPDLOG_ERROR(TEXT("Input pToken params error: {0}"), pToken);
return -ERR_INPUT_PARAMS;
}
if (pCliCfg == nullptr) {
SPDLOG_ERROR(TEXT("Input pCliCfg params error"));
return -ERR_INPUT_PARAMS;
}
StringCbPrintf(userPath, MAX_PATH, "%s\\%s", GetGlobalCfgInfo()->configDirectory, pUserName);
// 如果配置目录不存在则自动创建
if (!PathFileExists(userPath)) {
if (!CreateDirectory(userPath, nullptr)) {
SPDLOG_ERROR(TEXT("Create user {1} directory '{0}' error."), userPath, pUserName);
return -ERR_CREATE_FILE;
}
}
memset(pUser->userName, 0, MAX_PATH);
if (pUserName && lstrlen(pUserName) > 0) {
StringCbCopy(pUser->userName, MAX_PATH, pUserName);
}
StringCbCopy(pUser->userToken, MAX_PATH, pToken);
#if USER_REAL_PLATFORM
req.msgContent.token = pToken;
req.msgContent.user = pUserName;
ret = ProtolPostMessage(GET_CLIENTCFG_PATH, &req, &rsp, true);
if (ret != ERR_SUCCESS) {
return ret;
}
StringCbCopy(pUserCfg->cliPrivateKey, 64, rsp.msgContent.cliPrivateKey.c_str());
StringCbCopy(pUserCfg->cliPublicKey, 64, rsp.msgContent.cliPublicKey.c_str());
StringCbCopy(pUserCfg->cliAddress, MAX_IP_LEN, rsp.msgContent.cliAddress.c_str());
if (!rsp.msgContent.vmConfig.empty()) {
PVM_CFG pVm;
unsigned int memSize = sizeof(VM_CFG) * static_cast<UINT>(rsp.msgContent.vmConfig.size());
pUserCfg->pVMConfig = static_cast<PVM_CFG>(CoTaskMemAlloc(memSize));
if (pUserCfg->pVMConfig == nullptr) {
SPDLOG_ERROR(TEXT("Error allocating memory {0} bytes"), memSize);
return -ERR_MALLOC_MEMORY;
}
memset(pUserCfg->pVMConfig, 0, memSize);
pUserCfg->tolVM = static_cast<int>(rsp.msgContent.vmConfig.size());
pVm = pUserCfg->pVMConfig;
for (auto vm : rsp.msgContent.vmConfig) {
TCHAR tmpAddr[MAX_PATH];
pVm->vmId = vm.vmId;
StringCbCopy(pVm->vmName, MAX_PATH, vm.vmName.c_str());
StringCbCopy(pVm->svrPublicKey, 64, vm.svrPublicKey.c_str());
StringCbCopy(pVm->vmNetwork, MAX_IP_LEN, vm.vmNetwork.c_str());
//StringCbCopy(pVm->scgGateWay, MAX_PATH, vm.scgGateway.c_str());
StringCbPrintf(pVm->scgGateWay, MAX_PATH, TEXT("http://%s"), vm.scgGateway.c_str());
StringCbCopy(tmpAddr, MAX_PATH, vm.scgGateway.c_str());
httplib::Client cli(pVm->scgGateWay);
StringCbPrintf(pVm->scgTunnelGw, MAX_PATH, TEXT("%s:%d"), cli.host().c_str(), cli.port() - 1);
pVm++;
}
}
#else
req.userName = pUserName;
req.token = pToken;
ret = PlatformProtolPostMessage(GET_CLIENTCFG_PATH, &req, &rsp);
if (ret != ERR_SUCCESS) {
return ret;
}
ret = strtol(rsp.code.c_str(), nullptr, 10);
if (ret != 0) {
SPDLOG_ERROR(TEXT("Server response error code: {0}"), ret);
return -ERR_HTTP_SERVER_RSP;
}
StringCbCopy(pUserCfg->cliPrivateKey, 64, rsp.data.cliPriKey.c_str());
StringCbCopy(pUserCfg->cliPublicKey, 64, rsp.data.cliPubKey.c_str());
StringCbCopy(pUserCfg->cliAddress, MAX_IP_LEN, rsp.data.cliHost.c_str());
if (!rsp.data.vmInfoList.empty()) {
PVM_CFG pVm;
unsigned int memSize = sizeof(VM_CFG) * static_cast<UINT>(rsp.data.vmInfoList.size());
pUserCfg->pVMConfig = static_cast<PVM_CFG>(CoTaskMemAlloc(memSize));
if (pUserCfg->pVMConfig == nullptr) {
SPDLOG_ERROR(TEXT("Error allocating memory {0} bytes"), memSize);
return -ERR_MALLOC_MEMORY;
}
memset(pUserCfg->pVMConfig, 0, memSize);
pUserCfg->tolVM = static_cast<int>(rsp.data.vmInfoList.size());
pVm = pUserCfg->pVMConfig;
for (auto vm : rsp.data.vmInfoList) {
pVm->vmId = vm.vmId;
StringCbCopy(pVm->vmName, MAX_PATH, vm.vmName.c_str());
StringCbCopy(pVm->svrPublicKey, 64, vm.svrPubKey.c_str());
StringCbCopy(pVm->vmNetwork, MAX_IP_LEN, vm.vmNetwork.c_str());
//StringCbCopy(pVm->scgGateWay, MAX_PATH, vm.scgGateway.c_str());
StringCbPrintf(pVm->scgGateWay, MAX_PATH, TEXT("http://%s:%d"), vm.scgIp.c_str(), vm.scgPort);
#if USED_PORTMAP_TUNNEL
StringCbPrintf(pVm->scgTunnelGw, MAX_PATH, TEXT("%s:%d"), vm.portMapIp.c_str(), vm.portMapPort);
#else
StringCbPrintf(pVm->scgTunnelGw, MAX_PATH, TEXT("%s:%d"), vm.scgIp.c_str(), vm.scgPort - 1);
#endif
#if USED_PORTMAP_TUNNEL
#endif
pVm++;
}
}
#endif
*pCliCfg = pUserCfg;
return ERR_SUCCESS;
}
int GetUserConfigFiles(const TCHAR *pUserName, PUSER_CFGFILE *pCfgFile, int *pItems) {
PUSER_CFGFILE pCfg;
FILE_LIST fileList = {nullptr, 0};
TCHAR fnPath[MAX_PATH] = {};
TCHAR cfgVal[MAX_PATH];
bool isSelected = false;
if (pUserName == nullptr || lstrlen(pUserName) == 0) {
SPDLOG_ERROR(TEXT("Input pUserName params error: {0}"), pUserName);
return -ERR_INPUT_PARAMS;
}
if (pCfgFile == nullptr) {
SPDLOG_ERROR(TEXT("Input pCfgFile params error"));
return -ERR_INPUT_PARAMS;
}
if (pItems == nullptr) {
SPDLOG_ERROR(TEXT("Input pItems params error"));
return -ERR_INPUT_PARAMS;
}
GetPrivateProfileString(CFG_WIREGUARD_SECTION,
CFG_WGCFG_PATH,
TEXT(""),
cfgVal,
MAX_PATH,
GetGlobalCfgInfo()->cfgPath);
if (PathFileExists(cfgVal)) {
isSelected = true;
}
StringCbPrintf(fnPath, MAX_PATH, "%s\\%s\\*.conf", GetGlobalCfgInfo()->configDirectory, pUserName);
int ret = FindFile(fnPath, &fileList, false);
if (ret != ERR_SUCCESS) {
SPDLOG_ERROR(TEXT("Find WireGuard user {1} configure file error: {0}"), ret, pUserName);
return ret;
}
pCfg = static_cast<PUSER_CFGFILE>(CoTaskMemAlloc(sizeof(USER_CFGFILE) * fileList.nItems));
if (pCfg == nullptr) {
SPDLOG_ERROR(TEXT("Error allocating memory {0} bytes"), sizeof(USER_CFGFILE) * fileList.nItems);
return -ERR_SUCCESS;
}
memset(pCfg, 0, sizeof(USER_CFGFILE) * fileList.nItems);
*pCfgFile = pCfg;
*pItems = static_cast<int>(fileList.nItems);
for (unsigned int i = 0; fileList.pFilePath && i < fileList.nItems; i++) {
StringCbCopy(pCfg->CfgPath, MAX_PATH, fileList.pFilePath[i].path);
if (isSelected && StrCmp(pCfg->CfgPath, cfgVal) == 0) {
pCfg->isCurrent = true;
} else {
pCfg->isCurrent = false;
}
pCfg++;
}
if (fileList.pFilePath) {
HeapFree(GetProcessHeap(), 0, fileList.pFilePath);
}
return ERR_SUCCESS;
}

View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.22)
project(NetTunnelServerApp)
set(CMAKE_CXX_STANDARD 23)
add_definitions(-D_UNICODE)
find_package(spdlog CONFIG REQUIRED)
add_executable(NetTunnelServerApp NetTunnelServerApp.cpp)
target_link_libraries(NetTunnelServerApp PRIVATE spdlog::spdlog)
SET_TARGET_PROPERTIES(NetTunnelServerApp PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")

View File

@ -0,0 +1,39 @@
#include <Windows.h>
#include <strsafe.h>
#include <tchar.h>
#include <spdlog/spdlog.h>
#include <conio.h>
#pragma comment(linker, "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
int _tmain(int wargc, _TCHAR *wargv[]) {
int ret;
// PUSER_SERVER_CONFIG pSvrCfg;
//
// //https://xajhuang.com:9276
// //http://172.21.40.39:32549
// if ((ret = TunnelSDKInitEnv(nullptr, "https://112.17.28.201:1443", nullptr, LOG_DEBUG, true)) != ERR_SUCCESS) {
// wprintf(L"Init SCC SDK Error: %d\n", ret);
// return -1;
// }
//
// EnableVerifySignature("sc-winvdisdk-efa9v12xwtz5eppr", "lh5r8sw6m9m416nm");
//
// if (ERR_SUCCESS != (ret = GetUserServerConfigure("tunnel_svr", "172.21.97.100", &pSvrCfg))) {
// wprintf(L"GetUserServerConfigure Error: %d\n", ret);
// return -2;
// }
//
// if (ERR_SUCCESS != (ret = CreateControlService(pSvrCfg))) {
// wprintf(L"CreateControlService Error: %d\n", ret);
// return -2;
// }
wprintf(L"Press Key 'X' to exit......\n");
do {
ret = _getch();
} while (ret != 'X' && ret != 'x');
return 0;
}

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.22)
project(NetTunnelSvr)
set(CMAKE_CXX_STANDARD 23)
add_definitions(-D_UNICODE)
add_executable(NetTunnelSvr NetTunnelSvr.cpp)
SET_TARGET_PROPERTIES(NetTunnelSvr PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")

View File

@ -0,0 +1,106 @@
#include <Windows.h>
#include <strsafe.h>
#include <tchar.h>
#define WG_TUNNEL_SVR_NAME TEXT("WireGuard_DLL_SVR")
typedef BOOL(WINAPI WIREGUARD_TUNNEL_SERVICE_FUNC)(_In_z_ LPCWSTR Name);
static WIREGUARD_TUNNEL_SERVICE_FUNC *WireGuardTunnelService;
static void LogToSystemEventLog(int wErrorType, int wCustumerCode, const TCHAR *szMsg) {
HANDLE hEventSource;
DWORD dwEventIdentifer;
switch (wErrorType) {
case EVENTLOG_SUCCESS:
case EVENTLOG_AUDIT_SUCCESS:
dwEventIdentifer = 0x00;
break;
case EVENTLOG_INFORMATION_TYPE:
dwEventIdentifer = 0x01;
break;
case EVENTLOG_WARNING_TYPE:
dwEventIdentifer = 0x02;
break;
case EVENTLOG_ERROR_TYPE:
case EVENTLOG_AUDIT_FAILURE:
dwEventIdentifer = 0x03;
break;
default:
dwEventIdentifer = 0;
break;
}
// 移位获得Sev前面给出的 wErrorType 为 EVENTLOG_ERROR_TYPE对应着下图 “级别” 一列显示“错误”图标
dwEventIdentifer <<= 30;
dwEventIdentifer |= static_cast<WORD>(wCustumerCode); // 前面自定义了Code对应着下图中 事件ID 20
hEventSource = RegisterEventSource(nullptr, WG_TUNNEL_SVR_NAME);
if (nullptr != hEventSource) {
LPCTSTR lpszStrings[2] = {
WG_TUNNEL_SVR_NAME,
szMsg}; //要写入日志的信息有两行,分别是 服务名和前面给出的szMsg对应着下图“以下是包含在事件中的信息”
ReportEvent(hEventSource, // event log handle
wErrorType, // event type
0, // event category
dwEventIdentifer, // event identifier
nullptr, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
nullptr); // no binary data
DeregisterEventSource(hEventSource);
}
}
static HMODULE InitializeTunnelLibrary() {
const HMODULE tunnel = LoadLibraryExW(L"tunnel.dll", nullptr,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!tunnel) {
TCHAR tMsg[MAX_PATH * sizeof(TCHAR)];
StringCbPrintf(tMsg, MAX_PATH * sizeof(TCHAR), TEXT("LoadLibraryExW Error: %d\n"), GetLastError());
LogToSystemEventLog(EVENTLOG_ERROR_TYPE, 0x01, tMsg);
return nullptr;
}
#define X(Name) ((*(FARPROC *)&(Name) = GetProcAddress(tunnel, #Name)) == nullptr)
if (X(WireGuardTunnelService))
#undef X
{
const DWORD LastError = GetLastError();
FreeLibrary(tunnel);
SetLastError(LastError);
return nullptr;
}
return tunnel;
}
int _tmain(int wargc, _TCHAR *wargv[]) {
TCHAR tMsg[MAX_PATH] = {};
if (wargc == 3 && !wcscmp(wargv[1], L"/service")) {
BOOL ret;
const HMODULE hModule = InitializeTunnelLibrary();
if (!hModule || !WireGuardTunnelService) {
StringCbPrintf(tMsg, MAX_PATH, TEXT("Init WireGuardTunnelService Service Error: %d\n"), GetLastError());
LogToSystemEventLog(EVENTLOG_ERROR_TYPE, 0x01, tMsg);
return -1;
}
ret = WireGuardTunnelService(wargv[2]);
if (ret) {
StringCbPrintf(tMsg, MAX_PATH, TEXT("Start WireGuardTunnelService Service Successed\n"));
LogToSystemEventLog(EVENTLOG_INFORMATION_TYPE, 0x00, tMsg);
} else {
StringCbPrintf(tMsg, MAX_PATH, TEXT("Start WireGuardTunnelService Service failed: %d\n"), GetLastError());
LogToSystemEventLog(EVENTLOG_ERROR_TYPE, 0x02, tMsg);
}
return ret;
}
return 0;
}

View File

@ -0,0 +1,630 @@
/*
* windivert.h
* (C) 2019, all rights reserved,
*
* This file is part of WinDivert.
*
* WinDivert is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* WinDivert is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __WINDIVERT_H
#define __WINDIVERT_H
#ifndef WINDIVERT_KERNEL
#include <windows.h>
#endif /* WINDIVERT_KERNEL */
#ifndef WINDIVERTEXPORT
#define WINDIVERTEXPORT extern __declspec(dllimport)
#endif /* WINDIVERTEXPORT */
#ifdef __MINGW32__
#define __in
#define __in_opt
#define __out
#define __out_opt
#define __inout
#define __inout_opt
#include <stdint.h>
#define INT8 int8_t
#define UINT8 uint8_t
#define INT16 int16_t
#define UINT16 uint16_t
#define INT32 int32_t
#define UINT32 uint32_t
#define INT64 int64_t
#define UINT64 uint64_t
#endif /* __MINGW32__ */
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************/
/* WINDIVERT API */
/****************************************************************************/
/*
* WinDivert layers.
*/
typedef enum
{
WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
* WinDivert NETWORK and NETWORK_FORWARD layer data.
*/
typedef struct
{
UINT32 IfIdx; /* Packet's interface index. */
UINT32 SubIfIdx; /* Packet's sub-interface index. */
} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK;
/*
* WinDivert FLOW layer data.
*/
typedef struct
{
UINT64 EndpointId; /* Endpoint ID. */
UINT64 ParentEndpointId; /* Parent endpoint ID. */
UINT32 ProcessId; /* Process ID. */
UINT32 LocalAddr[4]; /* Local address. */
UINT32 RemoteAddr[4]; /* Remote address. */
UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */
} WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW;
/*
* WinDivert SOCKET layer data.
*/
typedef struct
{
UINT64 EndpointId; /* Endpoint ID. */
UINT64 ParentEndpointId; /* Parent Endpoint ID. */
UINT32 ProcessId; /* Process ID. */
UINT32 LocalAddr[4]; /* Local address. */
UINT32 RemoteAddr[4]; /* Remote address. */
UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */
} WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET;
/*
* WinDivert REFLECTION layer data.
*/
typedef struct
{
INT64 Timestamp; /* Handle open time. */
UINT32 ProcessId; /* Handle process ID. */
WINDIVERT_LAYER Layer; /* Handle layer. */
UINT64 Flags; /* Handle flags. */
INT16 Priority; /* Handle priority. */
} WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT;
/*
* WinDivert address.
*/
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4201)
#endif
typedef struct
{
INT64 Timestamp; /* Packet's timestamp. */
UINT32 Layer:8; /* Packet's layer. */
UINT32 Event:8; /* Packet event. */
UINT32 Sniffed:1; /* Packet was sniffed? */
UINT32 Outbound:1; /* Packet is outound? */
UINT32 Loopback:1; /* Packet is loopback? */
UINT32 Impostor:1; /* Packet is impostor? */
UINT32 IPv6:1; /* Packet is IPv6? */
UINT32 IPChecksum:1; /* Packet has valid IPv4 checksum? */
UINT32 TCPChecksum:1; /* Packet has valid TCP checksum? */
UINT32 UDPChecksum:1; /* Packet has valid UDP checksum? */
UINT32 Reserved1:8;
UINT32 Reserved2;
union
{
WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */
WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */
WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */
UINT8 Reserved3[64];
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/*
* WinDivert events.
*/
typedef enum
{
WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */
WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */
WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */
WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
* WinDivert flags.
*/
#define WINDIVERT_FLAG_SNIFF 0x0001
#define WINDIVERT_FLAG_DROP 0x0002
#define WINDIVERT_FLAG_RECV_ONLY 0x0004
#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
#define WINDIVERT_FLAG_SEND_ONLY 0x0008
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
#define WINDIVERT_FLAG_NO_INSTALL 0x0010
#define WINDIVERT_FLAG_FRAGMENTS 0x0020
/*
* WinDivert parameters.
*/
typedef enum
{
WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */
WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */
WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */
WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */
WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */
} WINDIVERT_PARAM, *PWINDIVERT_PARAM;
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR
/*
* WinDivert shutdown parameter.
*/
typedef enum
{
WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN;
#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
#ifndef WINDIVERT_KERNEL
/*
* Open a WinDivert handle.
*/
WINDIVERTEXPORT HANDLE WinDivertOpen(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__in INT16 priority,
__in UINT64 flags);
/*
* Receive (read) a packet from a WinDivert handle.
*/
WINDIVERTEXPORT BOOL WinDivertRecv(
__in HANDLE handle,
__out_opt VOID *pPacket,
__in UINT packetLen,
__out_opt UINT *pRecvLen,
__out_opt WINDIVERT_ADDRESS *pAddr);
/*
* Receive (read) a packet from a WinDivert handle.
*/
WINDIVERTEXPORT BOOL WinDivertRecvEx(
__in HANDLE handle,
__out_opt VOID *pPacket,
__in UINT packetLen,
__out_opt UINT *pRecvLen,
__in UINT64 flags,
__out WINDIVERT_ADDRESS *pAddr,
__inout_opt UINT *pAddrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
/*
* Send (write/inject) a packet to a WinDivert handle.
*/
WINDIVERTEXPORT BOOL WinDivertSend(
__in HANDLE handle,
__in const VOID *pPacket,
__in UINT packetLen,
__out_opt UINT *pSendLen,
__in const WINDIVERT_ADDRESS *pAddr);
/*
* Send (write/inject) a packet to a WinDivert handle.
*/
WINDIVERTEXPORT BOOL WinDivertSendEx(
__in HANDLE handle,
__in const VOID *pPacket,
__in UINT packetLen,
__out_opt UINT *pSendLen,
__in UINT64 flags,
__in const WINDIVERT_ADDRESS *pAddr,
__in UINT addrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
/*
* Shutdown a WinDivert handle.
*/
WINDIVERTEXPORT BOOL WinDivertShutdown(
__in HANDLE handle,
__in WINDIVERT_SHUTDOWN how);
/*
* Close a WinDivert handle.
*/
WINDIVERTEXPORT BOOL WinDivertClose(
__in HANDLE handle);
/*
* Set a WinDivert handle parameter.
*/
WINDIVERTEXPORT BOOL WinDivertSetParam(
__in HANDLE handle,
__in WINDIVERT_PARAM param,
__in UINT64 value);
/*
* Get a WinDivert handle parameter.
*/
WINDIVERTEXPORT BOOL WinDivertGetParam(
__in HANDLE handle,
__in WINDIVERT_PARAM param,
__out UINT64 *pValue);
#endif /* WINDIVERT_KERNEL */
/*
* WinDivert constants.
*/
#define WINDIVERT_PRIORITY_HIGHEST 30000
#define WINDIVERT_PRIORITY_LOWEST (-WINDIVERT_PRIORITY_HIGHEST)
#define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096
#define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32
#define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384
#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */
#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */
#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */
#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */
#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */
#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */
#define WINDIVERT_BATCH_MAX 0xFF /* 255 */
#define WINDIVERT_MTU_MAX (40 + 0xFFFF)
/****************************************************************************/
/* WINDIVERT HELPER API */
/****************************************************************************/
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4214)
#endif
/*
* IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions.
*/
typedef struct
{
UINT8 HdrLength:4;
UINT8 Version:4;
UINT8 TOS;
UINT16 Length;
UINT16 Id;
UINT16 FragOff0;
UINT8 TTL;
UINT8 Protocol;
UINT16 Checksum;
UINT32 SrcAddr;
UINT32 DstAddr;
} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR;
#define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \
(((hdr)->FragOff0) & 0xFF1F)
#define WINDIVERT_IPHDR_GET_MF(hdr) \
((((hdr)->FragOff0) & 0x0020) != 0)
#define WINDIVERT_IPHDR_GET_DF(hdr) \
((((hdr)->FragOff0) & 0x0040) != 0)
#define WINDIVERT_IPHDR_GET_RESERVED(hdr) \
((((hdr)->FragOff0) & 0x0080) != 0)
#define WINDIVERT_IPHDR_SET_FRAGOFF(hdr, val) \
do \
{ \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \
((val) & 0xFF1F); \
} \
while (FALSE)
#define WINDIVERT_IPHDR_SET_MF(hdr, val) \
do \
{ \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \
(((val) & 0x0001) << 5); \
} \
while (FALSE)
#define WINDIVERT_IPHDR_SET_DF(hdr, val) \
do \
{ \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \
(((val) & 0x0001) << 6); \
} \
while (FALSE)
#define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \
do \
{ \
(hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \
(((val) & 0x0001) << 7); \
} \
while (FALSE)
typedef struct
{
UINT8 TrafficClass0:4;
UINT8 Version:4;
UINT8 FlowLabel0:4;
UINT8 TrafficClass1:4;
UINT16 FlowLabel1;
UINT16 Length;
UINT8 NextHdr;
UINT8 HopLimit;
UINT32 SrcAddr[4];
UINT32 DstAddr[4];
} WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR;
#define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \
((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1))
#define WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr) \
((((UINT32)(hdr)->FlowLabel0) << 16) | ((UINT32)(hdr)->FlowLabel1))
#define WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val) \
do \
{ \
(hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \
(hdr)->TrafficClass1 = (UINT8)(val); \
} \
while (FALSE)
#define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \
do \
{ \
(hdr)->FlowLabel0 = (UINT8)((val) >> 16); \
(hdr)->FlowLabel1 = (UINT16)(val); \
} \
while (FALSE)
typedef struct
{
UINT8 Type;
UINT8 Code;
UINT16 Checksum;
UINT32 Body;
} WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR;
typedef struct
{
UINT8 Type;
UINT8 Code;
UINT16 Checksum;
UINT32 Body;
} WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR;
typedef struct
{
UINT16 SrcPort;
UINT16 DstPort;
UINT32 SeqNum;
UINT32 AckNum;
UINT16 Reserved1:4;
UINT16 HdrLength:4;
UINT16 Fin:1;
UINT16 Syn:1;
UINT16 Rst:1;
UINT16 Psh:1;
UINT16 Ack:1;
UINT16 Urg:1;
UINT16 Reserved2:2;
UINT16 Window;
UINT16 Checksum;
UINT16 UrgPtr;
} WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR;
typedef struct
{
UINT16 SrcPort;
UINT16 DstPort;
UINT16 Length;
UINT16 Checksum;
} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/*
* Flags for WinDivertHelperCalcChecksums()
*/
#define WINDIVERT_HELPER_NO_IP_CHECKSUM 1
#define WINDIVERT_HELPER_NO_ICMP_CHECKSUM 2
#define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4
#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8
#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16
#ifndef WINDIVERT_KERNEL
/*
* Hash a packet.
*/
WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket(
__in const VOID *pPacket,
__in UINT packetLen,
__in UINT64 seed
#ifdef __cplusplus
= 0
#endif
);
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
WINDIVERTEXPORT BOOL WinDivertHelperParsePacket(
__in const VOID *pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_IPHDR *ppIpHdr,
__out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
__out_opt UINT8 *pProtocol,
__out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr,
__out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
__out_opt PWINDIVERT_TCPHDR *ppTcpHdr,
__out_opt PWINDIVERT_UDPHDR *ppUdpHdr,
__out_opt PVOID *ppData,
__out_opt UINT *pDataLen,
__out_opt PVOID *ppNext,
__out_opt UINT *pNextLen);
/*
* Parse an IPv4 address.
*/
WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address(
__in const char *addrStr,
__out_opt UINT32 *pAddr);
/*
* Parse an IPv6 address.
*/
WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address(
__in const char *addrStr,
__out_opt UINT32 *pAddr);
/*
* Format an IPv4 address.
*/
WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address(
__in UINT32 addr,
__out char *buffer,
__in UINT bufLen);
/*
* Format an IPv6 address.
*/
WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address(
__in const UINT32 *pAddr,
__out char *buffer,
__in UINT bufLen);
/*
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/
WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums(
__inout VOID *pPacket,
__in UINT packetLen,
__out_opt WINDIVERT_ADDRESS *pAddr,
__in UINT64 flags);
/*
* Decrement the TTL/HopLimit.
*/
WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL(
__inout VOID *pPacket,
__in UINT packetLen);
/*
* Compile the given filter string.
*/
WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__out_opt char *object,
__in UINT objLen,
__out_opt const char **errorStr,
__out_opt UINT *errorPos);
/*
* Evaluate the given filter string.
*/
WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in const char *filter,
__in const VOID *pPacket,
__in UINT packetLen,
__in const WINDIVERT_ADDRESS *pAddr);
/*
* Format the given filter string.
*/
WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__out char *buffer,
__in UINT bufLen);
/*
* Byte ordering.
*/
WINDIVERTEXPORT UINT16 WinDivertHelperNtohs(
__in UINT16 x);
WINDIVERTEXPORT UINT16 WinDivertHelperHtons(
__in UINT16 x);
WINDIVERTEXPORT UINT32 WinDivertHelperNtohl(
__in UINT32 x);
WINDIVERTEXPORT UINT32 WinDivertHelperHtonl(
__in UINT32 x);
WINDIVERTEXPORT UINT64 WinDivertHelperNtohll(
__in UINT64 x);
WINDIVERTEXPORT UINT64 WinDivertHelperHtonll(
__in UINT64 x);
WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address(
__in const UINT *inAddr,
__out UINT *outAddr);
WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address(
__in const UINT *inAddr,
__out UINT *outAddr);
/*
* Old names to be removed in the next version.
*/
WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address(
__in const UINT *inAddr,
__out UINT *outAddr);
WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address(
__in const UINT *inAddr,
__out UINT *outAddr);
#endif /* WINDIVERT_KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* __WINDIVERT_H */

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,308 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#pragma once
#include <winsock2.h>
#include <windows.h>
#include <ipexport.h>
#include <ifdef.h>
#include <ws2ipdef.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ALIGNED
# if defined(_MSC_VER)
# define ALIGNED(n) __declspec(align(n))
# elif defined(__GNUC__)
# define ALIGNED(n) __attribute__((aligned(n)))
# else
# error "Unable to define ALIGNED"
# endif
#endif
/* MinGW is missing this one, unfortunately. */
#ifndef _Post_maybenull_
# define _Post_maybenull_
#endif
#pragma warning(push)
#pragma warning(disable : 4324) /* structure was padded due to alignment specifier */
/**
* A handle representing WireGuard adapter
*/
typedef struct _WIREGUARD_ADAPTER *WIREGUARD_ADAPTER_HANDLE;
/**
* Creates a new WireGuard adapter.
*
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @param TunnelType Name of the adapter tunnel type. 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.
*
* @return If the function succeeds, the return value is the adapter handle. Must be released with
* WireGuardCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
* GetLastError.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_CREATE_ADAPTER_FUNC)
(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID);
/**
* Opens an existing WireGuard adapter.
*
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @return If the function succeeds, the return value is the adapter handle. Must be released with
* WireGuardCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
* GetLastError.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name);
/**
* Releases WireGuard adapter resources and, if adapter was created with WireGuardCreateAdapter, removes adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter.
*/
typedef VOID(WINAPI WIREGUARD_CLOSE_ADAPTER_FUNC)(_In_opt_ WIREGUARD_ADAPTER_HANDLE Adapter);
/**
* Deletes the WireGuard driver if there are no more adapters in use.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_DELETE_DRIVER_FUNC)(VOID);
/**
* Returns the LUID of the adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param Luid Pointer to LUID to receive adapter LUID.
*/
typedef VOID(WINAPI WIREGUARD_GET_ADAPTER_LUID_FUNC)(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
/**
* Determines the version of the WireGuard driver currently 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 WireGuard not loaded
*/
typedef _Return_type_success_(return != 0)
DWORD(WINAPI WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID);
/**
* Determines the level of logging, passed to WIREGUARD_LOGGER_CALLBACK.
*/
typedef enum
{
WIREGUARD_LOG_INFO, /**< Informational */
WIREGUARD_LOG_WARN, /**< Warning */
WIREGUARD_LOG_ERR /**< Error */
} WIREGUARD_LOGGER_LEVEL;
/**
* Called by internal logger to report diagnostic messages
*
* @param Level Message level.
*
* @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC.
*
* @param Message Message text.
*/
typedef VOID(CALLBACK *WIREGUARD_LOGGER_CALLBACK)(
_In_ WIREGUARD_LOGGER_LEVEL Level,
_In_ DWORD64 Timestamp,
_In_z_ LPCWSTR Message);
/**
* Sets logger callback function.
*
* @param NewLogger Pointer to callback function to use as a new global logger. NewLogger may be called from various
* threads concurrently. Should the logging require serialization, you must handle serialization in
* NewLogger. Set to NULL to disable.
*/
typedef VOID(WINAPI WIREGUARD_SET_LOGGER_FUNC)(_In_ WIREGUARD_LOGGER_CALLBACK NewLogger);
/**
* Whether and how logs from the driver are collected for the callback function.
*/
typedef enum
{
WIREGUARD_ADAPTER_LOG_OFF, /**< No logs are generated from the driver. */
WIREGUARD_ADAPTER_LOG_ON, /**< Logs are generated from the driver. */
WIREGUARD_ADAPTER_LOG_ON_WITH_PREFIX /**< Logs are generated from the driver, index-prefixed. */
} WIREGUARD_ADAPTER_LOG_STATE;
/**
* Sets whether and how the adapter logs to the logger previously set up with WireGuardSetLogger.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param LogState Adapter logging state.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_SET_ADAPTER_LOGGING_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_ WIREGUARD_ADAPTER_LOG_STATE LogState);
/**
* Determines the state of the adapter.
*/
typedef enum
{
WIREGUARD_ADAPTER_STATE_DOWN, /**< Down */
WIREGUARD_ADAPTER_STATE_UP, /**< Up */
} WIREGUARD_ADAPTER_STATE;
/**
* Sets the adapter state of the WireGuard adapter. Note: sockets are owned by the process that sets the state to up.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param State Adapter state.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_SET_ADAPTER_STATE_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_ WIREGUARD_ADAPTER_STATE State);
/**
* Gets the adapter state of the WireGuard adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param State Pointer to adapter state.
*
* @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 _Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_GET_ADAPTER_STATE_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _Out_ WIREGUARD_ADAPTER_STATE *State);
#define WIREGUARD_KEY_LENGTH 32
typedef struct _WIREGUARD_ALLOWED_IP WIREGUARD_ALLOWED_IP;
struct ALIGNED(8) _WIREGUARD_ALLOWED_IP
{
union
{
IN_ADDR V4;
IN6_ADDR V6;
} Address; /**< IP address */
ADDRESS_FAMILY AddressFamily; /**< Address family, either AF_INET or AF_INET6 */
BYTE Cidr; /**< CIDR of allowed IPs */
};
typedef enum
{
WIREGUARD_PEER_HAS_PUBLIC_KEY = 1 << 0, /**< The PublicKey field is set */
WIREGUARD_PEER_HAS_PRESHARED_KEY = 1 << 1, /**< The PresharedKey field is set */
WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE = 1 << 2, /**< The PersistentKeepAlive field is set */
WIREGUARD_PEER_HAS_ENDPOINT = 1 << 3, /**< The Endpoint field is set */
WIREGUARD_PEER_REPLACE_ALLOWED_IPS = 1 << 5, /**< Remove all allowed IPs before adding new ones */
WIREGUARD_PEER_REMOVE = 1 << 6, /**< Remove specified peer */
WIREGUARD_PEER_UPDATE = 1 << 7 /**< Do not add a new peer */
} WIREGUARD_PEER_FLAG;
typedef struct _WIREGUARD_PEER WIREGUARD_PEER;
struct ALIGNED(8) _WIREGUARD_PEER
{
WIREGUARD_PEER_FLAG Flags; /**< Bitwise combination of flags */
DWORD Reserved; /**< Reserved; must be zero */
BYTE PublicKey[WIREGUARD_KEY_LENGTH]; /**< Public key, the peer's primary identifier */
BYTE PresharedKey[WIREGUARD_KEY_LENGTH]; /**< Preshared key for additional layer of post-quantum resistance */
WORD PersistentKeepalive; /**< Seconds interval, or 0 to disable */
SOCKADDR_INET Endpoint; /**< Endpoint, with IP address and UDP port number*/
DWORD64 TxBytes; /**< Number of bytes transmitted */
DWORD64 RxBytes; /**< Number of bytes received */
DWORD64 LastHandshake; /**< Time of the last handshake, in 100ns intervals since 1601-01-01 UTC */
DWORD AllowedIPsCount; /**< Number of allowed IP structs following this struct */
};
typedef enum
{
WIREGUARD_INTERFACE_HAS_PUBLIC_KEY = (1 << 0), /**< The PublicKey field is set */
WIREGUARD_INTERFACE_HAS_PRIVATE_KEY = (1 << 1), /**< The PrivateKey field is set */
WIREGUARD_INTERFACE_HAS_LISTEN_PORT = (1 << 2), /**< The ListenPort field is set */
WIREGUARD_INTERFACE_REPLACE_PEERS = (1 << 3) /**< Remove all peers before adding new ones */
} WIREGUARD_INTERFACE_FLAG;
typedef struct _WIREGUARD_INTERFACE WIREGUARD_INTERFACE;
struct ALIGNED(8) _WIREGUARD_INTERFACE
{
WIREGUARD_INTERFACE_FLAG Flags; /**< Bitwise combination of flags */
WORD ListenPort; /**< Port for UDP listen socket, or 0 to choose randomly */
BYTE PrivateKey[WIREGUARD_KEY_LENGTH]; /**< Private key of interface */
BYTE PublicKey[WIREGUARD_KEY_LENGTH]; /**< Corresponding public key of private key */
DWORD PeersCount; /**< Number of peer structs following this struct */
};
/**
* Sets the configuration of the WireGuard adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param Config Configuration for the adapter.
*
* @param Bytes Number of bytes in Config allocation.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_SET_CONFIGURATION_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_reads_bytes_(Bytes) const WIREGUARD_INTERFACE *Config, _In_ DWORD Bytes);
/**
* Gets the configuration of the WireGuard adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param Config Configuration for the adapter.
*
* @param Bytes Pointer to number of bytes in Config allocation.
*
* @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, which if ERROR_MORE_DATA, Bytes is updated with the
* required size.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_GET_CONFIGURATION_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter,
_Out_writes_bytes_all_(*Bytes) WIREGUARD_INTERFACE *Config,
_Inout_ DWORD *Bytes);
#pragma warning(pop)
#ifdef __cplusplus
}
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

6
scripts/cleansdk.bat Normal file
View File

@ -0,0 +1,6 @@
@echo off
setlocal EnableDelayedExpansion
set "CurrCD=%~dp0"
powershell -Command "& {Remove-Item sdk/*}"

8
scripts/gensdk.bat Normal file
View File

@ -0,0 +1,8 @@
@echo off
setlocal EnableDelayedExpansion
set "CurrCD=%~dp0"
for /f %%i in ('dir sdk /b /s') do (
powershell -Command "& {$fileContent = Get-Content -Path %%i;$newContent = $fileContent -replace 'TCHAR', 'CHAR ';$newContent | Set-Content -Path %%i}"
)

22
vcpkg.json Normal file
View File

@ -0,0 +1,22 @@
{
"name" : "scc",
"version-string" : "1.0.0",
"builtin-baseline" : "662dbb50e63af15baa2909b7eac5b1b87e86a0aa",
"dependencies" : [ {
"name" : "spdlog",
"version>=" : "1.11.0#1",
"$comment" : " find_package(spdlog CONFIG REQUIRED)\n\n target_link_libraries(main PRIVATE spdlog::spdlog)\n"
}, {
"name" : "openssl",
"version>=" : "3.1.1"
}, {
"name" : "magic-enum",
"version>=" : "0.9.1"
}, {
"name" : "cppcodec",
"version>=" : "0.2#4"
}, {
"name" : "rapidjson",
"version>=" : "2023-04-27"
} ]
}