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

Вопрос про systemd, сокеты и проблему с программным прослушиванием трафика для отказа от сокетов.

 ,


1

2

Решил я автоматизировать процесс запуска dnscrypt-proxy с помощью systemd, ибо надоело после каждой перезагрузки запускать из консоли. Погуглил — нашел готовый шаблон — сделал. Вроде бы можно насладиться успехом — но нет, мне захотелось разобраться что это за конфиги и что они делают. Все шло успешно, пока я не споткнулся об одну теоретически решаемую проблему, при желании заменить целый конфиг на пару символов.

dnscrypt-proxy — софт, цель которого в шифровании DNS трафика и его обменом со специальными DNS серверами.
dnscrypt-proxy имеет функцию прослушивания трафика с помощью атрибута -a [ip:port]

Итак, имеется есть два юнита: сокет dnscrypt-proxy.socket, который слушает IP 127.0.0.2:53(DNS трафик, в моем случае) и перенаправляет весь трафик на служебный юнит dnscrypt-proxy.service, который уже работает непосредственно с dnscrypt-proxy, если я правильно разобрался.

Так вот, сам вопрос: почему команда dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53 не равна записи ExecStart=/usr/sbin/dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53 в конфиге? Иначе как объяснить, что первая работает, а вторая — нет?


__________
Вот как выглядят юниты:
-----
/etc/systemd/system/dnscrypt-proxy.service

[Unit]
Description=DNSCrypt client proxy
Requires=dnscrypt-proxy.socket

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
NonBlocking=true
ExecStart=/usr/sbin/dnscrypt-proxy -R dns.server.name

-----
/etc/systemd/system/dnscrypt-proxy.socket
[Unit]
Description=dnscrypt-proxy listening socket
After=network.target

[Socket]
ListenStream=127.0.0.2:53
ListenDatagram=127.0.0.2:53

[Install]
WantedBy=sockets.target
__________


Ты не понимаешь, как работает socket-активация в systemd. Она требует специальной поддержки со стороны запускаемого приложения (в данном случае dnscrypt-proxy).

Вкратце: на раннем этапе загрузки (ещё до монтирования ФС) systemd проходит по всем *.socket-файлам и сам открывает все перечисленные в них сокеты. Таким образом складывается впечатление, что программа уже работает и к ней можно подключаться, хотя на самом деле нет. Когда же в сокет в конце концов прилетают какие-то данные (кто-то хочет подключиться) — systemd не трогает эти данные, оставляя их во внутриядерном буфере, но запускает основную программу (*.service-файл). Дальше самое главное: эта программа должна специальным образом «забрать» у systemd уже открытый сокет, в котором уже есть какие-то данные, и обработать их.

Соответственно, чтобы сказать программе, что она должна не сама открывать нужный сокет, а забирать из systemd уже готовый, мы используем немного другие параметры командной строки (ExecStart=/usr/local/sbin/dnscrypt-proxy -R dnscrypt.eu-nl).

Если написать ExecStart=/usr/sbin/dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53, то dnscrypt-proxy сам попытается открыть сокет на порту 53 и обломается, потому что этот сокет уже был открыт самим systemd.

В итоге есть два варианта:

  1. выкинуть *.socket-файл и указать порт в командной строке dnscrypt-proxy, со всеми вытекающими (dnscrypt-proxy будет запущен только в конце загрузки, что может быть неприемлемо для тебя — все программы, которые по стечению обстоятельств сделают DNS-запросы до запуска dnscrypt, либо обломаются, либо уйдут во второй по списку ресолвер, обходя dnscrypt, если у тебя в resolv.conf не только 127.0.0.1);
  2. оставить всё как есть, т. е. взять *.socket- и *.service-файлы из первоисточника (.socket, .service).
intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 3)
Ответ на: комментарий от intelfx

Ясно, спасибо. Я предполагал, что dnscrypt-proxy поддерживает сокет, который бы прослушивал IP.

Но мне все равно не понятно, почему строка ExecStart=/usr/sbin/dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53 не равна команде dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53?

Ведь в обоих случаях происходит обращение к dnscrypt-proxy с одинаковыми аргументами.

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

Я предполагал, что dnscrypt-proxy поддерживает сокет, который бы прослушивал IP.

Ты правильно предполагал — dnscrypt-proxy умеет сам открывать IP-сокеты. Но в данном случае мы просим его этого не делать, т. к. уже сделано заранее.

почему строка ExecStart=/usr/sbin/dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53 не равна команде dnscrypt-proxy -R dns.server.name -a 127.0.0.2:53?

Почему не равна? Вполне равна. Но чтобы это работало, необходимо заранее «освободить» порт 53, т. е. (в частности) отключить и остановить соответствующий .socket-файл. А также убрать из .service-юнита директиву Requires=dnscrypt-proxy.socket, иначе этот .socket будет автоматически запускаться и мешать.

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

Сделал, все работает :)

[Unit]
Description=DNSCrypt client proxy

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
NonBlocking=true
ExecStart=/usr/sbin/dnscrypt-proxy -R dns.server.name -E -a 127.0.0.2

Получается dnscrypt теперь запускается последним, потому что не указано после чего это делать, и приоритет самый низкий?

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

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

intelfx ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.