Wireguard

How to install Netmaker client (netclient) on Ubuntu in 15 seconds

Just run these commands in your Shell in Ubuntu to install netclient

curl -sL 'https://apt.netmaker.org/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/netclient.asc
curl -sL 'https://apt.netmaker.org/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/netclient.list
sudo apt update
sudo apt install netclient

Source: Netmaker installation page

Posted by Uli Köhler in Networking, VPN, Wireguard

iperf3 benchmark of ZeroTier vs Netmaker vs Tailscale vs direct switched connection

In our setup, a virtual machine (running on an XCP-NG host) on  was connected to my Desktop (HP Z240, i7-6700 @3.4 GHz running Ubuntu 22.04) in a purely switched network with 1Gbit links. Both devices were connected using a MikroTik 10G switch (Marvell chip

I ran iperf3 -s on the VM and ran iperf3 -c [IP address] on the desktop. Reverse tests have not been performed.

Direct switched connection (no VPN)

Connecting to host 10.9.2.103, port 5201
[  5] local 10.9.2.10 port 56848 connected to 10.9.2.103 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  92.8 MBytes   779 Mbits/sec    0    444 KBytes       
[  5]   1.00-2.00   sec  90.7 MBytes   761 Mbits/sec    0    543 KBytes       
[  5]   2.00-3.00   sec  88.6 MBytes   743 Mbits/sec    0    816 KBytes       
[  5]   3.00-4.00   sec  90.0 MBytes   755 Mbits/sec    0    816 KBytes       
[  5]   4.00-5.00   sec  90.0 MBytes   755 Mbits/sec    0    856 KBytes       
[  5]   5.00-6.00   sec  88.8 MBytes   744 Mbits/sec    0    946 KBytes       
[  5]   6.00-7.00   sec  88.8 MBytes   745 Mbits/sec    0    946 KBytes       
[  5]   7.00-8.00   sec  90.0 MBytes   755 Mbits/sec    0    993 KBytes       
[  5]   8.00-9.00   sec  90.0 MBytes   755 Mbits/sec    0    993 KBytes       
[  5]   9.00-10.00  sec  88.8 MBytes   744 Mbits/sec    0    993 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   898 MBytes   754 Mbits/sec    0             sender
[  5]   0.00-10.01  sec   896 MBytes   751 Mbits/sec                  receiver

ZeroTier

Connecting to host 10.80.246.34, port 5201
[  5] local 10.80.246.38 port 35474 connected to 10.80.246.34 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  59.9 MBytes   503 Mbits/sec  338    102 KBytes       
[  5]   1.00-2.00   sec  60.2 MBytes   505 Mbits/sec  313    188 KBytes       
[  5]   2.00-3.00   sec  63.9 MBytes   536 Mbits/sec  176   99.3 KBytes       
[  5]   3.00-4.00   sec  74.3 MBytes   623 Mbits/sec  174    113 KBytes       
[  5]   4.00-5.00   sec  67.7 MBytes   568 Mbits/sec  197   83.2 KBytes       
[  5]   5.00-6.00   sec  72.5 MBytes   609 Mbits/sec  218    228 KBytes       
[  5]   6.00-7.00   sec  61.3 MBytes   514 Mbits/sec  281   77.8 KBytes       
[  5]   7.00-8.00   sec  72.0 MBytes   604 Mbits/sec  213   91.2 KBytes       
[  5]   8.00-9.00   sec  65.4 MBytes   549 Mbits/sec  309    156 KBytes       
[  5]   9.00-10.00  sec  53.9 MBytes   453 Mbits/sec  190    121 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   651 MBytes   546 Mbits/sec  2409             sender
[  5]   0.00-10.01  sec   650 MBytes   545 Mbits/sec                  receiver

NetMaker

Netmaker internally uses a normal (kernel-based) wireguard connection, so in some respect this is a test of Wireguard performance

Connecting to host 10.230.113.3, port 5201
[  5] local 10.230.113.1 port 35534 connected to 10.230.113.3 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   105 MBytes   881 Mbits/sec    0   1.01 MBytes       
[  5]   1.00-2.00   sec   104 MBytes   870 Mbits/sec   86    422 KBytes       
[  5]   2.00-3.00   sec   101 MBytes   849 Mbits/sec    0    488 KBytes       
[  5]   3.00-4.00   sec  98.8 MBytes   828 Mbits/sec    0    535 KBytes       
[  5]   4.00-5.00   sec  98.8 MBytes   828 Mbits/sec    0    584 KBytes       
[  5]   5.00-6.00   sec   104 MBytes   870 Mbits/sec    0    615 KBytes       
[  5]   6.00-7.00   sec  97.5 MBytes   818 Mbits/sec    7    472 KBytes       
[  5]   7.00-8.00   sec   104 MBytes   870 Mbits/sec    0    522 KBytes       
[  5]   8.00-9.00   sec   101 MBytes   849 Mbits/sec    0    580 KBytes       
[  5]   9.00-10.00  sec   102 MBytes   860 Mbits/sec    0    606 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  1016 MBytes   852 Mbits/sec   93             sender
[  5]   0.00-10.00  sec  1014 MBytes   850 Mbits/sec                  receiver

 Tailscale

Tailscale 1.28.0 has been used for this test.

During this test, I ensured that the tailscale connection was established using the switched network and was not going through a DERP server or the routed network.

$ tailscale ping 100.64.0.3
pong from vm (fd5d:7b60:4742::3) via 10.9.2.103:41641 in 1ms

Results:

Connecting to host 100.64.0.3, port 5201
[  5] local 100.64.0.2 port 40690 connected to 100.64.0.3 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  38.3 MBytes   321 Mbits/sec  389   60.0 KBytes       
[  5]   1.00-2.00   sec  37.6 MBytes   315 Mbits/sec  366   43.2 KBytes       
[  5]   2.00-3.00   sec  36.7 MBytes   308 Mbits/sec  431   52.8 KBytes       
[  5]   3.00-4.00   sec  38.5 MBytes   323 Mbits/sec  488   80.3 KBytes       
[  5]   4.00-5.00   sec  29.3 MBytes   246 Mbits/sec  356   38.4 KBytes       
[  5]   5.00-6.00   sec  31.0 MBytes   260 Mbits/sec  351   86.3 KBytes       
[  5]   6.00-7.00   sec  27.1 MBytes   227 Mbits/sec  287   50.4 KBytes       
[  5]   7.00-8.00   sec  26.1 MBytes   219 Mbits/sec  210   46.8 KBytes       
[  5]   8.00-9.00   sec  27.1 MBytes   227 Mbits/sec  261   39.6 KBytes       
[  5]   9.00-10.00  sec  27.5 MBytes   231 Mbits/sec  222   40.8 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   319 MBytes   268 Mbits/sec  3361             sender
[  5]   0.00-10.01  sec   318 MBytes   267 Mbits/sec                  receiver

Summary

The approximate performance expectation in this specific scenario is:

  • Tailscale: 300 Mbit/s
  • ZeroTier: 550 Mbit/s
  • Netmaker: 850 Mbit/s
  • Direct switched network: 750 Mbit/s

Curiously, netmaker performed better than the direct connection. The reason for this is not known at this point, but a similar effect has been observed in this medium.com article.

Generally, one can see that Tailscale (which internally uses software wireguard) is approximately half the speed of ZeroTier, which in turn is outperformed significantly by Netmaker.

In a followup post I will describe advantages and disadvantages of those solutions and explore under which scenarios I would use the solutions.

Posted by Uli Köhler in Headscale, Networking, Wireguard, ZeroTier

How to install Tailscale on Ubuntu in less than 1 minute

Just run this sequence of commands to install tailscale. This will automatically determine the correct Ubuntu version

curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(lsb_release -sc).gpg | sudo apt-key add -
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(lsb_release -sc).list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt-get update
sudo apt-get install tailscale

 

Posted by Uli Köhler in Networking, Wireguard

How to setup headscale server in 5 minutes using docker-compose

This headscale setup is using sqlite – with a much lighter memory & CPU footprint than PostgreSQL for simple usecases, I recommend this for almost any installation: Headscale doesn’t have to manage that many requests and using sqlite3 is fine for all but the most demanding setups.

First, create the directory where headscale and all the data will reside in (we use /opt/headscale in this example).

sudo mkdir -p /opt/headscale

Now run the following script in /opt/headscale to initialize the files and directories headscale requires:

mkdir -p ./config
touch ./config/db.sqlite
curl https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml -o ./config/config.yaml

docker-compose config

Now it’s time to create /opt/headscale/docker-compose.yml:

version: '3.5'
services:
  headscale:
    image: headscale/headscale:latest
    volumes:
      - ./config:/etc/headscale/
      - ./data:/var/lib/headscale
    ports:
      - 27896:8080
    command: headscale serve
    restart: unless-stopped

This will configure headscale to run its HTTP server on port 27896. You can reverse proxy this port to the domain of your choice.

Configuration

Now we should edit the server name in config/config.yaml:

server_url: https://headscale.mydomain.com

Note that you need to restart tailscale after each

Next, see How to create namespace on headscale server for details on how you can create a namespace. Once you have created a namespace (comparable to an account on the commercial tailscale service), you can continue connecting clients (the client software is called tailscale), see e.g. How to connect tailscale to headscale server on Linux

Autostart

Using the method described in our previous post Create a systemd service for your docker-compose project in 10 seconds we will now setup autostart on boot for headscale using systemd. This command will also start it immediately:

curl -fsSL https://techoverflow.net/scripts/create-docker-compose-service.sh | sudo bash /dev/stdin

How to view the logs

Use this command to view & follow the logs:

docker-compose logs -f

Example output

headscale_1  | [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
headscale_1  | 
headscale_1  | [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
headscale_1  |  - using env:    export GIN_MODE=release
headscale_1  |  - using code:   gin.SetMode(gin.ReleaseMode)
headscale_1  | 
headscale_1  | [GIN-debug] GET    /metrics                  --> github.com/zsais/go-gin-prometheus.prometheusHandler.func1 (4 handlers)
headscale_1  | [GIN-debug] GET    /health                   --> github.com/juanfont/headscale.(*Headscale).Serve.func2 (4 handlers)
headscale_1  | [GIN-debug] GET    /key                      --> github.com/juanfont/headscale.(*Headscale).KeyHandler-fm (4 handlers)
headscale_1  | [GIN-debug] GET    /register                 --> github.com/juanfont/headscale.(*Headscale).RegisterWebAPI-fm (4 handlers)
headscale_1  | [GIN-debug] POST   /machine/:id/map          --> github.com/juanfont/headscale.(*Headscale).PollNetMapHandler-fm (4 handlers)
headscale_1  | [GIN-debug] POST   /machine/:id              --> github.com/juanfont/headscale.(*Headscale).RegistrationHandler-fm (4 handlers)
headscale_1  | [GIN-debug] GET    /oidc/register/:mkey      --> github.com/juanfont/headscale.(*Headscale).RegisterOIDC-fm (4 handlers)
headscale_1  | [GIN-debug] GET    /oidc/callback            --> github.com/juanfont/headscale.(*Headscale).OIDCCallback-fm (4 handlers)
headscale_1  | [GIN-debug] GET    /apple                    --> github.com/juanfont/headscale.(*Headscale).AppleMobileConfig-fm (4 handlers)
headscale_1  | [GIN-debug] GET    /apple/:platform          --> github.com/juanfont/headscale.(*Headscale).ApplePlatformConfig-fm (4 handlers)
headscale_1  | [GIN-debug] GET    /swagger                  --> github.com/juanfont/headscale.SwaggerUI (4 handlers)
headscale_1  | [GIN-debug] GET    /swagger/v1/openapiv2.json --> github.com/juanfont/headscale.SwaggerAPIv1 (4 handlers)
headscale_1  | [GIN-debug] GET    /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] POST   /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] PUT    /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] PATCH  /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] HEAD   /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] OPTIONS /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] DELETE /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] CONNECT /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | [GIN-debug] TRACE  /api/v1/*any              --> github.com/gin-gonic/gin.WrapF.func1 (5 handlers)
headscale_1  | 2022-01-16T19:04:04Z WRN Listening without TLS but ServerURL does not start with http://
headscale_1  | 2022-01-16T19:04:04Z INF listening and serving (multiplexed HTTP and gRPC) on: 0.0.0.0:8080
headscale_1  | 2022-01-16T19:04:04Z INF Setting up a DERPMap update worker frequency=86400000

 

Posted by Uli Köhler in Headscale, Networking, VPN, Wireguard

TPLink WDR3600 OpenWRT wireguard throughput benchmark

TechOverflow tested Wireguard bandwidth / throughput on the TPLink WDR3600 with OpenWRT 21.02, based on a standard iperf3 TCP benchmark. We did not use Pre-shared keys in this setup.

So far we were able to verify that the Wireguard bandwidth is approximately 27Mbit/s (unidirectional), measured using iperf3.

Connecting to host 192.168.239.254, port 5201
[  5] local 10.9.1.104 port 57502 connected to 192.168.239.254 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  3.48 MBytes  29.2 Mbits/sec    0    215 KBytes       
[  5]   1.00-2.00   sec  3.86 MBytes  32.4 Mbits/sec    0    387 KBytes       
[  5]   2.00-3.00   sec  3.13 MBytes  26.2 Mbits/sec    0    470 KBytes       
[  5]   3.00-4.00   sec  3.37 MBytes  28.3 Mbits/sec    0    470 KBytes       
[  5]   4.00-5.00   sec  3.31 MBytes  27.8 Mbits/sec    0    470 KBytes       
[  5]   5.00-6.00   sec  3.31 MBytes  27.8 Mbits/sec    0    470 KBytes       
[  5]   6.00-7.00   sec  3.31 MBytes  27.8 Mbits/sec    0    470 KBytes       
[  5]   7.00-8.00   sec  2.76 MBytes  23.1 Mbits/sec    0    470 KBytes       
[  5]   8.00-9.00   sec  3.31 MBytes  27.8 Mbits/sec    0    470 KBytes       
[  5]   9.00-10.00  sec  2.76 MBytes  23.1 Mbits/sec    0    470 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  32.6 MBytes  27.4 Mbits/sec    0             sender
[  5]   0.00-10.14  sec  32.0 MBytes  26.4 Mbits/sec                  receiver

During the test, top consistently showed 0% idle CPU load, with the load being approximately 51% sys and 49% sirq.

The commands in use were

iperf3 -s

on the WDR3600 and

iperf -c [IP address of WDR3600]

on the client.

Posted by Uli Köhler in Networking, Wireguard

How to install wireguard_watchdog on OpenWRT

Run this on your OpenWRT router to automatically re-resolve DNS names for peers.

/usr/bin/wireguard_watchdog is automatically installed with the standard wireguard package, so you only need to enable it to run every minute:

echo '* * * * * /usr/bin/wireguard_watchdog' >> /etc/crontabs/root

Source: This commit message.

Posted by Uli Köhler in Wireguard

How to install Wireguard on OpenWRT

Install using

opkg update
opkg install luci-proto-wireguard

 

Posted by Uli Köhler in Networking, Wireguard

How to check if WireGuard client/peer is connected?

You can use wg show to check if a client is connected:

interface: Computer
  public key: X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=
  private key: (hidden)
  listening port: 19628

peer: H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
  endpoint: 10.9.1.108:19628
  allowed ips: 10.217.59.2/32
  latest handshake: 27 seconds ago
  transfer: 13.19 MiB received, 12.70 MiB sent
  persistent keepalive: every 1 minute

Look for this line:

latest handshake: 27 seconds ago

If it’s less than two minutes old, the client is connected.

If the latest handshake line is missing entirely, the peer has never connected successfully!

If in doubt, you can often ping the client to verify. It depends on the client configuration and possibly firewall settings if it will answer the ping but it never hurts to try.

Posted by Uli Köhler in Networking, Wireguard

ESP32 Wireguard example with HTTP access over Wireguard (PlatformIO)

In this example we will use Wireguard-ESP32-Arduino in order to make HTTP requests over Wireguard on the ESP32.

[env:esp32-gateway]
platform = espressif32
board = esp32-gateway
framework = arduino
monitor_speed = 115200
lib_deps =
    ciniml/[email protected]^0.1.5
#include <WiFi.h>
#include <WireGuard-ESP32.h>

// WiFi configuration --- UPDATE this configuration for your WiFi AP
char ssid[] = "MyWifiESSID";
char password[] = "my-wifi-password";

// WireGuard configuration --- UPDATE this configuration from JSON
char private_key[] = "gH2YqDa+St6x5eFhomVQDwtV1F0YMQd3HtOElPkZgVY=";
IPAddress local_ip(10, 217, 59, 2);
char public_key[] = "X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=";
char endpoint_address[] = "192.168.178.133"; // IP of Wireguard endpoint to connect to.
int endpoint_port = 19628;

static WireGuard wg;

void setup()
{
    Serial.begin(115200);
    Serial.println("Connecting to the AP...");
    WiFi.begin(ssid, password);
    while( !WiFi.isConnected() ) {
        delay(100);
    }
    Serial.println(WiFi.localIP());
    Serial.println("Adjusting system time...");
    configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com");

    Serial.println("Connected. Initializing WireGuard...");
    wg.begin(
        local_ip,
        private_key,
        endpoint_address,
        public_key,
        endpoint_port);
}

void loop()
{
    WiFiClient client;

    /**
     * Connect to
     * python3 -m http.server
     */
    if( !client.connect("10.217.59.1", 8000) ) {
        Serial.println("Failed to connect...");
        delay(1000);
        return;
    } else { // Client connected successfully. Send dummy HTTP request.
        client.write("GET /wireguard-test HTTP/1.1\r\n");
        client.write("Host: wireguard.test.com\r\n");
        client.write("\r\n\r\n");
    }

}

Remember to replace 192.168.238.133 by the IP address of the computer your ESP32 should connect to (i.e. the computer running WireGuard). You also need to enter the correct Wifi credentials.

On the computer, deploy this WireGuard config:

[Interface]
# Name = Computer
PrivateKey = ONj6Iefel47uMKtWRCSMLan2UC5eW3Fj9Gsy9bqcyEc=
Address = 10.217.59.1/24
ListenPort = 19628

[Peer]
# Name = ESP32
PublicKey = H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
AllowedIPs = 10.217.59.2/32
PersistentKeepalive = 60

which is auto-generated by the following GuardMyWire config:

{
    "rules": {
        "Node": {
            "connect_to": ["*"],
            "keepalive": 60
        }
    },
    "peers": [
        {
            "name": "Computer",
            "endpoint": "192.168.178.233:19628",
            "addresses": [
                "10.217.59.1/24"
            ],
            "type": "Node",
            "interface_name": "wg0"
        }, {
            "name": "ESP32",
            "addresses": [
                "10.217.59.2/24"
            ],
            "type": "Node",
            "interface_name": "wg0"
        }
    ]
}

Enable this config and start a Python HTTP server to receive the requests using

python3 -m http.server

Now flash the firmware on the ESP32.

Using wg show you should see the ESP connecting:

interface: Computer
  public key: X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=
  private key: (hidden)
  listening port: 19628

peer: H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
  endpoint: 10.9.1.108:19628
  allowed ips: 10.217.59.2/32
  latest handshake: 5 seconds ago
  transfer: 11.71 MiB received, 10.43 MiB sent
  persistent keepalive: every 1 minute

Look for the

latest handshake: 5 seconds ago

line.

On the shell running python3 -m http.server you should see the dummy HTTP requests:

10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
Posted by Uli Köhler in ESP8266/ESP32, PlatformIO, Wireguard

How to update WireGuard peer endpoint address using DNS on MikroTik RouterOS

Assuming your peer comment is peer1 and the correct endpoint DNS record is peer1.mydomain.com, you can use this RouterOS script to update the endpoint based on the DNS record:

:if ([interface wireguard peers get number=[find comment=peer1] value-name=endpoint-address] != [resolve peer1.mydomain.com]) do={
    interface wireguard peers set number=[find comment=peer1] endpoint-address=[/resolve peer1.mydomain.com]
}

Modify the names like peer1 and peer1.mydomain.com in that script, then add it as a new script in System -> Scripts, then add a Scheduler to run the script e.g. every 30 seconds under System -> Scheduler

Script settings

Scheduler settings

Related posts which might make the process easier to understand:

Posted by Uli Köhler in MikroTik, Wireguard

How to check if WireGuard Peer endpoint address equals DNS record using RouterOS scripting on MikroTik

Assuming your peer comment is peer1 and the correct endpoint DNS record is peer1.mydomain.com:

([interface wireguard peers get number=[find comment=peer1] value-name=endpoint-address] = [resolve peer1.mydomain.com])

This will return true if the peer endpoint is the same as the DNS record.

Example

[[email protected]] > :put ([interface wireguard peers get number=[find comment=peer1] value-name=endpoint-address] = [resolve peer1.mydomain.com])
true
Posted by Uli Köhler in MikroTik, Wireguard

RouterOS scripting: How to get Wireguard peer endpoint address on MikroTik

We assume that the peer you want to find info about has comment=peer1.mydomain.com. Use

Use

interface wireguard peers get number=[find comment=peer1.mydomain.com] value-name=endpoint-address

or use :put [...] to print the value:

:put [interface wireguard peers get number=[find comment=peer1.mydomain.com] value-name=endpoint-address]

Example

[[email protected]] > :put [interface wireguard peers get number=[find comment=peer1.mydomain.com] value-name=endpoint-address]
12.245.102.141

 

Posted by Uli Köhler in MikroTik, Wireguard

How to automatically re-resolve DNS in Wireguard on Linux

When installing wireguard-tools on Linux, it includes a script called reresolve-dns.sh. This will take care of automatically re-resolving.

According to its documentation, you should run it every 30 seconds or so.

So we can just create a systemd timer to run it every 30 seconds.

Easy way

Use our script

wget -qO- https://techoverflow.net/scripts/install-wireguard-reresolve-dns.sh | sudo bash /dev/stdin

Now you need to enable it for each relevant interface separately, for example for wg0:

systemctl enable --now [email protected]

Hard way

Do manually what our script does.

Create /etc/systemd/system/[email protected]:

[Unit]
[email protected]

[Service]
Type=oneshot
ExecStart=/usr/share/doc/wireguard-tools/examples/reresolve-dns/reresolve-dns.sh %i

Create /etc/systemd/system/[email protected]:

[Unit]
[email protected] timer
[Timer]
[email protected]%i.service
OnCalendar=*-*-* *:*:00,30
Persistent=true
[Install]
WantedBy=timers.target

Now you need to enable it for each relevant interface separately, for example for wg0:

systemctl enable --now [email protected]
Posted by Uli Köhler in Networking, systemd, VPN, Wireguard

Who is client and who is server in Wireguard?

Wireguard doesn’t really use the concept of client and server the same way OpenVPN does. A wireguard interface does not have a fixed role as client or server – think about it like this:

  • A wireguard connection is a link between two peers
  • One wireguard interface can host one or many connections

For a single connection:

  • connection can be considered a client if it knows a fixed endpoint (IP address or hostname) to connect to, i.e. if you have Endpoint set in your wireguard config like this:
    Endpoint = vpn.mydomain.com:31265

    client will take the initiative and send packets to the server without having received any packet from the server beforehand – just like in classical VPNs.

  • connection can be considered a server if it doesn’t have an Endpoint set to connect to. A server will learn which IP address to send packets to once a client has completed the handshake. If a client IP address changes, the server will learn the new IP address as soon as it receives a validated packet from the client.

Most real-world wireguard connections have one client and one server. There are exceptions to this, namely if both endpoints have a static IP address or fixed host name, so both wireguard instances always know which IP address or hostname to send packets to.

Posted by Uli Köhler in Networking, VPN, Wireguard

What to look for in “wg show” output?

This is an example wg show output:

interface: MyVPN
  public key: xJ+A//t9RbOU4ISIr61tsZwc8SPLbLONXhknnU1QvBQ=
  private key: (hidden)
  listening port: 12073

peer: xgmml6wPoe9auL5oGhqScQXLByfrI/1xq3sOJzYaNhE=
  endpoint: 77.55.81.22:23711
  allowed ips: 10.178.212.1/32, 10.39.24.0/24
  latest handshake: 37 seconds ago
  transfer: 948 B received, 1.40 KiB sent
  persistent keepalive: every 30 seconds

This is what I look for:

  • Is the desired wireguard interface present? If not, this indicates that either the computer doesn’t even try to start the interface (e.g. because autostart is not enabled) or starting it fails, for example because the route is already defined
  • Are the desired peers listed? If not, this is always a configuration error
  • Is persistent keepalive enabled? Without persistent keepalive, you will not be able to properly debug Wireguard because no packets will be sent unless some traffic is going through the interface. Therefore, I strongly recommend to always enable persistent keepalive even if you plan to disable it later!
  • Is latest handshake listed and recent? Not being able to handshake with a remote peer typically indic-ates either a network problem or a configuration problem, but in some cases it’s also a system-related problem:
    • System problems: Is wireguard interface on the local & remote side up & configured?
    • Networking problems: Port not forwarded to destination machine, TCP port instead of UDP port forwarded, local or remote internet access is firewalled, incorrect port given, incorrect IP address or hostname given, DynDNS hostname not updated, Wireguard tries to access IPv6 address but only IPv4 port is forwarded properly (check using host)
    • Wireguard configuration problem: Does the remote peer use the correct private key that matches the public key in the local configuration? Does the remote configuration have listed the local public key as peer at all? Does the local configuration have the correct private key that matches the public key listed in the remote config? Does the peer public key match the endpoint (if specified) or maybe the key doesn’t match the endpoint?
  • transfer should show >0 bytes received and sent! This is typically equivalent to the latest handshake debugging method. Bytes being sent but no bytes being received typically indicates that the Wireguard interface is trying to perform an handshake but does not get any reply back.

Also see my WireguardConfig project which makes this kind of configuration much easier

Posted by Uli Köhler in Networking, VPN, Wireguard

Install & autostart Wireguard config on Ubuntu or Debian

We will assume that you already have a wireguard config file, e.g. MyVPN.conf

  1. Copy MyVPN.conf to /etc/wireguard/MyVPN.conf:
    sudo cp MyVPN.conf /etc/wireguard/MyVPN.conf
  2. Start & enable (i.e. autostart) service:
    sudo systemctl enable --now [email protected]
  3. Check if it works using
    sudo wg show

Example wg-show output

interface: MyVPN
  public key: xJ+A//t9RbOU4ISIr61tsZwc8SPLbLONXhknnU1QvBQ=
  private key: (hidden)
  listening port: 12073

peer: xgmml6wPoe9auL5oGhqScQXLByfrI/1xq3sOJzYaNhE=
  endpoint: 77.55.81.22:23711
  allowed ips: 10.178.212.1/32, 10.39.24.0/24
  latest handshake: 37 seconds ago
  transfer: 948 B received, 1.40 KiB sent
  persistent keepalive: every 30 seconds

 

Posted by Uli Köhler in Networking, VPN, Wireguard

What does WireGuard AllowedIPs actually do?

Wireguard’s allowed_ips field does two different things. Let’s consider the following WireGuard config (generated by the WireguardConfig Site2Site example):

[Interface]
# Name = office1.mydomain.org
PrivateKey = ......
Address = 10.82.85.1/24
ListenPort = 19628

[Peer]
# Name = office2.mydomain.org
PublicKey = ...
AllowedIPs = 10.82.85.2/32, 192.168.200.0/24
PersistentKeepalive = 60

We can see that for the peer office2.mydomain.org the AllowedIPs field is set to 10.82.85.2/32, 192.168.200.0/24.

AllowedIPs does two things:

  • It adds a route to the given networks, i.e. packets addressed to 10.82.85.2/32 or to 192.168.200.0/24 will be routed through the WireGuard interface to that peer
  • It will allow packets with the source IPs 10.82.85.2/32 or 192.168.200.0/24 to be routed from the given peer on the WireGuard interface

Note especially the second point. Any packet from the given peer with a source IP address which is not listed in AllowedIPs will be discarded! While this does not replace a firewall, it serves a an integral part of Wireguard’s security model.

Posted by Uli Köhler in VPN, Wireguard

How to migrate from OpenVPN to Wireguard for Site-to-Site VPNs

The following diagram will assist you in transitioning your VPNs from OpenVPN to Wireguard.

Many users have difficulties in grasping the allowed_ips concept, even though it’s mostly similar to OpenVPN’s route and the architecture where no. In most usecases, you can consider any WireGuard instance with ListenPort = ... to be a server and any WireGuard instance with Endpoint = ... defined for a given peer as client.

Diagram source

The WireGuard config is available as WireguardConfig example Site2Site.json

Posted by Uli Köhler in OpenVPN, VPN, Wireguard

How to autostart Wireguard using systemd (wg-quick)

If you’ve added a wg-quick config, e.g. /etc/wireguard/wg0.conf, you can enable autostarting it on system boot using systemd:

sudo systemctl enable --now [email protected]

If you have started Wireguard with this config manually before, you need to shut it down first or systemd will not be able to start it !

Posted by Uli Köhler in Networking, systemd, Wireguard

Real-world data on CRS309-1G-8S+ RouterOS Wireguard throughput

Also see Wireguard bandwidth performance of the MikroTik CRS326-24G-2S+

We tested the throughput of the new Wireguard functionality MikroTik CRS309-1G-8S+ running on RouterOS 7.1beta6.

Our test setup consists of a Desktop PC with 1GBase-T connection and a virtualized server on XCP-NG, attached with a 10GB shared connection, both running Ubuntu. Note that the L2 switching infrastructure (consisting only of MikroTik CRS3xx and CRS610 switching with complete hardware offloading) is ignored here because due to 100% hardware offloading to the marvelous Marvell switch chips it has orders of magnitude higher performance compared to any L3 function, hence it will only have minimal impact only the overall performance.

Wireguard was being used without preshared keys. Hitherto, it is unknown to us whether PSKs will have an impact on throughput.

The command on the Desktop was

dd if=/dev/urandom bs=100M | netcat -v 10.185.244.199 2222

whereas the command on the server was

netcat -vvnlp 2222 > /dev/null

As we expected with an uncompressed protocol like Wireguard, there is no difference if you pipe the data from /dev/urandom as opposed to /dev/zero.

Scenario: Routing from Wireguard to local routed VLAN

With IP firewall

The Desktop was connected to the CRS309-1G-8S+ using Wireguard. The virtual server was connected to the CRS309 as default gateway within a separate VLAN that was designed to be routed. The CRS309 L3 hardware offloading capability was disabled.

The IP firewall contained 8 simple accept and fasttrack rules. All the WireGuard traffic only matched the last (8th) rule and was accepted. It has not been tested whether fasttracking the Wireguard connection would increase performance

The throughput results showed a steady rate of 131 Mbit/s (unidirectional, bidirectional not tested), but up to 160 Mbit/s. It is unknown what caused the increase in speed, but it’s possible that additional traffic was L3-forwarded over the switch during the test.

Without IP firewall

The same test was repeated with the IP firewall being disabled in the Bridge Settings.

As expected, disabling additional IP firewall processing caused the throughput to increase, but only by a small margin. The typical speed was around 160 Mbit/s (unidirectional), with peaks up to 185 Mbit/s.

Conclusion

It should be pretty obvious that the CRS309-1G-S+ outperforms most conventional VPN solutions when using Wireguard. For a street price of ~175€, it is not only an awesome switch, but also doubles as a more than adequate Wireguard router for most practical applications.

Reliablity considerations

Note that at the moment of writing this article, Wireguard is only available in the RouterOS 7.1beta6 firmware, which is not yet considered stable. While I have not experienced any problems that have affected reliability in any way, if you run a network where it hurts if it fails, you should consider using alternative solutions in the meantime.

Posted by Uli Köhler in MikroTik, Networking, VPN, Wireguard