systemd-resolved
Поставил пакеты network-manager-openconnect network-manager-openconnect-gnome
Настроил соединение и оно даже подключилось. Проблема первая, каждый раз когда я подключался снова, он забывал имя пользователя, что раздражает. Я нашел решение и создал
баг. Решение простое, с консоли задаем свое имя в особом виде nmcli con mod prgcvp vpn.secrets 'form:main:username=yourName','save_passwords=yes'
После чего оно будет запомнено. Да, галочку «запомнить пароль» я ставил и пароль он даже запомнил, но вот в тексте галочки про имя пользователя ничего не сказано, так что он честно его забыл :) Напомню, что настройки менеджера лежат в /etc/NetworkManager/system-connections/.
И если параметры знаешь, то можно и руками отредактировать нужное соединение.
Подключаться стало удобно и возникла вторая проблема, имена ресурсов в VPN сети не разрешаются в адреса DNS сервером. Сервер есть, все настройки на месте, но nslookup someserver.local выдает ошибку, а nslookup someserver.local somednsIP выдет правильный ответ. Странно, подумал я, как так, сервер есть, отвечает, а если его конкретно не указать, ошибка? Ответ оказался прост. Когда systemd-resolved пытается найти адрес сервера по имени, он выступает фасадом для других DNS серверов. Делается это так, ссылка /etc/resolv.conf может указывать на несколько мест:
- /run/systemd/resolve/stub-resolv.conf это опция по умолчанию и этот файл будет содержать примерно такое
nameserver 127.0.0.53
options edns0 trust-ad
search somedomain.local - /run/systemd/resolve/resolv.conf это можно использовать если функционал systemd-resolved чем то не устроил когда он прикидывается DNS сервером 127.0.0.53. В итоге это не пригодилось, так для информации пишу.
Подробности тут.
Саму ссылку /etc/resolv.conf вы можете сами настроить что бы смотрела в любое из мест.
Так вот, дело в том, что openconnect при подключении к VPN получает таблицу route, DNS сервера, а так же search domain и этот домен от VPN сервера приходил неверный (так неправильно настроен у нас). От сервера приходило somedomain.local, а надо было просто local что бы somesrver.local был распознан.
Когда systemd-resolved прикинулся локальным DNS сервером и через /etc/resolv.conf всех отправил к себе за разрешением имен, логика его работы такова. Для каждого коннекта, которые можно посмотреть командой nmcli connection show (это те коннекты, которые знает NetworkManager) systemd-resolved помнит DNS сервера, которые получил по DHCP. Это можно посмотреть командой:
resolvectl dns
Global:
Link 6 (docker0):
Link 5 (vpn0): 999.999.999.999 999.999.999.999
Link 3 (wlp4s0): 192.168.3.8
Link 2 (enp5s0f2):
Когда в 127.0.0.53 приходит запрос на разрешение имени, systemd-resolved смотрит search domain у каждого из коннектов (эти домены он при подключении от DHCP получил тоже). Домены можно посмотреть командой:
resolvectl domain
Global:
Link 6 (docker0):
Link 5 (vpn0): somedomain.local
Link 3 (wlp4s0): ~.
Link 2 (enp5s0f2):
Далее имя хоста проверяется на частичное совпадение с теми доменами, которые прикреплены к коннектам и самое длинное совпадение и определяет какой конкретно DNS сервер вызвать. Либо все идет в DNS сервер где search domain "~."
От сервера компании мне приходил неверный search domain (somedomain.local) для VPN коннекта и потому когда я пытался разрешить адрес someserver.local, systemd-resolved их не мог найти, так как предполагал, что DNS сервера, полученные из этого соединения нужны что бы распознавать имена someserver.somedomain.local. Поправил я это подменив search domain в NetworkManager командой
nmcli connection modify yourConnectionName ipv4.dns-search «local»
Доменов может быть несколько через пробел. В итоге все заработало.
Помимо этого я удалил пакет avahi-daemon, так как службы bonjur, которые обслуживает этот демон по умолчанию тоже резолвятся на домене local, а в нашей сетке именно это имя используется для локальной сети и будут конфликты.
docker
Теперь в хост системе работает резолвинг адресов, но при запуске докера резолвинг локальных адресов в VPN может не работать по прежнему. И тут есть несколько вариантов.
Контейнер запущен с network_mode: host в таком случае будет использоваться для резольвинга то, что лежит в /run/systemd/resolve/resolv.conf и там у меня первый же днс сервер выбирается для резольва local и он для этого не подходит. Итог, не работает. Зато все сервисы хост машины видно из контейнера, что еще и неправильно.
Контейнер запущен с network_mode: bridge с созданием отдельной сети. В таком случае сервисы хоста будет не видно, помимо этого будет использован все тот же не работающий у меня /run/systemd/resolve/resolv.conf
Контейнер запущен без настроек сети и использует дефолтный bridge, созданный докером при инсталляции (docker0). В этом случае используется для резольва имен внутренний докеровский DNS, который судя по всему нормально взаимодействует с systemd-resolved и все резолвит как надо. В /etc/resolv.conf будет такое:
bash-5.0# cat /etc/resolv.conf
search local
nameserver 127.0.0.11
options ndots:0
Если надо показать сервисы хост машины для доступа из контейнера, то просто запускаем сервисы слушать на docker0 IP и получаем доступ.
ifconfig|grep -n1 docker0
27-
28:docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
29- inet 192.168.32.1 netmask 255.255.240.0 broadcast 192.168.47.255
Не забываем открыть порты, например у меня ufw зарезал 8080 и пришлось открывать.
Было бы отлично если бы docker просто использовал systemd-resolved dns stub как в последнем описанном варианте всегда. Но к сожалению это не так. В версии systemd-resolved 248, которая только вышла и в дистрах ее нет в документации есть параметр DNSStubListenerExtra, который может задать адрес где слушать для stub. Подробности тут.
В итоге можно будет указать адрес где слушать не захардкоженный 127.0.0.53, а доступный изнутри докера и все будет работать, но пока нет.
Есть другое решение, когда контейнер пойдет на порт 53 мы будем перебрасывать его запросы в стаб systemd с помощью чего то вроде
socat UDP-LISTEN:53,fork,reuseaddr,bind=yourInterfaceIP UDP:127.0.0.53:53
Соответственно, этот DNS можно указать докеру при старте и весь функционал systemd будет работать. Но не стал это использовать.
В итоге мы получаем работающий VPN на хосте, который резолвит имена в локальной сети, работающий докер, который может резолвить эти адреса как родные.
kozlyuk
Тема поднята важная, но в тексте сумбур и колхоз.
--add-host
/extra_hosts
для контейнер (не лучше /etc/hosts).AlexGluck
2й пункт поддерживаю.
По 3ему пункту можете поделиться знаниями?
kozlyuk
https://github.com/lathiat/nss-mdns
AlexGluck
Я бы хотел описание, что, где, как, зачем, для чего. Но уже сам разобрался(
Вот старая статья, которая, к сожалению, не рассказывает, почему надо такие настройки делать.
Вот здесь описание работы библиотек/и для nsswitch.
Вот здесь описание файла настроек nsswitch.
В кратце, строка в конфиге должна выглядеть так:
hosts: files mdns4_minimal dns mdns
Почему так:
1. Мы проверяем сначала файлы hosts.
2. Потом проверяем адреса 169.254.0.0/16 и домены X.local и Y.local. (только второй уровень днс).
3. Потом делаем поиск в днс серверах.
4. И только после этого проверяем все адреса ip стеков 4 и 6, а так же все домены перечисленные в файле /etc/mdns.allow