mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2026-03-09 17:59:19 +03:00
Compare commits
27 Commits
copilot/fi
...
a0afd98744
| Author | SHA1 | Date | |
|---|---|---|---|
| a0afd98744 | |||
| ae448abdad | |||
| cfe854b339 | |||
| c075bd85a8 | |||
| 6f749ab71c | |||
| 0e36e095f0 | |||
| 34e4d4a54b | |||
| df3ea19f0e | |||
| 9da4aabda5 | |||
| 3cb3dd20fc | |||
| b551b77e25 | |||
| 609b8f4a5e | |||
| 0a87ff8fbd | |||
| 6016f84315 | |||
| 9d27b935b7 | |||
| 1e1104d3ba | |||
| 074efb5479 | |||
| fe460de5a6 | |||
| 6ef941db21 | |||
| d7d3ec8cac | |||
| 68e9f0b593 | |||
| f1012da5fb | |||
| 1411d4ceb4 | |||
| a3176175f9 | |||
| 88af7986b4 | |||
| 38f102e2e7 | |||
| 4a4c1c79de |
3
.github/workflows/coverity.yml
vendored
3
.github/workflows/coverity.yml
vendored
@ -4,6 +4,7 @@ name: Coverity
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@ -11,7 +12,7 @@ permissions:
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'SoftEtherVPN' }}
|
||||
if: ${{ github.repository_owner == 'SoftEtherVPN' || github.event_name == 'workflow_dispatch' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -210,5 +210,3 @@ developer_tools/stbchecker/**/*.binlog
|
||||
developer_tools/stbchecker/**/*.nvuser
|
||||
developer_tools/stbchecker/**/.mfractor/
|
||||
/vcpkg_installed
|
||||
_codeql_build_dir/
|
||||
_codeql_detected_source_root
|
||||
|
||||
@ -87,6 +87,10 @@ into it. So that is what will be described below.
|
||||
- x86-on-x64
|
||||
|
||||
Cross compile x86 executables with 64-bit compiler
|
||||
|
||||
- arm64-on-x64
|
||||
|
||||
Cross compile arm64 executables with x64t compiler
|
||||
|
||||
On 64-bit Windows, all four configurations can be used. 32-bit platforms can only use 32-bit compiler.
|
||||
|
||||
|
||||
52
src/BUILD_WinArm64.md
Normal file
52
src/BUILD_WinArm64.md
Normal file
@ -0,0 +1,52 @@
|
||||
# How to build and install SoftEther VPN on Windows ARM64
|
||||
|
||||
This document describes how to build SoftEther VPN for Windows ARM64 and how to install the VPN Client and Neo6 virtual network adapter on Windows on ARM devices.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
- Build host: Windows x64
|
||||
|
||||
- Target device: Windows 10 / Windows 11 ARM64
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
**Notes before building**: ARM64 builds are cross-compiled from an x64 Windows host. An existing x64-native build is required to generate hamcore.se2.
|
||||
1. Follow [BUILD_WINDOWS.md](BUILD_WINDOWS.md##Building)
|
||||
|
||||
1. Build x64 (Native): From the build menu, select x64-on-x64. Complete the build successfully. This build is required to generate shared resources
|
||||
|
||||
1. Build ARM64 (Cross-Compiled): From the same build menu, select arm64-on-x64.
|
||||
Build the ARM64 version of SoftEther VPN.
|
||||
|
||||
1. Building the Neo6 Virtual Network Adapter (ARM64)
|
||||
|
||||
Open the following project in Visual Studio:
|
||||
```
|
||||
.\src\Neo6\Neo6.vcxproj
|
||||
```
|
||||
|
||||
SoftEther VPN Client uses the Neo6 virtual network adapter.
|
||||
|
||||
|
||||
Driver Output Files
|
||||
The ARM64 driver package includes:
|
||||
```
|
||||
Neo6_arm64_VPN.sys
|
||||
Neo6_arm64_VPN.inf
|
||||
```
|
||||
Driver Signing and Installation (Windows ARM64)
|
||||
```
|
||||
Enable test-signing mode: bcdedit /set testsigning on
|
||||
Reboot the system.
|
||||
Testing signing:
|
||||
Install the Neo6 ARM64 driver.
|
||||
```
|
||||
# Summary
|
||||
|
||||
SoftEther VPN can be cross-compiled for Windows ARM64 on an x64 host
|
||||
VPN Client works natively on Windows on ARM
|
||||
Neo6 ARM64 driver requires Microsoft signing for production use
|
||||
Test-signing is suitable for local development only
|
||||
@ -2562,9 +2562,16 @@ void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol)
|
||||
Debug("OpenVPN Channel %u Failed.\n", j);
|
||||
OvsLog(s, se, c, "LO_CHANNEL_FAILED");
|
||||
|
||||
// Return the AUTH_FAILED
|
||||
str = "AUTH_FAILED";
|
||||
WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
|
||||
if ((se->IpcAsync->ErrorCode == ERR_AUTHTYPE_NOT_SUPPORTED) ||
|
||||
(se->IpcAsync->ErrorCode == ERR_AUTH_FAILED) ||
|
||||
(se->IpcAsync->ErrorCode == ERR_PROXY_AUTH_FAILED) ||
|
||||
(se->IpcAsync->ErrorCode == ERR_USER_AUTHTYPE_NOT_PASSWORD) ||
|
||||
(se->IpcAsync->ErrorCode == ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE))
|
||||
{
|
||||
// Return the AUTH_FAILED
|
||||
str = "AUTH_FAILED";
|
||||
WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
|
||||
}
|
||||
|
||||
s->SessionEstablishedCount++;
|
||||
|
||||
|
||||
@ -1190,67 +1190,6 @@ void NnIpSendForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UCHAR ttl, UINT src_i
|
||||
}
|
||||
}
|
||||
|
||||
// Host IP address cache TTL in milliseconds (60 seconds)
|
||||
#define HOST_IP_CACHE_TTL_MS 60000
|
||||
|
||||
// Check if destination IP is one of the host's own IP addresses
|
||||
// Uses caching to avoid frequent system calls
|
||||
// Returns true if dest_ip matches any of the host's IPs
|
||||
bool IsDestinationHostOwnIP(VH *v, UINT dest_ip)
|
||||
{
|
||||
bool is_host_ip = false;
|
||||
UINT64 now;
|
||||
LIST *new_list = NULL;
|
||||
// Validate arguments
|
||||
if (v == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
now = Tick64();
|
||||
|
||||
Lock(v->HostIPCacheLock);
|
||||
{
|
||||
// Check if cache needs refresh (every 60 seconds or if not initialized)
|
||||
if (v->HostIPAddressCache == NULL || now >= v->HostIPCacheExpires)
|
||||
{
|
||||
// Get new list while holding the lock to prevent multiple threads from refreshing
|
||||
new_list = GetHostIPAddressList();
|
||||
|
||||
// Free old cache
|
||||
if (v->HostIPAddressCache != NULL)
|
||||
{
|
||||
FreeHostIPAddressList(v->HostIPAddressCache);
|
||||
}
|
||||
|
||||
// Set new cache with TTL
|
||||
v->HostIPAddressCache = new_list;
|
||||
v->HostIPCacheExpires = now + HOST_IP_CACHE_TTL_MS;
|
||||
}
|
||||
|
||||
// Check if dest_ip matches any cached host IP
|
||||
if (v->HostIPAddressCache != NULL)
|
||||
{
|
||||
UINT i;
|
||||
IP dest_ip_obj;
|
||||
UINTToIP(&dest_ip_obj, dest_ip);
|
||||
|
||||
for (i = 0; i < LIST_NUM(v->HostIPAddressCache); i++)
|
||||
{
|
||||
IP *host_ip = LIST_DATA(v->HostIPAddressCache, i);
|
||||
if (IsIP4(host_ip) && CmpIpAddr(&dest_ip_obj, host_ip) == 0)
|
||||
{
|
||||
is_host_ip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(v->HostIPCacheLock);
|
||||
|
||||
return is_host_ip;
|
||||
}
|
||||
|
||||
// Communication of ICMP towards the Internet
|
||||
void NnIcmpEchoRecvForInternet(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
|
||||
{
|
||||
@ -1270,15 +1209,6 @@ void NnIcmpEchoRecvForInternet(VH *v, UINT src_ip, UINT dest_ip, void *data, UIN
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if destination is the host's own IP address
|
||||
// When Native NAT tries to send packets to the host's own IP, the OS routing
|
||||
// may fail or behave unexpectedly. Drop such packets to avoid issues.
|
||||
if (IsDestinationHostOwnIP(v, dest_ip))
|
||||
{
|
||||
// Destination is the host's own IP - drop the packet
|
||||
return;
|
||||
}
|
||||
|
||||
t = v->NativeNat;
|
||||
|
||||
old_icmp_header = (ICMP_HEADER *)icmp_data;
|
||||
@ -1421,15 +1351,6 @@ void NnUdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if destination is the host's own IP address
|
||||
// When Native NAT tries to send packets to the host's own IP, the OS routing
|
||||
// may fail or behave unexpectedly. Drop such packets to avoid issues.
|
||||
if (IsDestinationHostOwnIP(v, dest_ip))
|
||||
{
|
||||
// Destination is the host's own IP - drop the packet
|
||||
return;
|
||||
}
|
||||
|
||||
t = v->NativeNat;
|
||||
|
||||
// Search whether there is an existing session
|
||||
@ -1528,15 +1449,6 @@ void NnTcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if destination is the host's own IP address
|
||||
// When Native NAT tries to send packets to the host's own IP, the OS routing
|
||||
// may fail or behave unexpectedly. Drop such packets to avoid issues.
|
||||
if (IsDestinationHostOwnIP(v, dest_ip))
|
||||
{
|
||||
// Destination is the host's own IP - drop the packet
|
||||
return;
|
||||
}
|
||||
|
||||
t = v->NativeNat;
|
||||
|
||||
// Search whether there is an existing session
|
||||
@ -10281,13 +10193,6 @@ void Virtual_Free(VH *v)
|
||||
|
||||
LockVirtual(v);
|
||||
{
|
||||
// Free host IP cache
|
||||
if (v->HostIPAddressCache != NULL)
|
||||
{
|
||||
FreeHostIPAddressList(v->HostIPAddressCache);
|
||||
v->HostIPAddressCache = NULL;
|
||||
}
|
||||
|
||||
// Release the IP combining list
|
||||
FreeIpCombineList(v);
|
||||
|
||||
@ -10322,9 +10227,6 @@ void Virtual_Free(VH *v)
|
||||
}
|
||||
UnlockVirtual(v);
|
||||
|
||||
// Release the host IP cache lock
|
||||
DeleteLock(v->HostIPCacheLock);
|
||||
|
||||
// Release the logger
|
||||
FreeLog(v->Logger);
|
||||
}
|
||||
@ -10455,11 +10357,6 @@ VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_
|
||||
|
||||
v->nat = nat;
|
||||
|
||||
// Initialize host IP cache for Native NAT
|
||||
v->HostIPAddressCache = NULL;
|
||||
v->HostIPCacheExpires = 0;
|
||||
v->HostIPCacheLock = NewLock();
|
||||
|
||||
// Examine whether ICMP Raw Socket can be created
|
||||
s = NewUDP4(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4), NULL);
|
||||
if (s != NULL)
|
||||
|
||||
@ -313,11 +313,6 @@ struct VH
|
||||
HUB_OPTION *HubOption; // Pointer to the Virtual HUB options
|
||||
|
||||
NATIVE_NAT *NativeNat; // Native NAT
|
||||
|
||||
// Host IP cache for Native NAT packet filtering
|
||||
LIST *HostIPAddressCache; // Cached list of host IP addresses
|
||||
UINT64 HostIPCacheExpires; // When the cache expires (tick64)
|
||||
LOCK *HostIPCacheLock; // Lock for cache access
|
||||
};
|
||||
|
||||
// Virtual host option
|
||||
|
||||
@ -4761,7 +4761,7 @@ static void MY_SHA0_Transform(MY_SHA0_CTX* ctx) {
|
||||
UCHAR* p = ctx->buf;
|
||||
int t;
|
||||
for(t = 0; t < 16; ++t) {
|
||||
UINT tmp = *p++ << 24;
|
||||
UINT tmp = (UINT)*p++ << 24;
|
||||
tmp |= *p++ << 16;
|
||||
tmp |= *p++ << 8;
|
||||
tmp |= *p++;
|
||||
|
||||
@ -63,7 +63,7 @@ static int ydays[] =
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
||||
};
|
||||
|
||||
static UINT current_num_thread = 0;
|
||||
static COUNTER *current_num_thread = NULL;
|
||||
static UINT cached_number_of_cpus = 0;
|
||||
|
||||
|
||||
@ -776,6 +776,7 @@ void InitThreading()
|
||||
{
|
||||
thread_pool = NewSk();
|
||||
thread_count = NewCounter();
|
||||
current_num_thread = NewCounter();
|
||||
}
|
||||
|
||||
// Release of thread pool
|
||||
@ -821,6 +822,9 @@ void FreeThreading()
|
||||
|
||||
DeleteCounter(thread_count);
|
||||
thread_count = NULL;
|
||||
|
||||
DeleteCounter(current_num_thread);
|
||||
current_num_thread = NULL;
|
||||
}
|
||||
|
||||
// Thread pool procedure
|
||||
@ -1028,9 +1032,9 @@ THREAD *NewThreadNamed(THREAD_PROC *thread_proc, void *param, char *name)
|
||||
|
||||
Wait(pd->InitFinishEvent, INFINITE);
|
||||
|
||||
current_num_thread++;
|
||||
Inc(current_num_thread);
|
||||
|
||||
// Debug("current_num_thread = %u\n", current_num_thread);
|
||||
// Debug("current_num_thread = %u\n", Count(current_num_thread));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1055,8 +1059,8 @@ void CleanupThread(THREAD *t)
|
||||
|
||||
Free(t);
|
||||
|
||||
current_num_thread--;
|
||||
//Debug("current_num_thread = %u\n", current_num_thread);
|
||||
Dec(current_num_thread);
|
||||
//Debug("current_num_thread = %u\n", Count(current_num_thread));
|
||||
}
|
||||
|
||||
// Release thread (pool)
|
||||
|
||||
@ -72,11 +72,26 @@ int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow)
|
||||
|
||||
// Compiler dependent
|
||||
#ifndef OS_WIN32
|
||||
// Gcc compiler
|
||||
// GCC or Clang compiler
|
||||
#define GCC_PACKED __attribute__ ((__packed__))
|
||||
// Clang compiler
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(thread_sanitizer)
|
||||
#define ATTRIBUTE_NO_TSAN __attribute__((no_sanitize("thread")))
|
||||
#endif // __has_feature(thread_sanitizer)
|
||||
#endif // __has_feature
|
||||
// GCC compiler
|
||||
#if defined(__SANITIZE_THREAD__) && !defined(ATTRIBUTE_NO_TSAN)
|
||||
#define ATTRIBUTE_NO_TSAN __attribute__((no_sanitize("thread")))
|
||||
#endif // __SANITIZE_THREAD__
|
||||
// Other or older Clang/GCC compiler
|
||||
#ifndef ATTRIBUTE_NO_TSAN
|
||||
#define ATTRIBUTE_NO_TSAN
|
||||
#endif // ATTRIBUTE_NO_TSAN
|
||||
#else // OS_WIN32
|
||||
// VC++ compiler
|
||||
#define GCC_PACKED
|
||||
#define ATTRIBUTE_NO_TSAN
|
||||
#endif // OS_WIN32
|
||||
|
||||
// Macro that displays the current file name and line number
|
||||
|
||||
@ -470,6 +470,7 @@ LIST *LoadLangList()
|
||||
b = ReadDump(filename);
|
||||
if (b == NULL)
|
||||
{
|
||||
FreeLangList(o);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -2140,9 +2140,13 @@ void UnixMemoryFree(void *addr)
|
||||
// SIGCHLD handler
|
||||
void UnixSigChldHandler(int sig)
|
||||
{
|
||||
int old_errno = errno;
|
||||
|
||||
// Recall the zombie processes
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||
signal(SIGCHLD, UnixSigChldHandler);
|
||||
|
||||
errno = old_errno;
|
||||
}
|
||||
|
||||
// Disable core dump
|
||||
|
||||
669
src/bin/hamcore/wwwroot/admin/default/package-lock.json
generated
669
src/bin/hamcore/wwwroot/admin/default/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
tsan_suppressions.txt
Normal file
28
tsan_suppressions.txt
Normal file
@ -0,0 +1,28 @@
|
||||
# This file contains suppressions for Thread Sanitizer.
|
||||
# For the specification, refer to: https://github.com/google/sanitizers/wiki/threadsanitizersuppressions
|
||||
|
||||
|
||||
|
||||
## Set/Wait
|
||||
# This provides synchronization equivalent to a lock, but Thread Sanitizer cannot recognize it.
|
||||
|
||||
# Thread Sanitizer reports data race on Halt in TK64.
|
||||
# https://github.com/SoftEtherVPN/SoftEtherVPN/pull/2221
|
||||
race_top:FreeTick64
|
||||
|
||||
# Thread Sanitizer reports data races on Finished and NoDelayFlag in CONNECT_SERIAL_PARAM,
|
||||
# shared between BindConnectThreadForIPv4, BindConnectThreadForIPv6, and BindConnectEx5.
|
||||
# https://github.com/SoftEtherVPN/SoftEtherVPN/pull/2222
|
||||
race_top:BindConnectThreadForIPv4
|
||||
race_top:BindConnectThreadForIPv6
|
||||
race_top:BindConnectEx5
|
||||
|
||||
|
||||
## Manual PTHREAD_MUTEX_RECURSIVE
|
||||
# The Lock/Unlock mechanism on Unix is a manual, hand-coded implementation of PTHREAD_MUTEX_RECURSIVE.
|
||||
# We avoid using the PTHREAD_MUTEX_RECURSIVE directly because it exhibits critical bugs, such as deadlocks
|
||||
# on certain older systems(Linux, Solaris, or macOS). While Thread Sanitizer will report data races,
|
||||
# these warnings should be ignored as the logic has been carefully implemented to ensure thread safety.
|
||||
# https://github.com/SoftEtherVPN/SoftEtherVPN/pull/2219
|
||||
race_top:UnixLock
|
||||
race_top:UnixUnlockEx
|
||||
Reference in New Issue
Block a user