Table of Contents

go back

Wireguard Intro

Wireguard is a free and libre software that allows to set up virtual private networks (VPN).

Wireguard adds virtual interfaces that manage encrypted traffic to and from other wireguard interfaces. Physically the traffic is sent via UDP datagrams, but applications treat the wireguard interfaces as any other interface.

By design, wireguard has a minimal set of features leaving many details in the hand of the user. In particular: key generation, key exchange, and to set up the routing.

Configuration

Wireguard interfaces are set up with configuration files that uses a ini syntax. In the ini file is a section called [Interface] that describes the interface itself and one or more [Peer] sections that describe from who can be reached and how.

Each interface comprises a asymmetrical key, the private key never leaves the computer hosting the interface, the public key is the main identification of each peer.

The connection between two interfaces is also protected by symmetric encryption. So each pair of wireguard interfaces need an extra key known to to both parties.

Generate keys

wg genkey generates the private key, wg pubkey generates its relative public key. (umask ensures that the keys are readable only by the user):

$ ( umask 0077; wg genkey | tee PrivateKey.key | wg pubkey > PublicKey.pub )

wg genkey by itself can be used for the symmetric key.

$ ( umask 0077; wg genkey > PresharedKey.key )

IP Addresses

Virtual Private Networks, as the name suggest, use IPs in the private space. There are multiple spaces and Wireguard supports both IP6 and IP4, but for most purposes to use the IP addresses in the 10.0.0.0/8 block is sufficient.

Interface section

Here is an example of an [Interface] section of a Wireguard interface configuration.

[Interface]
PrivateKey = yBK+IcuZ2XBaghdJZfH551Veo8T/JXl48XJdMYjrQ0c=
#PublicKey = NYsczmRiSV+aekAoTs6uKA+CcXHmxJVLS6gRNpIQ3yM=
Address = 10.11.12.100/32
DNS = 1.1.1.1
ListenPort = 51820
MTU=1368

The private key identifies the interface, the public key is only a comment to have it handy. The DNS is arbitrary, but 1.1.1.1 is a easy-to-remember DNS service from Cloudfare.

The IP line is important; the value in CIDR notation is used both to identify the interface (the IP address) and for routing (the IP range). For example, /32 means the interface won't do any routing, /24 means the interface will route traffic to the addresses in the block from 10.11.12.0 to 10.11.12.255.

Peer sections

The peer sections are similar:

[Peer]
PublicKey = zqGcoTNCPbxx0rKxI3iH1ImV+KE1wGIroc6qts51Rzk=
PresharedKey = OKrM0kinDG5pUb/GwB1/yDC/X2e2lmPi8mpo/7HcjlE=
Endpoint = 1.2.3.4:51820
AllowedIPs = 10.11.12.0/24
PersistentKeepalive = 25

For Peers the AllowedIPs section is just for routing. The Endpoint value is used to reach the machine running the wireguard interface; it can omitted if it is expected that the machine will be reached from outside first (i.e., functions as a server).

IPtables

For firewalling a machine running Wireguard needs to be able to receive UDP datagrams in the 51820 port (or whence the physical interface is listening) and allow traffic to the Wireguard interface.

Besides, if routing is necessary (i.e., the [Interface] Address section is not a single IP) forward traffic should be allowed.

Here is an example, the relevant lines are indented:

# iptables-save
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
   -A INPUT -i wg0 -j ACCEPT
   -A INPUT -p udp -m udp --dport 51820 -j ACCEPT
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
   -A FORWARD -i wg0 -o wg0 -j ACCEPT
COMMIT

Forwarding needs to be enabled at kernel level.

# sysctl -w net.ipv4.ip_forward=1

If IPv6 is used:

# sysctl -w net.ipv6.conf.all.forwarding=1

Activating the Wireguard interface

The program to create or destroy the interfaces is wg-quick with the verb up to create and down to destroy the interface.

If the configuration file is in /etc/wireguard you can just use the interface name, otherwise you need to give the full path.

Finally wg executed by itself returns the current state of the wireguard interfaces.