30 июл. 2013 г.

Краткий экскурс в sslh

Доступ ко многим сервисам (особенно в публичных местах или при проксированном доступе на рабочем месте) "из коробки" не работает: что SSH, что OpenVPN, что Jabber, что $еще_стопицот_нужных_сервисов требуют NAT или разрешенный порт на прокси для подключения к удаленной точке. Если таких настроек нет - соединение установить не удастся. 
Однако на сегодняший день реалии таковы, что любой, пусть даже самый ограниченный, доступ к интернет-ресурсам подразумевает разрешенные исходящие соединения на 443/tcp. А это значит, что при наличии собственного сервера в интернете, мы можем получить доступ к нему (или куда-либо еще) с помощью демона sslh.
Этот демон висит на внешнем (доступном из Сети) IP и слушает 443 порт, анализируя входящий трафик. По заголовкам пакетов он определяет "чьих будете" и перенаправляет трафик на соответствующий внутренний адрес и порт. По умолчанию на сегодняший день поддерживаются HTTP, SSL, SSH, OpenVPN, tinc, XMPP, а также существует возможность описать любой другой протокол, задав уникальный для его однозначного определения regex
Разработчики заявляют, что sslh опакечен для многих дистрибутивов (Debian точно есть), но даже если и врут, собрать свежую версию из исходников быстро и просто.
Например, для моего сервера с устаревшим уже Squeeze это будет выглядеть примерно так (в репозитории пакет доступен, однако его версия не умеет иных протоколов, кроме ssh\ssl):
Загружаем исходники:
wget http://www.rutschle.net/tech/sslh-1.15.tar.gz
Распаковываем и переходим в каталог:
tar -zxvf sslh-1.15.tar.gz
cd sslh-1.15.tar.gz
Читаем README, узнаем, что для сборки необходимы заголовочные файлы библиотек libconfig и libwrap. Устанавливаем оные (при необходимости нужно установить набор пакетов для сборки - build-essential):
apt-get install libconfig8-dev libwrap0-dev
Ввиду малого объема кода настройка через configure-скрипт не используется, все изменения в конфигурацию по умолчанию следует внести прямо в Makefile. Меняем PREFIX на
PREFIX=/usr
Далее пробуем собрать бинарник:
make
Если процесс завершился без ошибок, устанавливаем sslh (для Debian сделана специальная цель в Makefile, поэтому используется не make install):
make install-debian
Настраиваем форвардинг нужных нам сервисов (в файле /etc/default/sslh):
LISTEN=server.example.org:443
SSH=localhost:22
SSL=localhost:443
XMPP=localhost:5222
USER=nobody
PID=/var/run/sslh.pid
В предложенном примере sslh будет запущен на интерфейсе с адресом server.example.org:443 (можно указать и IP-адрес). Перед запуском следует убедиться, что порт 443/tcp на желаемом адресе не занят, иначе sslh не сможет запуститься. Форвардиться на внутренний интерфейс будут доступны по умолчанию сервисы SSL, SSH и XMPP. Запустится sslh от имени пользователя nobody, а свой PID запишет в /var/run/sslh.pid
Все, запускаем sslh:
/etc/init.d/sslh star
Да, выяснилось, что init-файл подставляет в строку запуска демона только переменные SSL и SSH, то есть ничего другое (из протоколов) при старте демону не передастся. Лечится ручным добавлением соответствующего параметра. Например, для запуска с форвардингом XMPP я меняю в /etc/init.d/sslh
 start()
{
        echo "Start services: sslh"
        $DAEMON --user ${USER} --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL} --pidfile ${PID}
        logger -t ${tag} -p ${facility} -i 'Started sslh'
}
на
  start()
{
        echo "Start services: sslh"
        $DAEMON --user ${USER} --listen ${LISTEN} --ssh ${SSH} --ssl ${SSL} --xmpp ${XMPP} --pidfile ${PID}
        logger -t ${tag} -p ${facility} -i 'Started sslh'
}
Итак, после запуска в списке сервисов должно быть примерно следующее:
 # ps aux | grep sslh
nobody   13923  0.0  0.0   2084   528 ?        Ss   20:30   0:00 /usr/sbin/sslh --user nobody --listen server.example.org 443 --ssh localhost 22 --ssl localhost 443 --xmpp localhost 5222 --pidfile /var/run/sslh.pid
nobody   13925  0.0  0.0   2084   224 ?        S    20:30   0:00 /usr/sbin/sslh --user nobody --listen server.example.org 443 --ssh localhost 22 --ssl localhost 443 --xmpp localhost 5222 --pidfile /var/run/sslh.pid
nobody   29435  0.0  0.0   2296   676 ?        S    20:49   0:00 /usr/sbin/sslh --user nobody --listen server.example.org 443 --ssh localhost 22 --ssl localhost 443 --xmpp localhost 5222 --pidfile /var/run/sslh.pid
Почему сервисов несколько? Ответ есть в README: sslh собирается в два бинарника - sslh-fork, который запускает новый процесс при каждом новом потоке данных (подключении), и sslh-select, который держит все потоки внутри одного процесса. По умолчанию предлагается fork-вариант, как более стабильный. Однако, если предполагается поддерживать много соединений (несколько сотен), или просто не нравится множество одинаковых процессов в top-е, можно заменить sslh-fork на sslh-select (выполняется из каталога, где собирался sslh):
/etc/init.d/sslh stop
cp sslh-select /usr/sbin/sslh
/etc/init.d/sslh start
После этих операций процесс будет лишь один:
nobody    8956  0.0  0.0   2088   536 ?        Ss   21:43   0:00 /usr/sbin/sslh --user nobody --listen server.example.org 443 --ssh localhost 22 --ssl localhost 443 --xmpp localhost 5222 --pidfile /var/run/sslh.pid
Более сложные конфигурации - к примеру, проксирование или прозрачный режим работы, можно почитать в README.