52 bytes in 2 blocks are definitely lost in loss record 5 of 13
at 0x483877F: malloc (vg_replace_malloc.c:307)
by 0x4ABB1BB: UnixMemoryAlloc (Unix.c:2033)
by 0x4A7FABF: InternalMalloc (Memory.c:3819)
by 0x4A7B769: MallocEx (Memory.c:3650)
by 0x4A7B769: Malloc (Memory.c:3641)
by 0x4AA71A9: CopyStr (Str.c:1884)
by 0x4A61A9C: DnsCacheReverseUpdate (DNS.c:257)
by 0x4A62123: DnsResolveReverse (DNS.c:506)
by 0x4A93EB3: GetHostName (Network.c:15023)
by 0x4A93EB3: AcceptInitEx (Network.c:12589)
by 0x4934659: TCPAcceptedThread (Listener.c:172)
by 0x4A76469: ThreadPoolProc (Kernel.c:872)
by 0x4ABD159: UnixDefaultThreadProc (Unix.c:1589)
by 0x51C2EA6: start_thread (pthread_create.c:477)
2,280 (684 direct, 1,596 indirect) bytes in 9 blocks are definitely lost in loss record 11 of 13
at 0x483877F: malloc (vg_replace_malloc.c:307)
by 0x4C65AC5: gaih_inet.constprop.0 (getaddrinfo.c:1058)
by 0x4C67224: getaddrinfo (getaddrinfo.c:2256)
by 0x4A61E06: DnsResolver (DNS.c:404)
by 0x4A76469: ThreadPoolProc (Kernel.c:872)
by 0x4ABD159: UnixDefaultThreadProc (Unix.c:1589)
by 0x51C2EA6: start_thread (pthread_create.c:477)
by 0x4C7CDEE: clone (clone.S:95)
Also, the default timeout value is set to 30000 (milliseconds) instead of 10000.
The change is made because it was reported that some routers failed to connect in time.
This commit also fixes a bug which caused the server to initialize all boolean options to false.
It was caused by SiLoadProtoCfg() not checking whether the item exists in the configuration file.
CfgGetBool() always returns false if the item doesn't exist.
From a functional point of view, the main improvement is that GetIP() now always prioritizes IPv6 over IPv4.
The previous implementation always returned an IPv4 address, unless not available: in such case it failed.
This means that now connections to hostnames should be established via IPv6 if available.
From a programmer point of view, getting rid of the insane wrappers is enough to justify a complete rewrite.
As an extra, several unrelated unused global variables are removed.
Before this commit, the IP address reported by the NAT-T server was immediately discarded.
That's because the peer should be accessible via the IP address used to establish the TCP connection.
User "domosekai" (https://www.domosekai.com) pointed out that the NAT-T IP address should be taken into account.
In his case it's required due to his broadband carrier's NAT causing TCP and UDP to have different external IPs.
Co-authored-by: domosekai <54519668+domosekai@users.noreply.github.com>
This greatly improves performance and reduces the binary's size (~0.2 MB vs ~5 MB).
All recent Windows versions are supported, starting with Vista.
No dialogs are created, aside from error/warning ones in case of failure.
The only dependency (aside from Windows libraries) is libhamcore.
The bug caused ProtoOptionsGet and ProtoOptionsSet not to work anymore after c90617e0e86dedf78e0e3c8a71263a80eec29caa.
The functions were introduced in aa65327e73, but the issue went unnoticed because bool was the same as UINT.
BOOL was just an alias for bool, this commit replaces all instances of it for consistency.
For some reason bool was defined as a 4-byte integer instead of a 1-byte one, presumably to match WinAPI's definition: https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types
Nothing should break now that bool is 1-byte, as no protocol code appears to be relying on the size of the data type.
PACK, for example, explicitly stores boolean values as 4-byte integers.
This commit can be seen as a follow-up to 61ccaed4f6.
WgkAdd command - Add a WireGuard key
Help for command "WgkAdd"
Purpose:
Add a WireGuard key
Description:
This command can be used to add a WireGuard key to the allowed key list.
To execute this command, you must have VPN Server administrator privileges.
Usage:
WgkAdd [key] [/HUB:hub] [/USER:user]
Parameters:
key - WireGuard key. Make sure it is the public one!
/HUB - Hub the key will be associated to.
/USER - User the key will be associated to, in the specified hub.
================================================================================
WgkDelete command - Delete a WireGuard key
Help for command "WgkDelete"
Purpose:
Delete a WireGuard key
Description:
This command can be used to delete a WireGuard key from the allowed key list.
To execute this command, you must have VPN Server administrator privileges.
Usage:
WgkDelete [key]
Parameters:
key - WireGuard key.
================================================================================
WgkEnum command - List the WireGuard keys
Help for command "WgkEnum"
Purpose:
List the WireGuard keys
Description:
This command retrieves the WireGuard keys that are allowed to connect to the server, along with the associated Virtual Hub and user.
You can add a key with the WgkAdd command.
You can delete a key with the WgkDelete command.
To execute this command, you must have VPN Server administrator privileges.
Usage:
WgkEnum
Please note that the implementation is not 100% conformant to the protocol whitepaper (https://www.wireguard.com/papers/wireguard.pdf).
More specifically: all peers are expected to send a handshake initiation once the current keypair is about to expire or is expired.
I decided not to do that because our implementation is meant to act as a server only. A true WireGuard peer acts, instead, as both a client and a server.
Once the keypair is expired, we immediately delete the session.
The cookie mechanism can be implemented in future.
As for authentication: unfortunately using the already existing methods is not possible due to the protocol not providing a way to send strings to a peer.
That's because WireGuard doesn't have a concept of "users": it identifies a peer through the public key, which is determined using the source address.
As a solution, this commit adds a special authentication method: once we receive the handshake initiation message and decrypt the peer's public key, we check whether it's in the allowed key list.
If it is, we retrieve the associated Virtual Hub and user; if the hub exists and the user is in it, the authentication is successful.
The allowed key list is stored in the configuration file like this:
declare WireGuardKeyList
{
declare 96oA7iMvjn7oXiG3ghBDPaSUytT75uXceLV+Fx3XMlM=
{
string Hub DEFAULT
string User user
}
}
WireGuard does not provide any configuration messages, meaning that we cannot push the IP address we receive from the DHCP server to the client.
In order to overcome the limitation we don't perform any DHCP operations and instead just extract the source IP address from the first IPv4 packet we receive in the tunnel.
The gateway address and the subnet mask can be set using the new "SetStaticNetwork" command. The values can be retrieved using "OptionsGet".
In future we will add a "allowed source IP addresses" function, similar to what the original WireGuard implementation provides.
================================================================================
SetStaticNetwork command - Set Virtual Hub static IPv4 network parameters
Help for command "SetStaticNetwork"
Purpose:
Set Virtual Hub static IPv4 network parameters
Description:
Set the static IPv4 network parameters for the Virtual Hub. They are used when DHCP is not available (e.g. WireGuard sessions).
You can get the current settings by using the OptionsGet command.
Usage:
SetStaticNetwork [/GATEWAY:gateway] [/SUBNET:subnet]
Parameters:
/GATEWAY - Specify the IP address of the gateway that will be used for internet communication.
/SUBNET - Specify the subnet mask, required to determine the size of the local VPN network.
The WireGuard implementation will have two options that should not have a fixed default value, because they represent two keys (one is preshared, the other is private).
Instead of handling these two options differently in ProtoNewContainer(), this commit adds a new function to PROTO_IMPL: ProtoOptionString().
ProtoOptionString() takes the option's name as argument and returns a heap-allocated string that will be used as value. The function returns NULL when the option doesn't need a randomized value.
This new implementation can be easily compiled and executed without the need for other components to be present.
It relies on standard C functions, aside from stat() which is part of POSIX but available on Windows as well.
There's only one third-party dependency, which is tinydir: a single-file header-only library for traversing directories.
2575 // Address
at_least: At condition size < 1U, the value of size must be at least 1.
cannot_single: At condition size < 1U, the value of size cannot be equal to 0.
dead_error_condition: The condition size < 1U cannot be true.
2576 if (size < 1)
2577 {
CID 287533 (#1 of 1): Logically dead code (DEADCODE)dead_error_line: Execution cannot reach this statement: goto LABEL_ERROR;.
2578 goto LABEL_ERROR;
2579 }
CID 355460 (#1 of 1): Dereference before null check (REVERSE_INULL)check_after_deref: Null-checking p suggests that it may be null, but it has already been dereferenced on all paths leading to the check.
737 if (p == NULL)
738 {
739 return false;
740 }
CID 287561 (#1 of 1): Array compared against 0 (NO_EFFECT)array_null: Comparing an array to null is not useful: src == NULL, since the test will always evaluate as true.
Was src formerly declared as a pointer?
3748 if (cedar == NULL || src == NULL || dst == NULL)
3749 {
3750 return false;
3751 }