LINUX.ORG.RU
решено ФорумAdmin

Подкроватный DNS для VPN'ов в топологии «звезда»

 , , ,


0

3

Приветствую.

Допустим, у меня есть набор из нескольких подсетей /24, соединённых различными IP-туннелями (в смысле, L3, а не L2) в топологии «звезда». В частности, две подсети соединяются с центральной через IPsec между роутерами в туннельном режиме, и ещё есть подсеть для OpenVPN-клиентов (OpenVPN-сервер находится в центральной подсети, но на отдельной машине). Все подсети лежат внутри 10.0.0.0/8. OSPF и прочими протоколами динамической маршрутизации не пользуюсь, везде статические маршруты. Это всё как-то работает (все всех видят). Для определённости, все роутеры Mikrotik.

Теперь собственно задача. В каждой подсети есть свой кэширующий DNS-сервер-ресолвер, в кэш которого инжектируются записи о DHCP-клиентах в данной подсети (как dnsmasq, но не dnsmasq). Доменные зоны везде разные (*.1.lan, *.2.lan и так далее). И ещё у OpenVPN-сервера есть свой список клиентов с именами. И хочется сделать так, чтобы любой узел в любой подсети мог заресолвить имя любого другого узла, обращаясь к «своему» кэширующему ресолверу (к тому, чей адрес он получает через DHCP).

Как лучше всего это сделать? Я придумал три одинаково хреновых подхода.

Простейший и мегакостыльный способ 1 — синхронизировать списки клиентов, т. е. при появлении DHCP-клиента в любой подсети DHCP-сервер роутера через lease script будет стучаться по SSH на все остальные роутеры и добавлять это имя во все кэши. То же самое для OpenVPN-сервера.

Ещё один простейший и скорее всего нерабочий способ 2 — выдавать через DHCP адреса всех кэширующих ресолверов, а не только свой. Но это наверняка будет тормозить, потому что наверняка найдётся клиент, который перепутает порядок и будет пинать чужой сервер через VPN по умолчанию. Или, как вариант 2a, прописать адреса всех кэширующих ресолверов на каждом роутере как статические upstream DNS servers. Наверное, будет получше, но всё равно порядок опроса наверняка где-нибудь навернётся.

Наконец, способ номер 3 поизящнее — поднять в центре полновесный DNS-сервер, в котором делегировать каждую зону на соответствующий кэширующий ресолвер через VPN, и прописать этот DNS-сервер как второй upstream DNS server на каждом роутере. Но я не знаю, что взять в качестве полновесного DNS-сервера и как заставить ресолверы роутеров ресолвить запросы к *.lan через этот сервер, а остальные — через нормальный?

Есть ли у уважаемых админов и недоадминов ЛОРа какие-либо предложения (помимо «убей себя об стену, нуб»), комментарии (помимо «больной поехавший ублюдок»), идеи (помимо «оставить администрирование и идти работать дворником»)?

★★★★★

Первый вариант так себе, но потенциально рабочий, особенно если синхронизировать кеши различных DNS-серверов будет не lease-скрипт, а скрипт на центральном сервере.

Второй вариант не рабочий, так как если DNS-сервер не знает ответ, он сообщает, что нет такого имени и клиент не пойдёт к другми серверам.

В третьем варианте вы и указали корень проблемы — ущербый DNS-резолвер, который не умеет ходить к разным серверам за разными доменами. И, если не менять встроенный в mikrotik резолвер на что-то получше, то тогда слать все DNS-запросы к центральному DNS-серверу. Дать центральному DNS-у как-бы ip-адреса провайдерских DNS-ов и намутить что-нибудь с маршрутами/адресами, чтобы при падении тунеля DNS-запросы шли к провайдеру.

mky ★★★★★ ()
Ответ на: комментарий от mky

Первый вариант так себе, но потенциально рабочий, особенно если синхронизировать кеши различных DNS-серверов будет не lease-скрипт, а скрипт на центральном сервере.

Ну, я имел в виду скорее «из lease-скрипта пинать центр, а оттуда раскидывать по остальным», чтобы список подсетей был ровно в одном месте.

Второй вариант не рабочий, так как если DNS-сервер не знает ответ, он сообщает, что нет такого имени и клиент не пойдёт к другми серверам.

Такое поведение описано в каком-то стандарте? Просто в линуксе nss_dns из glibc (насколько я мог заметить) как раз делает цикл по всем nameserver'ам из resolv.conf, иначе бы ни у кого DNS внутри VPN не работал.

В третьем варианте вы и указали корень проблемы — ущербый DNS-резолвер, который не умеет ходить к разным серверам за разными доменами. И, если не менять встроенный в mikrotik резолвер на что-то получше,

Я бы с радостью. Это возможно?

слать все DNS-запросы к центральному DNS-серверу. Дать центральному DNS-у как-бы ip-адреса провайдерских DNS-ов и намутить что-нибудь с маршрутами/адресами, чтобы при падении тунеля DNS-запросы шли к провайдеру.

Боюсь, это замедлит common path (большая часть запросов всё же будет относиться к доменным именам из Интернета). Впрочем, тут вообще вот что предлагают: матчить содержимое DNS-запросов в prerouting регуляркой и по результатам dstnat'ить их куда надо :)

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 2)
Ответ на: комментарий от mky

к центральному DNS-серверу

Кстати, а какой, собственно, взять DNS-сервер? Оптимизируем для простоты настройки. Нужно уметь совсем немного: 1) матчить зоны, 2) перенаправлять запросы другому серверу и 3) отвечать из локального списка (для OpenVPN-клиентов).

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

Просто в линуксе nss_dns из glibc...

Может мы говорим про разное поведение, а может у нас разные glibc. Но, обычный dns-клиент обращается ко всем dns-серверам из списка по очереди, пока не будет получен ответ от сервера. Не важно, положительный, что dns-запись найдена или отрицательный (NXDOMAIN). И нормальный рекурсивный dns-сервер, знающий корневые DNS-сервера, быстро ответит NXDOMAIN на запросы по домену lan.

Какой это стандарт я не знаю, лучше проверьте это с помощью tcpdump.

Я бы с радостью. Это возможно?

ИМХО, нет. Хотя, может кто и пропатчил прошивку микротика. А пока что только поставить рядом с микротиком отдельную коробочку с dd-wrt и dns-masq.

Боюсь, это замедлит common path

Возможно замедлит, но насколько сказать сложно. С одной стороны, у микротика есть какой-то кеш, с другой стороны, до DNS-сервера провайдера запрос тоже идёт какое-то время и сколько-то там обратабывается.

А по поводу, того какой сервер выбрать в центр, решать вам. Вроде бы хватит dnsmasq, но лично я бы на всякий случай поставил bind, вдруг потом требования расширятся, захочется view, несколько зон, soa-записи...

mky ★★★★★ ()

bind c slave зонами не оно?

anc ★★★★★ ()

К слову, по запросу «conditional DNS forwarding» я нашел одно решение для себя, может и вам пригодится. Да, на всякий случай уточняю - еще не тестировал.

/ip firewall layer7-protocol
add name=testdns regexp=lantest.mindlesstux.com

/ip firewall mangle
add chain=prerouting dst-address=4.2.2.2 protocol=udp dst-port=53 layer7-protocol=testdns action=mark-connection new-connection-mark=forwarded-dns
add chain=prerouting dst-address=4.2.2.2 protocol=tcp dst-port=53 layer7-protocol=testdns action=mark-connection new-connection-mark=forwarded-dns

/ip firewall nat
add action=dst-nat chain=dstnat connection-mark=forwarded-dns to-addresses=8.8.8.8
add action=masquerade chain=srcnat connection-mark=forwarded-dns
ravdinve ()
Ответ на: комментарий от ravdinve

Пока ещё никак. Но я тоже видел, что для эмуляции conditional DNS forwarding предлагают использовать матчинг тела DNS-запросов. Видимо, так и сделаю (и подниму в центре условный dnsmasq).

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

Я как раз закончил разбираться с этой историей сегодня. Смотри: 4 сетки, IPSec, полносвязная топология. Устройства внутри каждой из сеток получают адреса по DHCP, с помощью скрипта они добавляются в DNS:

:foreach lease in=[/ip dhcp-server lease find] do={
  	:if ([:len [/ip dhcp-server lease get $lease host-name]] > 0) do={
    		:foreach static in [/ip dns static find] do={
      			:if ([/ip dns static get $static name] = ([/ip dhcp-server lease get $lease host-name] . ".35.ravdin.su")) do={
        			remove $static;
      			}
    		}
    	/ip dns static add name=([/ip dhcp-server lease get $lease host-name] . ".35.ravdin.su") address=[/ip dhcp-server lease get $lease address];
  	}
}

Для того, чтобы находясь в одной из сети разрешать адреса другой я добавил следующие правила:

/ip firewall layer7-protocol
add name=61.ravdin.su regexp=61.ravdin.su
add name=1.61.10.in-addr.arpa regexp=1.61.10.in-addr.arpa
add action=dst-nat chain=dstnat comment=61.ravdin.su dst-address=10.35.1.1 dst-port=53 layer7-protocol=61.ravdin.su protocol=tcp to-addresses=10.61.1.1 to-ports=53
add action=dst-nat chain=dstnat comment=61.ravdin.su dst-address=10.35.1.1 dst-port=53 layer7-protocol=61.ravdin.su protocol=udp to-addresses=10.61.1.1 to-ports=53
add action=dst-nat chain=dstnat comment=1.61.10.in-addr.arpa dst-address=10.35.1.1 dst-port=53 layer7-protocol=1.61.10.in-addr.arpa protocol=tcp to-addresses=10.61.1.1 \
    to-ports=53
add action=dst-nat chain=dstnat comment=1.61.10.in-addr.arpa dst-address=10.35.1.1 dst-port=53 layer7-protocol=1.61.10.in-addr.arpa protocol=udp to-addresses=10.61.1.1 \
    to-ports=53

В результате, даже если какой-то из узлов сети упадет, все остальные будут работать и разрешать имена друг-друга. Да, к слову, есть еще один интересный скрипт, который позволяет создавать IPSec-туннели не имея статических IP-адресов:

:foreach policy in=[/ip ipsec policy find] do={
  :if ([/ip ipsec policy get $policy sa-src-address]!=[:resolve [/ip cloud get dns-name]]) do={
    /ip ipsec policy set $policy sa-src-address=[:resolve [/ip cloud get dns-name]]
  }
  :if ([/ip ipsec policy get $policy comment]!="") do={
    :if ([/ip ipsec policy get $policy sa-dst-address]!=[:resolve [/ip ipsec policy get $policy comment]]) do={
      /ip ipsec policy set $policy sa-dst-address=[:resolve [/ip ipsec policy get $policy comment]]
    }
  }
}
:foreach peer in=[/ip ipsec peer find] do={
  :if ([/ip ipsec peer get $peer comment]!="") do={
    :if ([/ip ipsec peer get $peer address]!=([:resolve [/ip ipsec peer get $peer comment]] . "/32")) do={
      /ip ipsec peer set $peer address=([:resolve [/ip ipsec peer get $peer comment]] . "/32")
    }
  }
}

Надеюсь, будет полезным.

ravdinve ()
Ответ на: комментарий от intelfx

Да, маленькое уточнение. Чтобы реализовать отказоустойчивость, я держу «условный DNS-сервер» (полноценным DNS-сервером это назвать, конечно же, сложно) на каждом из MikroTik-ов. Тоже была мысль поднять bind на каком-нибудь из узлов и обращаться всегда к нему, но т.к. сбой (причем банальный, интернет оплатить забыли) может случиться где угодно, я побоялся реализовывать такую топологию. На мой взгляд в вашем случае отдельный dnsmasq также будет избыточным.

ravdinve ()
Ответ на: комментарий от ravdinve

У меня в любом случае топология «звезда», поэтому от наличия центрального DNS-сервера я ничего не теряю. При этом я специально постарался сделать так, чтобы избежать перечисления всех подсетей вообще где-либо (кроме конфигурации центрального DNS-сервера): все правила файрволла написаны обобщённо и все политики тоже шаблонные.

intelfx ★★★★★ ()
Ответ на: комментарий от ravdinve

Да, к слову, есть еще один интересный скрипт, который позволяет создавать IPSec-туннели не имея статических IP-адресов

Да, я и так делаю в точности то же самое. Но спасибо.

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

К слову, давно спросить хотел: как получить пять звездочек? За что они вообще даются и как считается Score. Отдельную тему создавать не хочу, а поиск ни к чему не привел.

ravdinve ()
Ответ на: комментарий от anonymous

Две сетки из четырех - дома. Признаю, никакой необходимости (дома) в этих извращениях нет, но прикольно же!

ravdinve ()
Ответ на: комментарий от ravdinve

1 единица score начисляется каждые два дня, если в их течение пользователь «проявлял активность» (написал хотя бы одно сообщение) в техразделах. За нарушение правил форума (в любых разделах) можно получить штраф в виде вычитания нескольких единиц score (-2, -7, -20 на усмотрение модератора). 100 score — одна звезда, максимум 5 звёзд.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 5)
Ответ на: комментарий от ravdinve

Да, за публикацию новостей (насчёт галереи не уверен) можно получить поощрение в виде нескольких единиц score (на усмотрение подтверждающего модератора, не обязательно 15).

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

intelfx

Одна из сетей — дома. А ещё в общежитии, на даче и дома у родственников. А что?

Полагаю, кому-то это кажется невероятным извращением. Кстати, к слову об извращениях. Какие еще интересные штуки реализуете в «домашней сети»?

ravdinve ()
Ответ на: комментарий от ravdinve

Полагаю, кому-то это кажется невероятным извращением.

Возможно. Но у меня это всё служит конкретным практическим целям — нужен доступ к узлам в других сетях.

Какие еще интересные штуки реализуете в «домашней сети»?

Да никаких. Даже DLNA-сервера нет, NAS и HTPC на одной машине. Можно было бы много чего сделать, но времени нет.

intelfx ★★★★★ ()
Ответ на: комментарий от ravdinve

Да, это работает.

Итак:

dnsmasq.conf на 10.159.230.2:

port=5353
no-resolv

server=/9-20.lan/10.159.230.1
server=/230.159.10.in-addr.arpa/10.159.230.1

server=/sanino.lan/10.167.15.1
server=/15.167.10.in-addr.arpa/10.167.15.1

# сюда остальные подсети с IPsec-туннелями

local=/ovpn.lan/

no-hosts
addn-hosts=/etc/admin/hosts

openvpn.conf на 10.159.230.2 (выдержка):

script-security 2
client-connect "/etc/systemd/scripts/admin/openvpn-client.sh connect .ovpn.lan /etc/admin/hosts"
client-disconnect "/etc/systemd/scripts/admin/openvpn-client.sh disconnect .ovpn.lan /etc/admin/hosts"
push "dhcp-option DNS 10.159.230.1"
push "dhcp-option DOMAIN lan"

openvpn-client.sh на 10.159.230.2: http://ix.io/1Ts5

Файрволл на 10.159.230.1 и аналогично на остальных роутерах:

[admin@router] > /ip firewall layer7-protocol print
 # NAME                                                                                                                 REGEXP                                                                                                                
 0 ;;; DNS queries for .9-20.lan or DNS PTR queries for 10.159.230.0/24
   dns:9-20.lan                                                                                                         ([\x04]9-20[\x03])|([\x03]230[\x03]159[\x02]10[\x07]in-addr[\x04]arpa)
 1 ;;; DNS queries for .lan or DNS PTR queries for 10.0.0.0/8
   dns:lan                                                                                                              ([\x03]lan)|([\x02]10[\x07]in-addr[\x04]arpa)

[admin@router] > /ip firewall nat print # выдержка
 5    ;;; Conditional DNS forwarding
      chain=dstnat action=jump jump-target=dstnat-dns protocol=udp dst-address=10.159.230.1 dst-port=53 log=no

 6    ;;; Conditional DNS forwarding: *.9-20.lan -> ignore
      chain=dstnat-dns action=return layer7-protocol=dns:9-20.lan log=no

 7    ;;; Conditional DNS forwarding: *.lan -> server
      chain=dstnat-dns action=dst-nat to-addresses=10.159.230.2 to-ports=5353 layer7-protocol=dns:lan protocol=udp log=no

DHCP lease-скрипт на 10.159.230.1: http://ix.io/1Ts9

Здесь опущены SNAT-правила, нужные для правильной маршрутизации DNS-ответов в OpenVPN-подсети (т. к. DNS-сервер и OpenVPN-сервер на одной и той же машине, без SNAT ответы от DNS направляются сразу в OpenVPN-подсеть и не проходят обратную подмену адреса). Запросы к 9-20.lan (это как раз 10.159.230.0/24) принимаются и отвечаются встроенным ресолвером, остальные запросы к lan перенаправляются на 10.159.230.2:5353. Синхронизация DHCP и DNS выполняется lease-скриптом, добавление DNS-записей для OpenVPN клиентов выполняется client-connect скриптом в сервере OpenVPN. На остальных роутерах аналогично.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от ravdinve

SNAT у меня выглядит вот так:

[admin@router] > /ip firewall mangle print
Flags: X - disabled, I - invalid, D - dynamic
 3    ;;; Mark DNAT'ed connections that may need SNAT in some circumstances (to route the reply back for de-DNATing)
      chain=postrouting action=mark-connection new-connection-mark=want-snat passthrough=no connection-state=new connection-nat-state=dstnat log=no

[admin@router] > /ip firewall nat print
Flags: X - disabled, I - invalid, D - dynamic
 0    ;;; Normal SNAT
      chain=srcnat action=masquerade to-addresses=0.0.0.0 out-interface=ether1-gateway log=no log-prefix=""

 1    ;;; Hairpin SNAT: packets from our subnet DNATed back to our subnet (otherwise replies will skip routing) (TODO: widen for other subnets)
      chain=srcnat action=masquerade src-address=10.159.230.0/24 dst-address=10.159.230.0/24 connection-mark=want-snat log=yes log-prefix="hairpin"

 2    ;;; Hairpin SNAT: packets from OVPN subnets DNATed to OVPN server (otherwise replies will be routed internally on the OVPN server and miss deDNATing)
      chain=srcnat action=masquerade dst-address=10.159.230.2 src-address-list=ovpn-subnets connection-mark=want-snat log=yes log-prefix="hairpin-ovpn"

 3    ;;; Hairpin SNAT: packets from OVPN server DNATed to OVPN subnets (otherwise replies will be routed internally on the OVPN server and miss deDNATing)
      chain=srcnat action=masquerade src-address=10.159.230.2 dst-address-list=ovpn-subnets connection-mark=want-snat log=yes log-prefix="hairpin-ovpn"

 5    ;;; Quasi-hairpin: packets from Internet DNATed to foreign subnets (otherwise replies will be sent directly to Internet and miss deDNATing)
      chain=srcnat action=masquerade src-address=!10.0.0.0/8 dst-address=!10.159.230.0/24 connection-mark=want-snat log=yes log-prefix="hairpin-wan-to-vpn"

intelfx ★★★★★ ()
Ответ на: комментарий от intelfx

Твой выбор DNS-а по таким критериям - dnsmasq

Насчёт того как взгромоздить на mikrotik отдельный резолвер есть крамольная мысля(но она говно) - metarouter и там уже openwrt.

Говно, потому что:
а) Насколько мне известно OpenWRT нужен сильно патченный и не на любом микротике взлетит;
б) Производительность данного решения будет говно;

Pinkbyte ★★★★★ ()
Ответ на: комментарий от ravdinve

<moderator hat>От 1 до 20 единиц можно выдать технически. В среднем дают 3-15 единиц в зависимости от новости</moderator hat>

Pinkbyte ★★★★★ ()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от intelfx

Возьму на заметку, может и мне пригодится

Хоть какая-то польза от того, что DNS ходит в открытом виде

Pinkbyte ★★★★★ ()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.