WireGuard VPN
WireGuard хоть и называется VPN-ом, но по сути это просто туннель между двумя узлами. Ключи и адреса нужно указывать на обоих сторонах туннеля, т.к. функционала передачи параметров и ключей в нем нет. Дальше маршрутизацией на клиентской стороне трафик заворачивается в туннель, а на серверной стороне включается маскарадинг сетевых адресов (NAT). За счет отказа от функционала передачи ключей и параметром получается довольно простая настройка.
Генерация ключей
Окружение Nix:
user@machine:~$ nix-shell -p wireguard-tools
Генерируем пару ключей, публичный ключ генерируется из приватного:
[nix-shell:~]$ wg genkey
KFowPfMqvcfF0Zz/VuuxugZxwQ1GosKJzkyKjpBC3lY=
[nix-shell:~]$ echo -n KFowPfMqvcfF0Zz/VuuxugZxwQ1GosKJzkyKjpBC3lY= | wg pubkey
vzC6SdkNri5nWHi2sAK7QRJDsdggtEyszMMPA36yySo=
Сервер на NixOS
{
...
# enable NAT
networking.nat.enable = true;
networking.nat.externalInterface = "ens3";
networking.nat.internalInterfaces = [ "wg0" ];
networking.firewall.allowedUDPPorts = [ 51820 ];
networking.wireguard.interfaces = {
# "wg0" is the network interface name. You can name the interface arbitrarily.
wg0 = {
# Determines the IP address and subnet of the server's end of the tunnel interface.
ips = [ "10.100.0.1/24" ];
# The port that WireGuard listens to. Must be accessible by the client.
listenPort = 51820;
# This allows the wireguard server to route your traffic to the internet and hence be like a VPN
# For this to work you have to set the dnsserver IP of your router (or dnsserver of choice) in your clients
postSetup = ''
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o ens3 -j MASQUERADE
'';
# This undoes the above command
postShutdown = ''
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o ens3 -j MASQUERADE
'';
privateKey = "server_private_key";
peers = [
{
publicKey = "home_pc_public_key";
allowedIPs = [ "10.100.0.2/32" ];
}
{
publicKey = "phone_public_key";
allowedIPs = [ "10.100.0.3/32" ];
}
];
};
};
}
Клиент
Поднятие и настройка туннеля осуществляется утилитой wq-quick. Для нее нужно написать небольшой конфиг:
[Interface]
Address = 10.100.0.2/32
PrivateKey = home_pc_private_key
DNS = 1.1.1.1, 8.8.8.8
[Peer]
EndPoint = kysa.me:51820
PublicKey = server_public_key
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 1
Опция allowedIPs = [ "0.0.0.0/0" ]
- заворачивает весь трафик в туннель (используя маршрутизацию на основе меток пакетов). Рассмотрим это на примере лога поднятия туннеля при помощи wq-quick:
user@machine:~$ nix-shell -p wireguard-tools
[nix-shell:~]$ sudo `which wg-quick` wg.kysa.me.conf
[#] ip link add wg.kysa.me type wireguard
[#] wg setconf wg.kysa.me /dev/fd/63
[#] ip -4 address add 10.100.0.2/32 dev wg.kysa.me
[#] ip link set mtu 1420 up dev wg.kysa.me
[#] resolvconf -a wg.kysa.me -m 0 -x
[#] wg set wg.kysa.me fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg.kysa.me table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
[#] iptables-restore -n
Трафик интерфейса wg.kysa.me помечается меткой 51820 (строка 8) чтобы в дальнейшем различать wireguard-пакеты и отправлять их по обычному маршруту. Добавляется таблица маршрутизации с именем 51820, в нее помещается дефолтный маршрут, указывающий в качестве шлюза интерфейс wg.kysa.me (строка 9). Трафик без метки 51820 (не wireguard-пакеты) отправляется в таблицу 51820 (строка 10). Следующая строка (11) добавляет правило поиска маршрута сначала в таблице main и если таковой найден с префиксом нулевой длинны (default route), то отбросить его и использовать следующие правила (таблица 51820). Если же префикс маршрута, найденного в таблице main длиннее (нуля), то он используется для маршрутизации. Это правило обеспечивает работу уже существующих маршрутов (например еще один VPN). Итоговая таблица правил маршрутизации выглядит так:
[nix-shell:~]$ ip rule
0: from all lookup local
32764: from all lookup main suppress_prefixlength 0
32765: not from all fwmark 0xca6c lookup 51820
32766: from all lookup main
32767: from all lookup default
Строки 3 и 4 добавлены при поднятия туннеля утилитой wg-quick. Правило в строке 3 обеспечивает работу существующих специфичных маршрутов, правило в строке 4 отправляет НЕ wireguard-трафик в таблицу 51820. Подробней об маршрутизации можно почитать тут.
Опция PersistentKeealive = 1
включает периодическую (в данном случаи раз в секунду) отправку пакета для поддержания соединения. Т.к. WireGuard работает через state-less протокол UDP, а клиенты как правило находятся за NAT (домашний роутер, NAT провайдера), то для получения пакетов от сервера, в таблице трансляции NAT все время должна присутствовать запись, указывающая на какой узел за NAT отправлять входящие пакеты. Эта запись добавляется при первой отправке пакета от клиента к серверу и удаляется спустя некоторое время (10-25 секунд) простоя. Включение этой опции не дает туннелю простаивать и решает проблему удаления записи из таблицы трансляции NAT.
Android клиент
Клиент вот этот. Настраивается аналогично компу. Еще в нем есть возможность считать настройки из QR-кода. Для этого в линуксе есть утилитка с незамысловатым названием qrencode.
user@machine:~$ nix-shell -p qrencode
[nix-shell:~]$ cat phone.wg.kysa.me.conf
[Interface]
Address = 10.100.0.2/32
PrivateKey = KFowPfMqvcfF0Zz/VuuxugZxwQ1GosKJzkyKjpBC3lY=
DNS = 1.1.1.1, 8.8.8.8
[Peer]
EndPoint = kysa.me:51820
PublicKey = vzC6SdkNri5nWHi2sAK7QRJDsdggtEyszMMPA36yySo=
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 1
[nix-shell:~]$ qrencode -t ansiutf8 < phone.wg.kysa.me.conf
Заглавная картинка взята с официального сайта.