0

I'm implementing a WireGuard custom client using wireguard.dll for Windows NT. I took the following example as a basis: https://git.zx2c4.com/wireguard-nt/tree/example/example.c I need to create a VPN connection with an existing server. Firstly I create the Config structure:

struct Config
{
    WIREGUARD_INTERFACE Interface;
    WIREGUARD_PEER Server;
    WIREGUARD_ALLOWED_IP FirstPeerAllowedIP1;
};

After in main() I create an adapter and fill configuration with my data:


 WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"AdapterName", L"TunelType", NULL);
 if (!Adapter)
    {
        std::cout << "Error of adapter creating\n";
        FreeLibrary(WireGuardDll);
        return 1;
    }
 else {
        std::cout << "That's OK\n";
    }

 Config config;

 CHAR interfacePrivateKey[] = "privatekey";
 std::vector<BYTE> interfacePrivateKeyBytes = base64_decode(interfacePrivateKey); // base64_decode is a custom function. But it works correctly
 CHAR serverPublicKeyStr[46] = "publicKey";
 std::vector<BYTE> serverPublicKeyBytes = base64_decode(serverPublicKeyStr);

 config.Interface.Flags = WIREGUARD_INTERFACE_HAS_PRIVATE_KEY;
 memcpy(config.Interface.PrivateKey, &interfacePrivateKeyBytes[0], WIREGUARD_KEY_LENGTH);
 config.Interface.PeersCount = 1;
 config.Interface.ListenPort = NULL;

 config.Server.Flags = static_cast<WIREGUARD_PEER_FLAG>(WIREGUARD_PEER_HAS_PUBLIC_KEY | WIREGUARD_PEER_HAS_ENDPOINT);
 memcpy(config.Server.PublicKey, &serverPublicKeyBytes[0], WIREGUARD_KEY_LENGTH);
 config.Server.Endpoint.si_family = AF_INET;
 config.Server.Endpoint.Ipv4.sin_family = AF_INET;
 config.Server.Endpoint.Ipv4.sin_port = htons(aPortNumber); // server port
 std::cout << inet_pton(AF_INET, "x.x.x.x", &config.Server.Endpoint.Ipv4.sin_addr) << std::endl;
 config.Server.AllowedIPsCount = 16;

 config.Server.PersistentKeepalive = 25;

 config.FirstPeerAllowedIP1.AddressFamily = AF_INET;
 std::cout << inet_pton(AF_INET, "x.x.0.0", &config.FirstPeerAllowedIP1.Address) << std::endl;
 config.FirstPeerAllowedIP1.Cidr = static_cast<BYTE>(16);

After that I call WireGuardSetConfiguration() and it returns NULL:(

if (!WireGuardSetConfiguration(Adapter, &config.Interface, sizeof(Config)))
    {
        std::cout << "Config setting failed\n" << std::endl;
        FreeLibrary(WireGuardDll);
        return 1;

    }

The strangest thing is that if I clear config.Interface before configuration setting, it doesn't return NULL.

config.Interface = ...
ZeroMemory(&config.Interface, sizeof(config.Interface));

config.Server = ....
if (!WireGuardSetConfiguration(Adapter, &config.Interface, sizeof(Config))) ...

What could be the problem? Maybe someone knows how to solve it? I would be grateful for any help. Thanks!

Harith
  • 4,663
  • 1
  • 5
  • 20
  • It never hurts to zero out fields you do not use. – Botje Mar 31 '23 at 13:08
  • 1
    The problem was in this line: config.Server.AllowedIPsCount = 16; Error 0x57 means that the fuction DeviceIoControl(params) called in WireGuardSetConfiguration() has problems with parameters. In my case I have only one Allowed IP in the Config structure, however in my example AllowedIpsCount is equal to 16. My code still doesn't work correctly, but now I don't get 0x57 (87) error. – Семен Дьяков Apr 05 '23 at 06:26

1 Answers1

0

if relevant

Here's the code that works for me

#include <winsock2.h>
#include <Windows.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <bcrypt.h>
#include <wincrypt.h>
#include <sysinfoapi.h>
#include <winternl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "wireguard.h"
#include "Base64.hpp"

#include <vector>
#include <iostream>
#include <string>

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;

static HMODULE
InitializeWireGuardNT(void)
{
    HMODULE WireGuardDll =
        LoadLibraryExW(L"wireguard.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
    if (!WireGuardDll)
        return NULL;
#define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == NULL)
    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
    {
        DWORD LastError = GetLastError();
        FreeLibrary(WireGuardDll);
        SetLastError(LastError);
        return NULL;
    }
    return WireGuardDll;
}

struct Config
{
    WIREGUARD_INTERFACE Interface;
    WIREGUARD_PEER Server;
    WIREGUARD_ALLOWED_IP FirstPeerAllowedIP1;
};

int main(int argc, char *argv[])
{
    DWORD LastError;
    WSADATA WsaData;
    if (WSAStartup(MAKEWORD(2, 2), &WsaData))
    {
        std::cout << "WSA ERROR\n";
        return 1;
    }
    HMODULE WireGuardDll = InitializeWireGuardNT();
    if (!WireGuardDll)
    {
    std::cout << "Failed to initialize WireGuardNT\n";
        WSACleanup();
        return 1;
    }
    
    WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"AdapterName", L"TunelType", NULL);

    if (!Adapter)
        {
            std::cout << "Error of adapter creating\n";
            FreeLibrary(WireGuardDll);
            return 1;
        }

    std::cout << "That's OK\n";

    Config config;
    ZeroMemory(&config, sizeof(config));

    CHAR interfacePrivateKey[] = "";
    std::vector<BYTE> interfacePrivateKeyBytes = base64_decode(interfacePrivateKey); // base64_decode is a custom function. But it works correctly
    CHAR serverPublicKeyStr[46] = "";
    std::vector<BYTE> serverPublicKeyBytes = base64_decode(serverPublicKeyStr);

    config.Interface.Flags = WIREGUARD_INTERFACE_HAS_PRIVATE_KEY;
    memcpy(config.Interface.PrivateKey, &interfacePrivateKeyBytes[0], WIREGUARD_KEY_LENGTH);
    config.Interface.PeersCount = 1;

    config.Server.Flags = static_cast<WIREGUARD_PEER_FLAG>(WIREGUARD_PEER_HAS_PUBLIC_KEY | WIREGUARD_PEER_HAS_ENDPOINT);
    memcpy(config.Server.PublicKey, &serverPublicKeyBytes[0], WIREGUARD_KEY_LENGTH);
    config.Server.Endpoint.si_family = AF_INET;
    config.Server.Endpoint.Ipv4.sin_family = AF_INET;
    config.Server.Endpoint.Ipv4.sin_port = htons(51820); // server port
    std::cout << inet_pton(AF_INET, "x.x.x.x", &config.Server.Endpoint.Ipv4.sin_addr) << std::endl; //Server address
    config.Server.AllowedIPsCount = 1;

    config.Server.PersistentKeepalive = 25;

    config.FirstPeerAllowedIP1.AddressFamily = AF_INET;

    ////////////////////////

    MIB_UNICASTIPADDRESS_ROW AddressRow;
    InitializeUnicastIpAddressEntry(&AddressRow);
    AddressRow.Address.Ipv4.sin_family = AF_INET;
    AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
    AddressRow.DadState = IpDadStatePreferred;
    inet_pton(AF_INET, "10.0.x.x", &AddressRow.Address.Ipv4.sin_addr); //Interface address

    WireGuardGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);

    MIB_IPFORWARD_ROW2 DefaultRoute;
    ZeroMemory(&DefaultRoute, sizeof(DefaultRoute));
    InitializeIpForwardEntry(&DefaultRoute);
    DefaultRoute.InterfaceLuid = AddressRow.InterfaceLuid;
    DefaultRoute.DestinationPrefix.Prefix.si_family = AF_INET;
    DefaultRoute.NextHop.si_family = AF_INET;
    DefaultRoute.Metric = 0;
    LastError = CreateIpForwardEntry2(&DefaultRoute);
    if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
    {
        WireGuardCloseAdapter(Adapter);
        FreeLibrary(WireGuardDll);
        WSACleanup();
        std::cout << "CreateIPForwardEntry2Error\n";
        return 1;
    }
    LastError = CreateUnicastIpAddressEntry(&AddressRow);
    if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
    {
        WireGuardCloseAdapter(Adapter);
        FreeLibrary(WireGuardDll);
        WSACleanup();
        std::cout << "CreateUnicastIpAddressEntryError\n";
        return 1;
    }

    MIB_IPINTERFACE_ROW IpInterface;
    ZeroMemory(&IpInterface, sizeof(IpInterface));

    InitializeIpInterfaceEntry(&IpInterface);
    IpInterface.InterfaceLuid = AddressRow.InterfaceLuid;
    IpInterface.Family = AF_INET;
    LastError = GetIpInterfaceEntry(&IpInterface);
    if (LastError != ERROR_SUCCESS)
    {
        WireGuardCloseAdapter(Adapter);
        FreeLibrary(WireGuardDll);
        WSACleanup();
        std::cout << "GetIpInterfaceEntryError\n";
        return 1;
    }
    IpInterface.UseAutomaticMetric = FALSE;
    IpInterface.Metric = 0;
    IpInterface.NlMtu = 1420;
    IpInterface.SitePrefixLength = 0;
    LastError = SetIpInterfaceEntry(&IpInterface);
    if (LastError != ERROR_SUCCESS)
    {
        WireGuardCloseAdapter(Adapter);
        FreeLibrary(WireGuardDll);
        WSACleanup();

        std::cout << "SetIpInterfaceEntryError\n";
        return 1;
    }


    /////////////////////////////////
    if (!WireGuardSetConfiguration(Adapter, &config.Interface, sizeof(Config)))
    {
        std::cout << "Config setting failedError\n" << std::endl;
        FreeLibrary(WireGuardDll);
        getchar();
        return 1;

    }

    if(!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE_UP))
    {
        std::cout << "Adapter state setting failedError\n" << std::endl;
        FreeLibrary(WireGuardDll);
        getchar();
        return 1;
    }

    getchar();
    return 0;
}

This will work as long as the program is running. The getchar() function is like a plug here.

  • I removed the extra "include," and the following remained. ' #include #include #include "wireguard.h" #include "Base64.hpp" #include #include #include ' – InstantRemedy Aug 26 '23 at 17:23