mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2026-02-05 18:20:32 +03:00
Compare commits
3 Commits
copilot/fi
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
| c7d906c01c | |||
| 66119d1303 | |||
| 486b9ed7c5 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -210,5 +210,3 @@ developer_tools/stbchecker/**/*.binlog
|
|||||||
developer_tools/stbchecker/**/*.nvuser
|
developer_tools/stbchecker/**/*.nvuser
|
||||||
developer_tools/stbchecker/**/.mfractor/
|
developer_tools/stbchecker/**/.mfractor/
|
||||||
/vcpkg_installed
|
/vcpkg_installed
|
||||||
_codeql_build_dir/
|
|
||||||
_codeql_detected_source_root
|
|
||||||
|
|||||||
@ -220,7 +220,7 @@ Please look at the [ContainerREADME.md](ContainerREADME.md)
|
|||||||
|
|
||||||
## Build from Source code
|
## Build from Source code
|
||||||
|
|
||||||
see [BUILD_UNIX](src/BUILD_UNIX.md) or [BUILD_WINDOWS](src/BUILD_WINDOWS.md)
|
see [BUILD_UNIX](src/BUILD_UNIX.md), [BUILD_WINDOWS](src/BUILD_WINDOWS.md), or [BUILD_WINDOWS_ARM64](src/BUILD_WINDOWS_ARM64.md)
|
||||||
|
|
||||||
There are two flavours of SoftEtherVPN source code:
|
There are two flavours of SoftEtherVPN source code:
|
||||||
|
|
||||||
|
|||||||
220
src/BUILD_WINDOWS_ARM64.md
Normal file
220
src/BUILD_WINDOWS_ARM64.md
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
# How to build SoftEther VPN for Windows ARM64
|
||||||
|
|
||||||
|
This guide explains how to build SoftEther VPN for Windows ARM64 architecture. Windows on ARM is becoming increasingly important, especially on modern laptops and virtualized environments. This allows SoftEther VPN to run **natively on Windows ARM64**, improving performance and compatibility compared to x86 emulation.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **Windows x64 host machine** (ARM64 builds are cross-compiled from x64)
|
||||||
|
- Visual Studio 2019 or 2022 (Community Edition is fine)
|
||||||
|
|
||||||
|
https://visualstudio.microsoft.com/downloads
|
||||||
|
|
||||||
|
- Git for Windows (or other git tool)
|
||||||
|
|
||||||
|
https://gitforwindows.org/
|
||||||
|
|
||||||
|
- vcpkg
|
||||||
|
|
||||||
|
https://github.com/microsoft/vcpkg
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Visual Studio
|
||||||
|
|
||||||
|
Download from the official site and run the installer.
|
||||||
|
|
||||||
|
Make sure to check:
|
||||||
|
- **Desktop development with C++** under *Workloads*
|
||||||
|
- **Clang C++ Tools for Windows** in *Optional* components
|
||||||
|
- **MSVC v142 - VS 2019 C++ ARM64 build tools** (or equivalent for VS 2022) in *Optional* components
|
||||||
|
|
||||||
|
### Git
|
||||||
|
|
||||||
|
Nothing special. Just follow the installer.
|
||||||
|
|
||||||
|
### vcpkg
|
||||||
|
|
||||||
|
Let's say you will install it to `C:\vcpkg`.
|
||||||
|
|
||||||
|
Open your preferred terminal and go to `C:\`. Then run these commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\> git clone https://github.com/microsoft/vcpkg
|
||||||
|
C:\> cd vcpkg
|
||||||
|
C:\vcpkg> bootstrap-vcpkg.bat
|
||||||
|
C:\vcpkg> vcpkg integrate install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update
|
||||||
|
|
||||||
|
### vcpkg
|
||||||
|
|
||||||
|
You are recommended to update vcpkg from time to time, so that the latest libraries are used in the build.
|
||||||
|
|
||||||
|
Go to the installation path, pull the latest repo and the binary:
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\vcpkg> git pull
|
||||||
|
C:\vcpkg> bootstrap-vcpkg.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
### Step 1: Build x64-native first
|
||||||
|
|
||||||
|
**Important:** For ARM64 builds, an existing `x64-native` build is required to generate `hamcore.se2`.
|
||||||
|
|
||||||
|
1. Launch Visual Studio
|
||||||
|
|
||||||
|
Choose either **Clone a repository** to clone from GitHub or **Open a local folder** if you already have a copy.
|
||||||
|
|
||||||
|
2. Open Terminal (*View -> Terminal*). Install the needed submodules to build the project:
|
||||||
|
|
||||||
|
`git submodule update --init --recursive`
|
||||||
|
|
||||||
|
**Note**: This step is not necessary if you have chosen **Clone a repository** as Visual Studio automatically takes care of it.
|
||||||
|
|
||||||
|
3. Switch to folder view in the solution explorer
|
||||||
|
|
||||||
|
4. Select **x64-native** configuration from the dropdown menu below the search box
|
||||||
|
|
||||||
|
5. Visual Studio will try generating CMake cache. If not, click **Project -> Configure Cache** or **Generate Cache**.
|
||||||
|
|
||||||
|
If CMake is busy, you will find **Generate Cache** greyed out. Wait until it finishes or click **Cancel CMake Cache Generation** to stop it.
|
||||||
|
|
||||||
|
The initial configuration will take a longer time since it needs to download and install dependencies.
|
||||||
|
|
||||||
|
6. When *CMake generation finished* is displayed, simply go to toolbar and click **Build -> Build All**.
|
||||||
|
|
||||||
|
7. Wait for the x64 build to complete. This creates the necessary `hamcorebuilder` executable that will be reused for the ARM64 build.
|
||||||
|
|
||||||
|
### Step 2: Build arm64-on-x64
|
||||||
|
|
||||||
|
1. Switch to the **arm64-on-x64** configuration from the dropdown menu
|
||||||
|
|
||||||
|
This configuration cross-compiles ARM64 executables using the 64-bit compiler on your x64 Windows host.
|
||||||
|
|
||||||
|
2. Click **Project -> Configure Cache** or **Generate Cache** to configure the ARM64 build.
|
||||||
|
|
||||||
|
The ARM64 build will reuse the `hamcorebuilder` executable from the x64-native build to generate `hamcore.se2`.
|
||||||
|
|
||||||
|
3. When *CMake generation finished* is displayed, click **Build -> Build All**.
|
||||||
|
|
||||||
|
4. Once building has finished, hopefully with no errors, look in the newly created `/build` directory in the project's folder.
|
||||||
|
|
||||||
|
## Installation on Windows ARM64 Devices
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Windows 10 or Windows 11 ARM64 device
|
||||||
|
- The compiled ARM64 binaries from the build process
|
||||||
|
- Administrator privileges
|
||||||
|
|
||||||
|
### Installing the VPN Client
|
||||||
|
|
||||||
|
1. Copy the ARM64 build output to your Windows ARM64 device
|
||||||
|
|
||||||
|
2. Run `vpnsetup.exe` from the ARM64 build output
|
||||||
|
|
||||||
|
3. Select the components you want to install (typically VPN Client)
|
||||||
|
|
||||||
|
4. Follow the installation wizard
|
||||||
|
|
||||||
|
### VPN Client Driver Installation
|
||||||
|
|
||||||
|
The ARM64 Neo6 VPN driver is included in the build and targets **Windows 10 ARM64** or later.
|
||||||
|
|
||||||
|
**Important Notes:**
|
||||||
|
|
||||||
|
- The ARM64 driver is **unsigned by default**
|
||||||
|
- To use the unsigned driver, you need to:
|
||||||
|
1. Enable Windows Test Mode by running in an Administrator Command Prompt:
|
||||||
|
```
|
||||||
|
bcdedit /set testsigning on
|
||||||
|
```
|
||||||
|
2. Restart your computer
|
||||||
|
3. Install the VPN Client as described above
|
||||||
|
|
||||||
|
- For production use, the driver should be properly signed with a valid code signing certificate
|
||||||
|
|
||||||
|
### Disabling Test Mode (Optional)
|
||||||
|
|
||||||
|
After you're done testing or if you have a signed driver, you can disable Test Mode:
|
||||||
|
|
||||||
|
```
|
||||||
|
bcdedit /set testsigning off
|
||||||
|
```
|
||||||
|
|
||||||
|
Then restart your computer.
|
||||||
|
|
||||||
|
## Build Configuration Details
|
||||||
|
|
||||||
|
The **arm64-on-x64** configuration includes:
|
||||||
|
|
||||||
|
- **Cross-compilation target**: Windows ARM64
|
||||||
|
- **Compiler**: clang-cl (LLVM)
|
||||||
|
- **Toolchain**: MSVC ARM64 toolchain
|
||||||
|
- **VCPKG triplet**: arm64-windows-static
|
||||||
|
- **CPU feature detection**: ARM64 crypto extensions (AES via `PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE`)
|
||||||
|
- **BLAKE2 optimization**: NEON implementation (instead of SSE2)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
### Build Number
|
||||||
|
|
||||||
|
You can change the build number in `CMakeSettings.json`. Use any integer no less than 5180.
|
||||||
|
|
||||||
|
Delete and regenerate CMake cache after the change.
|
||||||
|
|
||||||
|
### OpenSSL
|
||||||
|
|
||||||
|
The above instruction builds OpenSSL library statically in the SoftEther binaries. This means:
|
||||||
|
|
||||||
|
- When you distribute the installer, users will not need to install OpenSSL separately
|
||||||
|
- The OpenSSL library cannot be updated without a rebuild and reinstallation of SoftEther
|
||||||
|
|
||||||
|
It's also possible to build OpenSSL library dynamically, but this requires additional configuration and is beyond the scope of this ARM64-specific guide. Refer to `BUILD_WINDOWS.md` for details on dynamic OpenSSL linking.
|
||||||
|
|
||||||
|
### Driver Signing
|
||||||
|
|
||||||
|
For production deployments, you should sign the ARM64 driver with a valid code signing certificate:
|
||||||
|
|
||||||
|
1. Obtain a code signing certificate from a trusted Certificate Authority
|
||||||
|
2. Use the Windows Driver Kit (WDK) tools to sign the driver
|
||||||
|
3. Distribute the signed driver to users
|
||||||
|
|
||||||
|
Without driver signing, users will need to enable Test Mode which reduces system security.
|
||||||
|
|
||||||
|
### Tested Environments
|
||||||
|
|
||||||
|
This ARM64 build process has been tested on:
|
||||||
|
|
||||||
|
- Windows x64 host (cross-compiling ARM64)
|
||||||
|
- Windows 10 ARM64 (VPN Client driver load and basic functionality)
|
||||||
|
- Windows 11 ARM64 devices
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Build Fails During hamcore.se2 Generation
|
||||||
|
|
||||||
|
Make sure you have completed the x64-native build first. The ARM64 build requires the x64 `hamcorebuilder` executable.
|
||||||
|
|
||||||
|
### Driver Installation Fails
|
||||||
|
|
||||||
|
Ensure you have:
|
||||||
|
- Enabled Test Mode (for unsigned drivers)
|
||||||
|
- Administrator privileges
|
||||||
|
- Windows 10 or later ARM64
|
||||||
|
|
||||||
|
### VPN Client Doesn't Start
|
||||||
|
|
||||||
|
Check that:
|
||||||
|
- All ARM64 binaries are in the correct installation directory
|
||||||
|
- The Neo6 ARM64 driver is properly installed
|
||||||
|
- Windows Event Viewer for any error messages
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Main Windows build guide: `BUILD_WINDOWS.md`
|
||||||
|
- Pull Request #2209: Windows ARM64 support
|
||||||
|
- Issue #1331: Windows ARM64 support request
|
||||||
@ -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
|
// 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)
|
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;
|
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;
|
t = v->NativeNat;
|
||||||
|
|
||||||
old_icmp_header = (ICMP_HEADER *)icmp_data;
|
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;
|
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;
|
t = v->NativeNat;
|
||||||
|
|
||||||
// Search whether there is an existing session
|
// 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;
|
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;
|
t = v->NativeNat;
|
||||||
|
|
||||||
// Search whether there is an existing session
|
// Search whether there is an existing session
|
||||||
@ -10281,13 +10193,6 @@ void Virtual_Free(VH *v)
|
|||||||
|
|
||||||
LockVirtual(v);
|
LockVirtual(v);
|
||||||
{
|
{
|
||||||
// Free host IP cache
|
|
||||||
if (v->HostIPAddressCache != NULL)
|
|
||||||
{
|
|
||||||
FreeHostIPAddressList(v->HostIPAddressCache);
|
|
||||||
v->HostIPAddressCache = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the IP combining list
|
// Release the IP combining list
|
||||||
FreeIpCombineList(v);
|
FreeIpCombineList(v);
|
||||||
|
|
||||||
@ -10322,9 +10227,6 @@ void Virtual_Free(VH *v)
|
|||||||
}
|
}
|
||||||
UnlockVirtual(v);
|
UnlockVirtual(v);
|
||||||
|
|
||||||
// Release the host IP cache lock
|
|
||||||
DeleteLock(v->HostIPCacheLock);
|
|
||||||
|
|
||||||
// Release the logger
|
// Release the logger
|
||||||
FreeLog(v->Logger);
|
FreeLog(v->Logger);
|
||||||
}
|
}
|
||||||
@ -10455,11 +10357,6 @@ VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_
|
|||||||
|
|
||||||
v->nat = nat;
|
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
|
// Examine whether ICMP Raw Socket can be created
|
||||||
s = NewUDP4(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4), NULL);
|
s = NewUDP4(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4), NULL);
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
|
|||||||
@ -313,11 +313,6 @@ struct VH
|
|||||||
HUB_OPTION *HubOption; // Pointer to the Virtual HUB options
|
HUB_OPTION *HubOption; // Pointer to the Virtual HUB options
|
||||||
|
|
||||||
NATIVE_NAT *NativeNat; // Native NAT
|
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
|
// Virtual host option
|
||||||
|
|||||||
Reference in New Issue
Block a user