FreeBSD: WireGuard VPN, Linux peer та routing між мережами

Автор |  18/12/2025
 

Продовжую налаштування свого домашнього сервера на FreeBSD 14.3, де планується мати NAS.

В попередньому пості FreeBSD: знайомство з Packet Filter (PF) firewall познайомились з фаєрволами, наступний крок – це налаштувати VPN для доступу.

Основна ідея – поєднати (нарешті!) мій “офіс” і квартиру, а пізніше, можливо, ще і підключити сервер, на якому зараз працює rtfm.co.ua – аби бекапи блогу і баз даних зберігати відразу на ZFS пулі з RAID домашнього сервера.

WireGuard vs OpenVPN

Коли діло дійшло до вибору який конкретно VPN сервер вибрати, то я спочатку думав взяти OpenVPN – бо працюю з ним не один рік, і на RTFM про нього навіть є якісь матеріали.

Але, трохи подумавши вирішив, що для домашнього VPN рішення типу OpenVPN або Pritunl будуть трохи оверхедом, і можна спробувати WireGuard.

Системи дуже різні, але якщо коротко, то:

  • WireGuard набагато менший по коду – наприклад, Linux-реалізація це близько 4000 строк в ядрі, тоді як в OpenVPN це близько 100,000 строк в user space
  • WireGuard працює як модуль ядра – обробка пакетів і криптографія виконуються безпосередньо в kernel space, а OpenVPN є user space сервісом і працює через TCP або UDP socket та взаємодіє з ядром через стандартний мережевий стек ядра
  • туди ж – шифрування, бо WireGuard має вбудовану криптографію, яка є частиною самого протоколу і працює в kernel space, а OpenVPN використовує стандартний SSL/TLS стек (OpenSSL, LibreSSL тощо) в user space, що додає складність і накладні витрати CPU/RAM
  • модель роботи WireGuard – peer-to-peer, тобто протокол не має вбудованих ролей “сервер” чи “клієнт”, є лише Peers з ключами і дозволеними IP, тоді як OpenVPN побудований навколо класичної клієнт-серверної архітектури

В результаті WireGuard можна сприймати не як окремий сервіс, а як зашифрований мережевий інтерфейс, тоді як OpenVPN залишається класичним прикладним VPN-сервісом.

Навіть офіційний документ по WireGuard названий “Next Generation Kernel Network Tunnel“.

Архітектура мережі

Отже, що в мене є:

  • “офіс”: окрема локальна мережа 192.168.0.0/24, на вході – роутер TP-LINK Archer AX12
    • в цій мережі є робочий ноутбук з Arch Linux і Lenovo ThinkCentre з FreeBSD
    • на FreeBSD буде NAS, NFS і, власне, саме WireGuard
      • хоча Archer AX12 має власні вбудовані OpenVPN і WireGuard – але хочеться зробити самому, руками, плюс все ж більше контролю
  • дома: там мережа 192.168.100.0/24, на вході точно такий же роутер Archer AX12
    • там єдиний клієнт – це домашній ноутбук з Arch Linux

І що я хочу зробити:

  • на FreeBSD буде WireGuard в ролі VPN-сервера
  • на роутері Archer AX12 буде NAT port-forwarding для підключення до WireGuard на FreeBSD
  • мережа VPN – 10.8.0.1/24
  • на FreeBSD – Paket Filter firewall для контролю трафіка
  • обидва ноутбуки повинні мати доступ один до одного і до майбутнього NAS на FreeBSD

Як це в результаті виглядає схематично:

Запуск WireGuard на FreeBSD

У FreeBSD (власне, як і в Linux) WireGuard – це kernel module + userspace tools: основна “робоча” частина завантажується як модуль ядра, а для роботи з ним встановлюється окремий пакет.

Встановлюємо wireguard-tools:

root@setevoy-nas:/home/setevoy # pkg install wireguard-tools

Завантажуємо модуль:

root@setevoy-nas:/home/setevoy # kldload if_wg

Перевіряємо:

root@setevoy-nas:/home/setevoy # kldstat | grep wg
 8    1 0xffffffff82a47000    2f5c0 if_wg.ko

Додаємо запуск WireGuard в /etc/rc.conf:

root@setevoy-nas:/home/setevoy # sysrc wireguard_enable=YES
wireguard_enable:  -> YES
root@setevoy-nas:/home/setevoy # sysrc wireguard_interfaces=wg0
wireguard_interfaces:  -> wg0

Поки не запускаємо – переходимо до налаштування мережі.

Network configuration

Далі треба налаштувати систему на роутинг пакетів між фізичним інтерфейсом та інтерфейсом WireGuard, і оновити конфіг фаєрвола.

Конфігурація IP forwarding

Додаємо IP forwarding з інтерфейсу wg0 (якого ще нема, з’явиться під час запуску WireGuard) на інтерфейс LAN, em0.

Оновлюємо автозапуск в /etc/rc.conf:

root@setevoy-nas:/usr/local/etc/wireguard # sysrc gateway_enable="YES"
gateway_enable: NO -> YES

Аби переадресація запрацювала зараз, без ребуту – вмикаємо її одразу з sysctl:

root@setevoy-nas:/usr/local/etc/wireguard # sysctl net.inet.ip.forwarding=1
net.inet.ip.forwarding: 0 -> 1

Перевіряємо:

root@setevoy-nas:/usr/local/etc/wireguard # sysctl net.inet.ip.forwarding
net.inet.ip.forwarding: 1

Наступний крок – налаштування Packet Filter.

Конфігурація Packet Filter

Отже, що у нас є:

  • мережа VPN: 10.8.0.0/24
  • мережа офісу, де FreeBSD/VPN: 192.168.0.0/24
    • FreeBSD LAN IP: 192.168.0.2
  • роутити інтернет через VPN не потрібно – тільки трафік між мережами дома і офісу

Конфіг pf зараз – мінімалістичний, з попереднього поста:

allowed_tcp_ports = "{ 22 }"

allowed_clients = "{ 192.168.0.0/24, 192.168.1.0/24 }"

set skip on lo

block all

# allow ssh only from specific hosts
pass in proto tcp from $allowed_clients to any port $allowed_tcp_ports keep state

# allow all outgoing traffic
pass out all keep state

Що до нього треба додати:

  • дозволити вхідні UDP-з’єднання на порт WireGuard (51820) для handshake
  • дозволити трафік з VPN-мережі 10.8.0.0/24 до самого FreeBSD-хоста (ping, SSH)
  • дозволити транзитний трафік з VPN-мережі 10.8.0.0/24 до локальних мереж офісу і дому (192.168.0.0/24 та 192.168.100.0/24)
  • дозволити ICMP і SSH з VPN-мережі та домашньої мережі до FreeBSD-хоста
  • дозволити вихідний трафік з FreeBSD

Я додав макроси в конфіг, але поки пишу і тестую – вказую всі порти та адреси явно прямо в конфігу, простіше читати.

Тепер /etc/pf.conf буде виглядати так:

##################
### Interfaces ###
##################
# lan_if = "em0"
# wg_if  = "wg0"

################
### Networks ###
################
# lan_net      = "192.168.0.0/24"
# home_net     = "192.168.100.0/24"
# wg_net       = "10.8.0.0/24"
# vpn_nets     = "{ 10.8.0.0/24, 192.168.100.0/24 }"

################
### Services ###
################
# ssh_ports = "{ 22 }"
# wg_port   = "51820"

######################
### Basic settings ###
######################

# do not filter loopback traffic
set skip on lo

######################
### Default policy ###
######################

# block everything by default
block all

#######################
### Inbound traffic ###
#######################

### SSH

# allow SSH from Office LAN (192.168.0.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.0.0/24 to (em0) port 22 keep state

# allow SSH from Home network (192.168.100.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.100.0/24 to (em0) port 22 keep state

# allow SSH from VPN clients to FreeBSD host
pass in on wg0 proto tcp from 10.8.0.0/24 to (wg0) port 22 keep state

### VPN 

# allow WireGuard handshake (UDP/51820) on LAN interface
pass in on em0 proto udp to (em0) port 51820 keep state

# allow VPN clients (10.8.0.0/24) to access FreeBSD host itself
# this allows ping, ssh, etc. to the wg0 address
pass in on wg0 from 10.8.0.0/24 to (wg0) keep state

# allow VPN clients to access Office LAN (192.168.0.0/24)
pass in on wg0 from 10.8.0.0/24 to 192.168.0.0/24 keep state

# allow VPN clients to access Home network (192.168.100.0/24)
pass in on wg0 from 10.8.0.0/24 to 192.168.100.0/24 keep state

# allow ICMP (ping) from VPN clients to FreeBSD host
pass in on wg0 proto icmp from 10.8.0.0/24 to (wg0) keep state

# allow ICMP (ping) from Home network to FreeBSD host
pass in on em0 proto icmp from 192.168.100.0/24 to (em0) keep state

############################
### outbound traffic ###
############################

# allow all outbound traffic from FreeBSD
pass out keep state

Перевіряємо синтаксис:

root@setevoy-nas:/home/setevoy # pfctl -vnf /etc/pf.conf
set skip on { lo }
block drop all
pass in log on em0 inet proto tcp from 192.168.0.0/24 to (em0) port = ssh flags S/SA keep state
pass in log on em0 inet proto tcp from 192.168.100.0/24 to (em0) port = ssh flags S/SA keep state
pass in on wg0 inet from 10.8.0.0/24 to (wg0) flags S/SA keep state
pass in on wg0 inet proto icmp from 10.8.0.0/24 to (wg0) keep state
pass in on wg0 inet from 10.8.0.0/24 to 192.168.0.0/24 flags S/SA keep state
pass in on wg0 inet from 10.8.0.0/24 to 192.168.100.0/24 flags S/SA keep state
pass in on em0 inet proto icmp from 192.168.100.0/24 to (em0) keep state
pass in on em0 proto udp from any to (em0) port = 51820 keep state
pass out all flags S/SA keep state

Виконуємо reload:

root@setevoy-nas:/home/setevoy # service pf reload
Reloading pf rules.

Тепер можемо підготувати запуск WireGuard.

Конфігурація WireGuard

Тут все дуже просто – створити ключі, написати конфіг-файл.

Створення ключів

Комунікація і криптографія у WireGuard побудована на стандартній схемі асиметричних ключів:

  • на “сервері” зберігається приватний ключі
  • на клієнті вказується публічний
  • під час handshake клієнт переконується, що підключився саме до того сервера, публічний ключ якого він знає
  • а далі, з цими ключами, відбувається і шифрування даних

Див. Key Exchange and Data Packets.

Слово “сервер” все ж беру в лапки, бо, як було зазначено вище – WireGuard це P2P, а не client-server.

Після установки wireguard-tools створюється каталог /usr/local/etc/wireguard – переходимо туди, і з wg genkey створюємо приватний та публічний ключ:

root@setevoy-nas:/home/setevoy # cd /usr/local/etc/wireguard
root@setevoy-nas:/usr/local/etc/wireguard # wg genkey | tee server.key | wg pubkey > server.pub

Міняємо права доступу до приватного ключа:

root@setevoy-nas:/usr/local/etc/wireguard # chmod 600 server.key

Перевіряємо:

root@setevoy-nas:/usr/local/etc/wireguard # chmod 600 server.key 
root@setevoy-nas:/usr/local/etc/wireguard # ll
total 12
-rw-------  1 root wheel  45 Dec 17 15:58 server.key
-rw-r--r--  1 root wheel  45 Dec 17 15:58 server.pub

Базовий конфіг для WireGuard

Можна створити кілька різних конфігурацій в /usr/local/etc/wireguard/, кожен на власному порті та/або IP та з власним ключем і мати кілька різних VPN-підключень, а керувати ними використовуючи ім’я файлу – wg0, wg1, etc.

Є навіть генератори конфігу – https://www.wireguardconfig.com.

Документація по синтаксису – Wireguard Configuration File Format.

Отримуємо приватний ключ:

root@setevoy-nas:/usr/local/etc/wireguard # cat server.key 
cLS***GQ=

Створюємо файл /usr/local/etc/wireguard/wg0.conf – поки тільки “сервер”:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = cLS***sGQ=

Блок Interface визначає параметри WireGuard-інтерфейсу wg0 – його IP-адресу, UDP-порт і приватний ключ, який використовується для шифрування трафіку.

Тут жеж можна вказати які DNS використовувати, чи робити апдейт в таблицях маршрутизації клієнтів (default – true) і запуск скриптів з PreUp, PostUp, PreDown, PostDown.

Запускаємо сам WireGuard:

root@setevoy-nas:/home/setevoy # wg-quick up wg0
[#] ifconfig wg create name wg0
[#] wg setconf wg0 /dev/stdin
[#] ifconfig wg0 inet 10.8.0.1/24 alias
[#] ifconfig wg0 mtu 1420
[#] ifconfig wg0 up
[+] Backgrounding route monitor

Перевіряємо інтерфейс:

root@setevoy-nas:/home/setevoy # ifconfig wg0
wg0: flags=10080c1<UP,RUNNING,NOARP,MULTICAST,LOWER_UP> metric 0 mtu 1420
        options=80000<LINKSTATE>
        inet 10.8.0.1 netmask 0xffffff00
        groups: wg
        nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>

Та статус WireGuard:

root@setevoy-nas:/home/setevoy # wg show
interface: wg0
  public key: xLWA/FgF3LBswHD5Z1uZZMOiCbtSvDaUOOFjH4IF6W8=
  private key: (hidden)
  listening port: 51820

Поки у нас нема ніяких клієнтів – переходимо до них.

TP-Link Dynamic DNS та NAT port-forwarding

Аби з дому підключатись до хосту з FreeBSD і WireGuard – на роутері в офісі додаємо форвард портів:

  • protocol: UDP
  • зовнішній порт на роутері: 51830 (трохи замаскувати від ботів)
  • куди форвардити: 192.168.0.2 (хост з FreeBSD)
  • на який порт форвардити: 51830 (WireGuard на em0 на FreeBSD)

На TP-Link Archer AX12 це виглядає так:

Якщо Internet IP в офісі динамічний – в Archer AX12 є можливість налаштування Dynamic DNS:

Хоча в мене він статичний, але DDNS заради інтересу налаштував з https://www.noip.com.

Запуск WireGuard на Arch Linux

В Linux все аналогічно – в ядрі є модулі, нам треба тільки встановити пакет з утилітами.

Перевіряємо модулі:

root@setevoy-home:/home/setevoy # lsmod | grep wireguard
wireguard             122880  0
curve25519_x86_64      36864  1 wireguard
libcurve25519_generic    45056  2 curve25519_x86_64,wireguard
ip6_udp_tunnel         16384  1 wireguard
udp_tunnel             32768  1 wireguard

Встановлюємо пакет:

root@setevoy-home:/home/setevoy # pacman -S wireguard-tools

Переходимо в /etc/wireguard/, створюємо ключі:

root@setevoy-home:/home/setevoy # cd /etc/wireguard/
root@setevoy-home:/etc/wireguard # wg genkey | tee client1.key | wg pubkey > client1.pub

Міняємо права доступу на приватний ключ:

root@setevoy-home:/etc/wireguard # chmod 600 client1.key

Тепер можемо додавати Peers – клієнтів.

Для цього нам потрібно додати ключі на клієнті та на сервері:

  • на сервері:
    • в InterfacePrivateKey: це /usr/local/etc/wireguard/server.key на хості FreeBSD
    • в PeerPublicKey: це /etc/wireguard/client1.pub на ноутбуці з Arch Linux
  • на клієнті:
    • в InterfacePrivateKey: це /etc/wireguard/client1.key
    • в PeerPublicKey: це /usr/local/etc/wireguard/server.pub

Описуємо конфіг на клієнті, файл /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = 0Cu***UWU=
Address = 10.8.0.3/24

[Peer]
PublicKey = xLWA/FgF3LBswHD5Z1uZZMOiCbtSvDaUOOFjH4IF6W8=
Endpoint = setevoy-***.ddns.me:51830

AllowedIPs = 10.8.0.1/32, 192.168.0.0/24
PersistentKeepalive = 25

Тут в AllowedIPs вказуємо мережі в які, по-перше, буде доступ взагалі, по-друге – вони будуть додані в таблиці маршрутизації (“Acts as a routing table and access control list“).

Запускаємо на клієнті:

[root@setevoy-wg-test setevoy]# wg-quick up wg0
[#] ip link add dev wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.8.0.3/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 10.8.0.3/32 dev wg0
[#] ip -4 route add 192.168.0.0/24 dev wg0

Тут:

  • ip -4 address add: Interface - Address заданий для wg0
  • ip -4 route add 10.8.0.3/32 та 192.168.0.0/24: додані нові роути через інтерфейс wg0 для мереж VPN та офісної локалки

Перевіряємо:

root@setevoy-home:/etc/wireguard # ip r s 10.8.0.0/24
10.8.0.0/24 dev wg0 proto kernel scope link src 10.8.0.3 
root@setevoy-home:/etc/wireguard # ip r s 192.168.0.0/24
192.168.0.0/24 dev wg0 scope link

Додаємо Peer на сервері, файл /usr/local/etc/wireguard/wg0.conf тепер буде таким:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = cLS***sGQ=

[Peer]
PublicKey = d7yqxOky4qOI/NTl/qbUnijfICwmbe/e/ulSVuQKLhk=
AllowedIPs = 10.8.0.3/32, 192.168.100.0/24

Перезапускаємо:

root@setevoy-nas:/usr/local/etc/wireguard # wg-quick down wg0
[#] ifconfig wg0 destroy

root@setevoy-nas:/usr/local/etc/wireguard # wg-quick up wg0
[#] ifconfig wg create name wg0
[#] wg setconf wg0 /dev/stdin
[#] ifconfig wg0 inet 10.8.0.1/24 alias
[#] ifconfig wg0 mtu 1420
[#] ifconfig wg0 up
[#] route -q -n add -inet 10.8.0.2/32 -interface wg0
[+] Backgrounding route monitor

Перевіряємо статус на клієнті:

root@setevoy-home:/etc/wireguard # wg show
interface: wg0
  public key: d7yqxOky4qOI/NTl/qbUnijfICwmbe/e/ulSVuQKLhk=
  private key: (hidden)
  listening port: 36864

peer: xLWA/FgF3LBswHD5Z1uZZMOiCbtSvDaUOOFjH4IF6W8=
  endpoint: 178.***.***.184:51830
  allowed ips: 10.8.0.1/32, 192.168.0.0/24
  latest handshake: 1 minute, 44 seconds ago
  transfer: 4.35 KiB received, 5.84 KiB sent
  persistent keepalive: every 25 seconds

Головне, на що звертаємо увагу, це “latest handshake” – значить клієнт до сервера підєднався.

Перевіряємо на сервері:

root@setevoy-nas:/home/setevoy # wg show
interface: wg0
  public key: xLWA/FgF3LBswHD5Z1uZZMOiCbtSvDaUOOFjH4IF6W8=
  private key: (hidden)
  listening port: 51820

peer: d7yqxOky4qOI/NTl/qbUnijfICwmbe/e/ulSVuQKLhk=
  endpoint: 178.***.***.236:56432
  allowed ips: 192.168.100.0/24, 10.8.0.3/32
  latest handshake: 15 seconds ago
  transfer: 1.69 KiB received, 3.87 KiB sent

Перевіряємо SSH з клієнта на сервер:

root@setevoy-home:/etc/wireguard # ssh [email protected]
([email protected]) Password for setevoy@setevoy-nas:
...
FreeBSD 14.3-RELEASE (GENERIC) releng/14.3-n271432-8c9ce319fef7

Welcome to FreeBSD!
...

setevoy@setevoy-nas:~ $

Або:

[setevoy@setevoy-home ~]$ ssh 192.168.0.2
([email protected]) Password for setevoy@setevoy-nas:

Додаємо профайл wg0 в автозапуск:

[setevoy@setevoy-home ~]$ sudo systemctl enable wg-quick@wg0
Created symlink '/etc/systemd/system/multi-user.target.wants/[email protected]' → '/usr/lib/systemd/system/[email protected]'.

В принципі, на цьому вже майже все готове – доступ є, все працює.

Але чого хочеться ще – це мати прямий доступ з домашнього ноута на робочий і з робочого на домашній, бо на робочому ноуті VPN нема – він там і не потрібен, бо FreeBSD/NAS в тій самій локальній мережі.

Конфігурація cross-LAN доступу

Тож що треба зробити – це налаштувати прямий доступ між ноутами в домашній мережі 192.168.100.0/24 і офісній 192.168.0.0/24, бо зараз з робочого ноутбука на ноутбук вдома і навпаки доступ не працює.

Картина зараз така:

  • IP ноута в офісі: 192.168.0.165
  • IP ноута вдома: 192.168.100.205
  • на робочому ноуті WireGuard нема
  • з офісу на домашній ноут конекта нема
  • з дому на робочий ноут конекта нема
  • з дому на FreeBSD конект є

Налаштування Routing tables

Поки робимо – закоментуємо block all в /etc/pf.conf, потім до нього повернемось.

В результаті того, що зараз будемо робити – вийде ось така схема: тут головне – це маршрути, спеціально робив схемою, аби те, що буде описано далі було простіше зрозуміти:

Перевіряємо роути з домашнього ноута на FreeBSD:

root@setevoy-home:/etc/wireguard # ip route get 192.168.0.2
192.168.0.2 dev wg0 src 10.8.0.3 uid 0

І на робочий ноут:

root@setevoy-home:/etc/wireguard # ip route get 192.168.0.165
192.168.0.165 dev wg0 src 10.8.0.3 uid 0

Трафік йде через wg0, і Source Address для пакета задається як 10.8.0.3.

А на робочому ноуті роут на домашній ноут йде через 192.168.0.1:

[setevoy@setevoy-work ~] $ ip route get 192.168.100.205
192.168.100.205 via 192.168.0.1 dev wlan0 src 192.168.0.165 uid 1000

Тут 192.168.0.1 – дефолтний гейтвей, роутер в офісі, який нічого не знає про домашню мережу 192.168.100.0/24.

Тому перше – додаємо роут в домашню мережу через хост з FreeBSD:

[setevoy@setevoy-work ~] $ sudo ip route add 192.168.100.0/24 via 192.168.0.2

Перевіряємо ще раз:

[setevoy@setevoy-work ~] $ ip route get 192.168.100.205
192.168.100.205 via 192.168.0.2 dev wlan0 src 192.168.0.165 uid 1000

Тепер є контакт з офісу додому:

[setevoy@setevoy-work ~] $ ping 192.168.100.205 -c 1
PING 192.168.100.205 (192.168.100.205) 56(84) bytes of data.
64 bytes from 192.168.100.205: icmp_seq=1 ttl=63 time=62.0 ms

--- 192.168.100.205 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

Але з домашнього все ще нема, бо з дому ми шлемо:

  • з домашнього ноута з IP 192.168.100.205
    • через FreeBSD з IP 192.168.0.2
      • на робочий ноутбук з IP 192.168.0.165

Але у нас з домашнього ноутбука задається Source IP як 10.8.0.3:

root@setevoy-home:/etc/wireguard # ip route get 192.168.0.165
192.168.0.165 dev wg0 src 10.8.0.3 uid 0

Бо маршрут в 192.168.0.0/24 заданий через VPN інтерфейс wg0:

root@setevoy-home:/etc/wireguard # ip r s 192.168.0.0/24
192.168.0.0/24 dev wg0 scope link 

А у wg0 заданий IP 10.8.0.3:

root@setevoy-home:/etc/wireguard # ip a s wg0
20: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none 
    inet 10.8.0.3/24 scope global wg0

А робочий ноут нічого про мережу 10.8.0.0/24 не знає і не може повернути відповідь.

Тому на робочому ноуті додаємо ще один маршрут:

[setevoy@setevoy-work ~] $ sudo ip route add 10.8.0.0/24 via 192.168.0.2 dev wlan0

Перевіряємо:

[setevoy@setevoy-work ~]  $ ip r s 10.8.0.0/24
10.8.0.0/24 via 192.168.0.2 dev wlan0

І тепер з домашнього ноута на робочий доступ теж є:

root@setevoy-home:/etc/wireguard # ping -c1 192.168.0.165
PING 192.168.0.165 (192.168.0.165) 56(84) bytes of data.
64 bytes from 192.168.0.165: icmp_seq=1 ttl=63 time=6.19 ms

--- 192.168.0.165 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

Аби ці роути додати постійно – можна зробити з NetworkManager CLI.

Видаляємо те, що додали вручну:

[setevoy@setevoy-work ~] $ sudo ip route del 10.8.0.0/24 via 192.168.0.2
[setevoy@setevoy-work ~] $ sudo ip route del 192.168.100.0/24 via 192.168.0.2

Знаходимо ім’я підключення:

[setevoy@setevoy-work ~] $ nmcli connection show
NAME                  UUID                                  TYPE       DEVICE          
setevoy-tp-link-21-5  3a12a60d-7b37-4c20-b573-d27c47a94ae5  wifi       wlan0 
...

Додаємо роути:

[setevoy@setevoy-work ~] $ nmcli connection modify setevoy-tp-link-21-5 +ipv4.routes "10.8.0.0/24 192.168.0.2,192.168.100.0/24 192.168.0.2"

Перевіряємо:

[setevoy@setevoy-work ~] $ nmcli connection show setevoy-tp-link-21-5 | grep ipv4.routes
ipv4.routes:                            { ip = 10.8.0.0/24, nh = 192.168.0.2 }; { ip = 192.168.100.0/24, nh = 192.168.0.2 }

Перезапускаємо підключення:

[setevoy@setevoy-work ~] $ sudo nmcli connection down setevoy-tp-link-21-5 && sudo nmcli connection up setevoy-tp-link-21-5
Connection 'setevoy-tp-link-21-5' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/15)
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/16)

Перевіряємо роути тепер:

[setevoy@setevoy-work ~] $ ip route get 10.8.0.3
10.8.0.3 via 192.168.0.2 dev wlan0 src 192.168.0.165 uid 1000

[setevoy@setevoy-work ~] $ ip route get 192.168.100.205
192.168.100.205 via 192.168.0.2 dev wlan0 src 192.168.0.165 uid 1000

Тепер у нас є ping з офісного ноутбука на домашній:

[setevoy@setevoy-work ~] $ ping -c1 192.168.100.205
PING 192.168.100.205 (192.168.100.205) 56(84) bytes of data.
64 bytes from 192.168.100.205: icmp_seq=1 ttl=63 time=5.95 ms

--- 192.168.100.205 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

І з домашнього на робочий:

root@setevoy-home:/etc/wireguard # ping -c1 192.168.0.165
PING 192.168.0.165 (192.168.0.165) 56(84) bytes of data.
64 bytes from 192.168.0.165: icmp_seq=1 ttl=63 time=5.67 ms

--- 192.168.0.165 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

Налаштування Packet Filter

Але якщо ми включимо block all в pf, то підключення з офісу на домашній ноут зламається, бо у нас зараз правила тільки для FreeBSD host:

...
# allow SSH from Office LAN (192.168.0.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.0.0/24 to (em0) port 22 keep state

...
# allow ICMP (ping) from Home network to FreeBSD host
pass in on em0 proto icmp from 192.168.100.0/24 to (em0) keep state

...

Тут:

  • перше правило – дозволяє SSH з офісної мережі на IP інтерфейсу em0 хоста з FreeBSD
  • друге – дозволяє ping з домашньої мережі на IP інтерфейсу em0 хоста з FreeBSD

Тому додаємо ще два правила – з SSH і ping з офісу додому:

...
# allow SSH from Office network to Home network
pass in on em0 proto tcp from 192.168.0.0/24 to 192.168.100.0/24 port 22 keep state

...

# allow ICMP from Home network to Office network
pass in on em0 proto icmp from 192.168.0.0/24 to 192.168.100.0/24 keep state
...

Перевіряємо, перечитуємо конфіг pf:

root@setevoy-nas:/usr/local/etc/wireguard # pfctl -vnf /etc/pf.conf && service pf reload
set skip on { lo }
block drop log all
pass in log on em0 inet proto tcp from 192.168.0.0/24 to (em0) port = ssh flags S/SA keep state
pass in log on em0 inet proto tcp from 192.168.100.0/24 to (em0) port = ssh flags S/SA keep state
pass in on wg0 inet from 10.8.0.0/24 to (wg0) flags S/SA keep state
pass in on wg0 inet proto icmp from 10.8.0.0/24 to (wg0) keep state
pass in on wg0 inet from 10.8.0.0/24 to 192.168.0.0/24 flags S/SA keep state
pass in on wg0 inet from 10.8.0.0/24 to 192.168.100.0/24 flags S/SA keep state
pass in on em0 inet proto tcp from 192.168.0.0/24 to 192.168.100.0/24 port = ssh flags S/SA keep state
pass in on em0 inet proto icmp from 192.168.0.0/24 to 192.168.100.0/24 keep state
pass in on em0 proto udp from any to (em0) port = 51820 keep state
pass out all flags S/SA keep state
Reloading pf rules.

І тепер у нас є пінг з дому в офіс:

root@setevoy-home:/etc/wireguard # ping -c1 192.168.0.165
PING 192.168.0.165 (192.168.0.165) 56(84) bytes of data.
64 bytes from 192.168.0.165: icmp_seq=1 ttl=63 time=8.09 ms

--- 192.168.0.165 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

Є SSH ssh з дому в офіс:

root@setevoy-home:/etc/wireguard # ssh 192.168.0.165
[email protected]'s password:

Є пінг з офісу додому:

[setevoy@setevoy-work ~]  $ ping -c1 192.168.100.205
PING 192.168.100.205 (192.168.100.205) 56(84) bytes of data.
64 bytes from 192.168.100.205: icmp_seq=1 ttl=63 time=60.5 ms

--- 192.168.100.205 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

І є SSH з офісу додому:

[setevoy@setevoy-work ~]  $ ssh 192.168.100.205
[email protected]'s password: 

Все працює.

Весь конфіг /etc/pf.conf тепер такий:

##################
### Interfaces ###
##################
# lan_if = "em0"
# wg_if  = "wg0"

################
### Networks ###
################
# lan_net      = "192.168.0.0/24"
# home_net     = "192.168.100.0/24"
# wg_net       = "10.8.0.0/24"
# vpn_nets     = "{ 10.8.0.0/24, 192.168.100.0/24 }"

################
### Services ###
################
# ssh_ports = "{ 22 }"
# wg_port   = "51820"

######################
### Basic settings ###
######################

# do not filter loopback traffic
set skip on lo

######################
### Default policy ###
######################

# block everything by default
block log all

#######################
### Inbound traffic ###
#######################

### SSH

# allow SSH from Office LAN (192.168.0.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.0.0/24 to (em0) port 22 keep state

# allow SSH from Home network (192.168.100.0/24) to FreeBSD host
pass in log on em0 proto tcp from 192.168.100.0/24 to (em0) port 22 keep state

# allow SSH from VPN clients to FreeBSD host
pass in on wg0 proto tcp from 10.8.0.0/24 to (wg0) port 22 keep state

### NEW
# allow SSH from Office netwrok to Home network 
pass in on em0 proto tcp from 192.168.0.0/24 to 192.168.100.0/24 port 22 keep state

### TEST

# allow Office LAN to reach Home LAN via WireGuard
#pass in  on em0 from 192.168.0.0/24 to 192.168.100.0/24 keep state
#pass out on wg0 from 192.168.0.0/24 to 192.168.100.0/24 keep state

# allow Home LAN to reach Office LAN via WireGuard
#pass in  on wg0 from 192.168.100.0/24 to 192.168.0.0/24 keep state
#pass out on em0 from 192.168.100.0/24 to 192.168.0.0/24 keep state

### VPN 

# allow WireGuard handshake (UDP/51820) on LAN interface
pass in on em0 proto udp to (em0) port 51820 keep state

# allow VPN clients (10.8.0.0/24) to access FreeBSD host itself
# this allows ping, ssh, etc. to the wg0 address
pass in on wg0 from 10.8.0.0/24 to (wg0) keep state

# allow VPN clients to access Office LAN (192.168.0.0/24)
pass in on wg0 from 10.8.0.0/24 to 192.168.0.0/24 keep state

# allow VPN clients to access Home network (192.168.100.0/24)
pass in on wg0 from 10.8.0.0/24 to 192.168.100.0/24 keep state

# 
#pass in on em0 from 192.168.0.0/24 to 192.168.100.0/24 keep state

#pass in on wg0 from 192.168.100.0/24 to 192.168.0.0/24 keep state

### ICMP

# allow ICMP from VPN clients to FreeBSD host
pass in on wg0 proto icmp from 10.8.0.0/24 to (wg0) keep state

# allow ICMP from Home network to FreeBSD host
#pass in on em0 proto icmp from 192.168.100.0/24 to (em0) keep state

# allow ICMP from Home network to Office network
pass in on em0 proto icmp from 192.168.0.0/24 to 192.168.100.0/24 keep state

############################
### outbound traffic ###
############################

# allow all outbound traffic from FreeBSD
pass out keep state

Активні підключення в pftop:

Тут:

  • In 192.168.0.165:50286 => 192.168.0.2:22: SSH робочий ноут на FreeBSD
  • In 178.***.***.236:56432 => 192.168.0.2:51820: підключення з дому через NAT Port-forwarding на офісному роутері до VPN на FreeBSD
  • In 10.8.0.3:39442 => 192.168.0.165:22: SSH з дому на робочий ноут
  • Out 10.8.0.1:50589 => 10.8.0.3:22: SSH з FreeBSD на домашній

P.S. Який це дикий кайф – оцей во “traditional networking” а не ці всі AWS VPC і його subnets…