Несколько различных VPN подключений с локальными DNS серверами

в 0:08, , рубрики: BIND, DNS, linux, vpn, метки: , , ,

Откуда появилась проблема

Многие из вас пользуются VPN подключением к рабочей локальной сети из дома.
Благодаря этому, подключив VPN вы работаете с рабочей сетью «как будто находясь в ней».

Как выглядит типичная настройка в linux?
В /etc/resolv.conf прописывается (при помощи openresolv или NetworkManager)

search local.company.name
nameserver 10.0.20.186

Где local.company.name — домен компании, а 10.0.20.186 — ip адрес локального (в рабочей сети) DNS сервера.

Как выглядит работа?

root@t510 0 /usr/share/openvpn # ping -c 1 cdash-master
PING cdash-master.local.company.name (10.0.20.237) 56(84) bytes of data.
64 bytes from 10.0.20.237: icmp_seq=1 ttl=63 time=214 ms
...

Что произошло?

  1. search добавил к cdash-master суффикс local.company.name
  2. DNS сервер в рабочей сети преобразовал cdash-master.local.company.name в 10.0.20.237

Всё прекрасно работает, пока у вас VPN подключение… одно.
Мне захотелось подключать одновременно два VPN и прописывать два DNS — один для рабочей сети, другой для локальной сети на hetzner, где крутятся мои виртуальные машины.

Казалось бы, что может быть проще? Однако путь к решению был долгим и извилистым.

Подробное описание результата

Рабочая сеть

Локальная подсеть — 10.0.20.0/24 (т.е. 10.0.20.* — из подсети)
Домен — *.local.company.name
DNS сервер — 10.0.20.186

ping -с 1 somename 

должен определить somename как somename.local.company.name, а somename.local.company.name превратить в IP адрес через DNS 10.0.20.186

Если VPN подключение выключено — имя не будет найдно

Личный сервер на hetzner

С ним всё немного хитрее

Локальная подсеть — 10.10.10.0/24 (т.е. 10.10.10.* — из подсети)
Домен — *.my.domain
Локальный DNS сервер — 10.10.10.253

Сервер my.domain имеет белый IP адрес и доступен извне
На сервере стоит nginx, который проксирует запросы вида subdomain.my.domain машинам из локальной подсети.

С одной стороны, если пользователь зашёл браузером на subdomain.my.domain, то DNS сервера регистратора вернут белый IP адрес my.domain, браузер отправит по данному IP адресу HTTP запрос, и дальше nginx разберётся куда его проксироват.

С другой стороны, при включенном VPN мои подключения вида:

ssh subdomain

должны попадать напрямую на машину из локальной подсети.
Зачем?

Мне так удобно. Я один раз настроил рабочую машину, и прозрачно гуляю по рабочей сети и личной сети.
Снаружи по *.my.domain пользователи видят ровно один сервер (который по совместительству и VPN) и к локальным машинам доступа не имеют
Я же могу напрямую подключать по ssh как к машинам из рабочей сети, так и из личной

«Подожди», скажет мне юзер.
«Я просто пропишу /etc/resolv.conf»:

search local.company.name my.domain

И всё будет работать.

Не будет. Для каждой зоны — local.company.name и my.domain требуется прописать свой DNS сервер. Через resolv.conf, openresolv эта проблема не решается.

Решение

Мне пришлось несколько часов мучать гугль и знакомых админов, чтобы найти решение.
Мой пост призван сэкономить ваше время.

Итак, прежде всего нужно поставить bind. Рабочая машина у меня на Arch Linux:

pacman -S bind
systemctl enable named

Дальше настраиваем /etc/named.conf, добавляет туда

zone "local.company.name" IN {
	type forward;
	forwarders { 10.0.20.186; };
};

include "/usr/share/openvpn/named.conf.my.domain";

zone "." IN {
	type forward;
        forwarders { 8.8.8.8; 8.8.4.4; };
};

Настраиваем NetworkManager либо редактируем /etc/resolv.conf. Результатом в обоих случаях должен быть:
root@t510 0 /usr/share/openvpn # cat /etc/resolv.conf

# Generated by NetworkManager
search local.company.name my.domain
nameserver 127.0.0.1

В openvpn скрипт для my.domain добавляем

up "/usr/share/openvpn/update-dns-my.domain"
down "/usr/share/openvpn/update-dns-my.domain"

Добавляем скрипт /usr/share/openvpn/update-dns-my.domain который будет обновлять настройки bind и перезапускать его после установления VPN подключения

#!/bin/bash

set -eu

NAME=/usr/share/openvpn/named.conf.my.domain
TEMPLATE=${NAME}.template

function restart_bind ()
{
    /usr/bin/systemctl restart named
}

case $script_type in
    up)
	cat ${TEMPLATE} > ${NAME}
	restart_bind
	;;
    down)
	cat /dev/null > ${NAME}
	restart_bind
	;;
esac

Добавляем /usr/share/openvpn/named.conf.my.domain.template

zone "my.domain" IN {
     type forward;
     forwarders { 10.10.10.253; };
};

Как это работает?

При установлении VPN подключения к личному серверу:

  1. openvpn запускает скрипт /usr/share/openvpn/update-dns-my.domain
  2. скрипт в файл /usr/share/openvpn/named.conf.my.domain записывает содержимое /usr/share/openvpn/named.conf.my.domain.template
  3. скртипт перезапускает bind
  4. bind вычитывает настройки зоны my.domain из обновлённого файла

При отключении VPN подключения

  1. openvpn запускает скрипт /usr/share/openvpn/update-dns-my.domain
  2. скрипт очищает содержимое /usr/share/openvpn/named.conf.my.domain.template
  3. скртипт перезапускает bind
  4. bind вычитывает настройки зоны my.domain из обновлённого файла (забывает про зону)
  5. зона my.domain теперь ресолвится общедоступными DNS

Как это выглядит на практике?

root@t510 0 /usr/share/openvpn # systemctl start named # не забываем включить bind
root@t510 0 /usr/share/openvpn # systemctl start openvpn@waltham # рабочая сеть 
root@t510 0 /usr/share/openvpn # systemctl start openvpn@hetzner # личная сеть

root@t510 0 /usr/share/openvpn # ping -c 1 cdash-master
PING cdash-master.local.company.name (10.0.20.237) 56(84) bytes of data.
64 bytes from 10.0.20.237: icmp_seq=1 ttl=63 time=214 ms
...

root@t510 0 /usr/share/openvpn # ping -c 1 db
PING db.my.domain (10.10.10.200) 56(84) bytes of data.
64 bytes from 10.10.10.200: icmp_seq=1 ttl=63 time=233 ms
...

root@t510 0 /usr/share/openvpn # systemctl stop openvpn@hetzner  

root@t510 0 /usr/share/openvpn # ping -c 1 db                  
PING db.my.domain (white-ip-address) 56(84) bytes of data.
64 bytes from my.domain (white-ip-address): icmp_seq=1 ttl=55 time=124 ms
...

root@t510 0 /usr/share/openvpn # systemctl start openvpn@hetzner 

root@t510 0 /usr/share/openvpn # ping -c 1 db                   
PING db.my.domain (10.10.10.200) 56(84) bytes of data.
64 bytes from 10.10.10.200: icmp_seq=1 ttl=63 time=118 ms
...

Забавно, что для получения такого простого поведения пришлось проделать столько работы.

Автор: zabivator

Источник

Поделиться

* - обязательные к заполнению поля