В попередньому пості FreeBSD: WireGuard VPN, Linux peer та routing між мережами підняли VPN для поєднання двох мереж – моєї офісної та домашньої, все працює.
Але зараз, аби підключитись до якогось хосту в мережах треба вказувати IP-адресу.
Можна, звісно, прописувати все в файлах /etc/hosts, але це і не дуже зручно, і будуть клієнти типу Android-телефонів, і взагалі – хочеться все красівоє.
Тому зробимо локальний DNS, на якому буде централізований DNS для всієї інфраструктури:
- власну локальну DNS-зону
.setevoy - DNS-відповіді для
.setevoy, що залежать від мережі, з якої приходить запит (office/home/VPN) - резолвінг зовнішніх доменів через forward-DNS (Cloudflare/Google)
Зміст
Вибір DNS серверу
Справа смаку.
Я колись мав BIND, який обслуговував навіть зону самого rtfm.co.ua – але для маленької домашньої мережі це зовсім overkill.
Мав справу з dnsmasq – простий, швидкий, вміє в DHCP, але трохи обмежений в можливостях.
І Unbound – рідний для FreeBSD, теж простий і швидкий, вміє в DNSSEC validation прям з коробки, вміє в views/access-control – те, що треба.
Routers та DHCP зі Static IP
Взагалі, можна було б заморочитись і автоматизувати навіть видачу IP для хостів в мережах, але, по-перше, ну камон – в мене 3 машинки у двох мережах 🙂
По-друге – робочий ноут і ThinkCenter знаходяться в офісі, а домашній ноутбук – вдома. Тобто, робити DHCP на хості з FreeBSD – така собі затєя, бо домашній ноутбук може бути не підключеним до VPN.
Тому – прибиваємо все статично в налаштуваннях роутера (чекаю, чекаю, коли до мене доїде MikroTik hAP ax3!):
Тепер для робочого ноута, коли він підключений по Ethernet, адреса завжди буде 192.168.0.3.
Базовий конфіг Unbound
Встановлюємо пакет:
root@setevoy-nas:/home/setevoy # pkg install -y unbound
Файл налаштувань – /usr/local/etc/unbound/unbound.conf.
Є цікавий приклад конфігу Example of how to configure Unbound as a local forwarder using DNS-over-TLS to forward queries, треба буде глянути.
Документація – unbound.conf і офіційна документація Unbound by NLnet Labs.
Можна забекапити дефолтний конфіг, напишемо свій з нуля:
root@setevoy-nas:/home/setevoy # cp /usr/local/etc/unbound/unbound.conf /usr/local/etc/unbound/unbound.conf-origin
Редагуємо/створюємо /usr/local/etc/unbound/unbound.conf, поки мінімальна конфігурація:
server:
interface: 0.0.0.0
access-control: 127.0.0.0/8 allow # local
access-control: 192.168.0.0/24 allow # office LAN
access-control: 192.168.100.0/24 allow # home LAN
access-control: 10.8.0.0/24 allow # WireGuard VPN
do-ip6: no
do-daemonize: yes
hide-identity: yes
hide-version: yes
local-zone: "setevoy." static
local-data: "nas.setevoy. A 192.168.0.2"
local-data: "work.setevoy. A 192.168.0.1"
local-data: "home.setevoy. A 192.168.100.205"
Тут вказуємо:
- на якій адресі приймати підключення
- з яких мереж приймати запити
- відключаємо IPv6 (бо нашо це вдома?)
- ховаємо ім’я серверу та версію
- навіть не знав, що так можна –
dig CHAOS TXT id.server @192.168.0.2 +shortповернеCH TXT "setevoy-nas"
- навіть не знав, що так можна –
- і описуємо локальну зону
.setevoyз трьома DNS records
Перевіряємо синтаксис конфігу:
root@setevoy-nas:/home/setevoy # unbound-checkconf unbound-checkconf: no errors in /usr/local/etc/unbound/unbound.conf
Додаємо в автостарт:
root@setevoy-nas:/home/setevoy # sysrc unbound_enable=YES unbound_enable: -> YES
Запускаємо:
root@setevoy-nas:/home/setevoy # service unbound start
Перевіряємо локально, з хоста з FreeBSD з drill замість dig:
root@setevoy-nas:/home/setevoy # drill nas.setevoy @127.0.0.1 ... ;; ANSWER SECTION: nas.setevoy. 3600 IN A 192.168.0.2 ...
І якийсь зовнішній домен:
root@setevoy-nas:/home/setevoy # drill google.com @127.0.0.1 ... ;; ANSWER SECTION: google.com. 300 IN A 142.251.98.101 google.com. 300 IN A 142.251.98.139 ...
Додаємо правило pf для доступу до DNS (див. FreeBSD: знайомство з Packet Filter (PF) firewall):
...
# DNS
pass in on em0 proto { udp tcp } from { 192.168.0.0/24, 192.168.100.0/24, 10.8.0.0/24 } to (em0) port 53 keep state
...
Перевіряємо синтаксис, застосовуємо:
root@setevoy-nas:/home/setevoy # pfctl -nvf /etc/pf.conf && pfctl -f /etc/pf.conf
І пробуємо вже з робочого ноута:
[setevoy@setevoy-work ~] $ dig nas.setevoy @192.168.0.2 +short 192.168.0.2 [setevoy@setevoy-work ~] $ dig google.com @192.168.0.2 +short 142.251.98.138 142.251.98.102 ...
Задаємо кастомні DNS сервери на офісному роутері:
WireGuard DNS settings
Домашній ноут підключається з WireGuard, де при підключенні можна задавати наш новий DNS.
З дому при підключеному VPN у нас сервер DNS буде на 10.8.0.1:
[setevoy@setevoy-home ~]$ dig work.setevoy @10.8.0.1 +short 192.168.0.1
Редагуємо /etc/wireguard/wg0.conf, в блок [Interface] додаємо DNS:
[Interface] PrivateKey = 0Cu***UWU= Address = 10.8.0.3/24 DNS = 10.8.0.1, 192.168.100.1 [Peer] PublicKey = xLWA/FgF3LBswHD5Z1uZZMOiCbtSvDaUOOFjH4IF6W8= Endpoint = setevoy-***.ddns.me:51830 AllowedIPs = 10.8.0.1/32, 192.168.0.0/24 PersistentKeepalive = 25
Тепер при підключенні VPN буде задаватись 10.8.0.1 як основний, і адреса домашнього роутера 192.168.100.1 як fallback опція.
Ще можна буде налаштувати split-DNS, задавши Domains = ~setevoy, аби до 10.8.0.1 робити запити тільки для зони .setevoy, див. systemd-resolved та systemd-networkd.
Налаштування forward-only DNS
З поточним конфігом наш unbound виконує повний рекурсивний пошук.
Тобто, коли ми з клієнта робимо запит google.com – то:
- unbound звертається до root-серверів DNS
- там шукає Name Servers для зони
.com - звертається до цих Name Servers, запитуючи інформацію про Name Servers для
google.com - і тільки після цього йде на Name Servers
google.com, звідки бере інформацію по IP, яку потім повертає клієнту
Натомість можемо налаштувати forward-only, і тоді Unbound одним запитом сходить на 1.1.1.1 або 8.8.8.8, і відразу поверне відповідь клієнту.
Додаємо в кінець конфігу:
...
forward-zone:
name: "."
forward-addr: 1.1.1.1
forward-addr: 8.8.8.8
Перевіряємо, застосовуємо зміни:
root@setevoy-nas:/home/setevoy # unbound-checkconf && service unbound reload
Тепер Unbound в порядку пріорітету спочатку перевірить свою локальну зону, якщо google.com в нього на обслуговуванні нема – то він переадресує запит до Cloudflare або Google.
Налаштування логів
Робив для того, аби подивись як впливає налаштування forward-zone – тому теж нехай тут буде.
В блок server: додаємо:
...
server:
...
# enable logging
verbosity: 3
log-queries: yes
log-replies: yes
logfile: "/var/log/unbound.log"
# disable caching during tests
cache-min-ttl: 0
cache-max-ttl: 0
...
На час тестів можна відключити локальне кешування – cache-min/max-ttl.
По дефолту Unbound працює в chroot-оточенні з кореневою директорією в /usr/local/etc/unbound – створюємо там файл логу:
root@setevoy-nas:/home/setevoy # mkdir -p /usr/local/etc/unbound/var/log root@setevoy-nas:/home/setevoy # touch /usr/local/etc/unbound/var/log/unbound.log root@setevoy-nas:/home/setevoy # chown unbound:unbound /usr/local/etc/unbound/var/log/unbound.log root@setevoy-nas:/home/setevoy # chmod 640 /usr/local/etc/unbound/var/log/unbound.log root@setevoy-nas:/home/setevoy # unbound-checkconf unbound-checkconf: no errors in /usr/local/etc/unbound/unbound.conf root@setevoy-nas:/home/setevoy # service unbound reload
Перевірка роботи Recursive DNS
Тепер відключаємо forward-zone, з робочого ноутбука робимо запит про google.com до нашого DNS:
[setevoy@setevoy-work ~] $ time dig +short google.com @192.168.0.2 ... real 0m0.109s
Час виконання – 0.109s.
Дивимось лог Unbound:
... info: 192.168.0.3 google.com. A IN ... info: priming . IN NS info: sending query: . NS IN info: reply from <.> 199.7.83.42#53 info: priming successful for . NS IN ... info: sending query: com. A IN info: reply from <.> 202.12.27.33#53 info: query response was REFERRAL ... info: sending query: google.com. A IN info: reply from <google.com.> 216.239.38.10#53 info: query response was ANSWER ... info: 192.168.0.3 google.com. A IN NOERROR 0.101574 ...
Тут добре видно, як Unbound працює як рекурсивний резолвер :
- спочатку виконує запит до root-зони “
.“, де отримує Name Servers для зони.com - далі звертається до Name Servers зони
.com, де отримує адреси Name Servers зониgoogle.com - і лише після цього звертається вже до Name Servers домену
google.com, отримуючи фінальну A-відповідь з IP-адресами серверів Google
А тепер повертаємо forward-zone, але залишаємо відключеним кешування (cache-min/max-ttl) і робимо запит з клієнта ще раз:
[setevoy@setevoy-work ~] $ time dig +short google.com @192.168.0.2 ... real 0m0.016s
Тепер час на отримання відповіді – 0.030s, а без forward-zone він був 0.109s (або з логу – google.com. A IN NOERROR 0.101574). Майже в 3 раз швидше. Іноді буває і 0.01s.
І логи Unbound тепер набагато менші:
... debug: forwarding request ... debug: ip4 1.1.1.1 port 53 debug: ip4 8.8.8.8 port 53 info: sending query: google.com. A IN debug: sending to target: <.> 8.8.8.8#53 ... info: 192.168.0.3 google.com. A IN NOERROR 0.039006 ...
Все, що він зробив – це передав запит до 8.8.8.8 і повернув результат, отриманий від нього.
Unbound DNS views для різних мереж
Зараз у нас з дому, який за VPN, при запиті nas.setevoy повернеться адреса 192.168.0.1:
... local-data: "nas.setevoy. A 192.168.0.2" ...
Але якщо хочемо ходити чисто через нетворк VPN – можемо розділити зони з views і для кожної мережі створити власні зони:
server:
interface: 0.0.0.0
do-daemonize: yes
do-ip6: no
hide-identity: yes
hide-version: yes
# map client networks to views
access-control-view: 127.0.0.0/8 office
access-control-view: 192.168.0.0/24 office
access-control-view: 10.8.0.0/24 vpn
#######################
### Hosts list note ###
#######################
# -Office:
# - setevoy-work: Arch Linux laptop
# - setevoy-pc: Arch Linux/Windows gaming PC
# - setevoy-nas: FreeBSD ThinkCentre
# - TP-Link router
# - Home:
# - setevoy-home: Arch Linux laptop
# - TP-Link router
################
# OFFICE VIEW #
################
view:
name: "office"
local-zone: "setevoy." static
local-data: "nas.setevoy. A 192.168.0.2"
local-data: "work.setevoy. A 192.168.0.3"
local-data: "pc.setevoy. A 192.168.0.4"
#############
# VPN VIEW #
#############
view:
name: "vpn"
local-zone: "setevoy." static
local-data: "nas.setevoy. A 10.8.0.1"
# not VPN-connected, but Home has routing to the 192.168.0.0/24
local-data: "work.setevoy. A 192.168.0.3"
local-data: "pc.setevoy. A 192.168.0.4"
#################
# FORWARD ONLY #
#################
forward-zone:
name: "."
forward-addr: 1.1.1.1
forward-addr: 8.8.8.8
Тут в access-control-view: 10.8.0.0/24 vpn прив’язує клієнтів з VPN-мережі 10.8.0.0/24 до view з ім’ям vpn, для якого далі окремо описується DNS-логіка.
Конкретно в моєму сетапі домашній ноутбук все одно має роутинг в мережу 192.168.0.0/24 через 10.8.0.1, і можна повертати адреси з неї – але в цілому штука корисна.
Перевіряємо, застосовуємо:
root@setevoy-nas:/home/setevoy # unbound-checkconf && service unbound reload unbound-checkconf: no errors in /usr/local/etc/unbound/unbound.conf
Перевіряємо з дому – отримуємо адресу з мережі VPN:
[setevoy@setevoy-home ~] $ dig nas.setevoy @10.8.0.1 +short 10.8.0.1
І з офісу – результат буде з офісної мережі:
[setevoy@setevoy-work ~] $ dig nas.setevoy @192.168.0.2 +short 192.168.0.2
Готово.

