PPP over SSH over HTTP
Настройка доступа в Интернет через HTTP proxy
18 февраля 2008 г.
Дано
- Рабочая станция с ОС Linux (Fedora) в локальной сети организации
- Доступ в Интернет через HTTP proxy с авторизацией Kerberos или NTLM
- Сервер в Интернете с административными правами на нем (например, домашний
компьютер с реальным IP-адресом)
- Прокси-сервер поддерживает команду HTTP CONNECT на порт 443 (https)
Не дано
- Доступ в Интернет по произвольным портам на произвольные адреса
- Доступ через прокси-сервер без авторизации
- Доступ через прокси-сервер с простой авторизацией (basic, digest)
Требуется
Настроить доступ на некоторый сервер в Интернете по протоколу cvspserver
Метод решения
Настроим доступ в Интернет на произвольные порты на требуемый сервер. Для
этого:
- Установим прокси-сервер, который может авторизоваться на прокси-сервере
компании по протоколу NTLM.
- Повесим ssh на внешнем сервере на порт 443.
- Настроим туннелирование ssh через http.
- Настроим туннелирование PPP через SSH.
- Настроим маршрутизацию с обеих сторон полученного туннеля.
Обозначения
ws.company.test - наша рабочая станция
proxy.company.test - прокси-сервер (пусть он слушает на порту 8080), как он виден из локальной сети организации
proxy_out.company.test - реальный адрес прокси-сервера, который виден из
Интернета
server.somewhere.test - сервер в Интернете, на который мы имеем
административный доступ
target.test - сервер, на который мы желаем получить доступ по произвольным
портам.
Проверка возможности настройки канала
- Убеждаемся, что у нас имеется доступ через корпоративный прокси-сервер. Для
этого запускаем браузер Mozilla Firefox, прописываем там прокси-сервер, и
убеждаемся, что нас пускают на произвольные адреса в Интернете. Этот доступ
нам также понадобится для загрузки необходимого ПО.
- Проверяем, что прокси-сервер позволяет доступ по протоколу HTTP CONNECT. См.
инструкции в Интернете.
1. Установка прокси-сервера, авторизующегося по протоколу NTLM.
Инструкция написана для версии cntlm-0.35.1. В следующих версиях могут быть
исправлены некоторые неудобства установки.
- Скачиваем прокси-сервер cntlm - http://freshmeat.net/projects/cntlm/.
- Устанавливаем как обычно (./configure && make && make install)
- Создаем пользователя cntlm, под которым будет работать прокси-сервер.
Пользователя добавляем как системного, для чего находим свободный uid меньше
1000 в /etc/passwd. Допустим, свободен uid 102.
adduser -u 102 cntlm
- Создаем директорию /var/run/cntlm и присваиваем ее созданному пользователю:
mkdir /var/run/cntlm
chown cntlm:cntlm /var/run/cntlm
- Копируем файл cntlm.conf из директории doc дистрибутива в /usr/local/etc.
- Прописываем в конфигурационном файле логин и пароль и домен для доступа к
корпоративному прокси-серверу.
Username your_windows_login
Domain your_company_windows_domain
Password your_windows_password
Proxy proxy.company.test:8080
- Копируем файл cntlm.sysconfig из поддиректории redhat дистрибутива в
/etc/sysconfig под именем cntlmd (не забудьте букву d в конце имени файла)
- Исправляем в нем путь к бинарнику cntlm на реальный:
DAEMON=/usr/local/bin/cntlm
- Копируем файл cntlm.init из поддиректории redhat дистрибутива в директорию
/etc/rc.d/init.d под именем cntlm.
- Меняем в нем в строке "daemon cntlm $OPTARGS 2>/dev/null" слово cntlm на
$DAEMON. Должно получиться:
daemon $DAEMON $OPTARGS 2>/dev/null
- Включаем сервис командой chkconfig cntlm on.
- Запускаем:
service cntlm start
- Проверяем:
telnet localhost 3128
GET http://ya.ru HTTP/1.0<CR><CR>
- Прописываем прокси-сервером по умолчанию в /etc/bashrc строкой:
export http_proxy=http://localhost:3128/
- Заставляем текущую оболочку перечитать этот файл:
exec bash
- Проверяем:
lynx ya.ru
2. Вешаем ssh на внешнем сервере на порт 443
Эту операцию невозможно выполнить из офиса. Сделайте ее вечером из дома, из
Интернет-кафе, через мобильный телефон или как-либо еще. Но предварительно
узнайте, под каким внешним IP-адресом выходит в Интернет корпоративный
прокси-сервер. Для этого можно либо воспользоваться соответствующими сайтами в
Интернете, либо, если на вашем внешнем сервере запущен веб-сервер, запросить
несуществующую страницу с характерным именем (например,
http://server.somewhere.test/remember_corporate_ip), а потом найти
соответствующую строку в логах веб-сервера (grep remember_corporate
access_log).
Цель работы - повесить сервер ssh на порт 443 (https). Но на сервере уже может
работать веб-сервер на этом порту и может оказаться нежелательным отключать на
нем протокол HTTPS. Мы сделаем переадресацию портов так, чтобы при коннекте на
443-й порт с прокси-сервера корпоративной сети запрос переадресовался на порт
22, а при коннекте с других адресов запрос обрабатывался как обычно
веб-сервером.
- Редактируем файл конфигурации iptables. Предполагается, что это скрипт bash,
а не файл хитрого формата, использующийся в современных версиях
дистрибутивов RedHat. Прописываем в нем строку:
iptables -t nat -A PREROUTING -p tcp -s $IP_HTTPS_SSH -d $INET_IPADDR --dport
443 -j DNAT --to-destination $INET_IPADDR:22
Где $INET_IPADDR - IP-адрес сервера, под которым он виден из Интернета
(server.somewhere.test),
$IP_HTTPS_SSH - внешний IP-адрес корпоративного прокси-сервера, который мы
нашли в логах (proxy_out.company.test).
- Перезапускаем iptables:
service iptables restart
По идее, уже должно работать. Но хотелось бы проверить прямо сейчас. Для теста
временно вместо адреса корпоративного прокси-сервера можно прописать адрес
текущей машины, за которой Вы сейчас работаете, перезапустить iptables, и
проверить, что перенаправление портов работает:
telnet server.somewhere.test 443
Если все нормально, сервер ответит строкой со словами SSH, OpenSSH и номером
версии. Дальше нам сессия telnet не нужна - можно прервать ее через Ctrl-[ и
quit. Можно для теста соединиться через ssh:
ssh server.somewhere.test
Нам понадобится еще раз редактировать тот же файл настроек iptables, когда мы
будем настраивать маршрутизацию. Но пока это можно отложить.
3. Настраиваем туннелирование ssh через прокси-сервер.
Возвращаемся в офис.
Устанавливаем программу proxytunnel
(http://freshmeat.net/projects/proxytunnel/).
Инструкция для версии proxytunnel-1.6.3.
- Скачиваем и устанавливаем программу как обычно (make && make install).
- Создаем у себя в домашней директории в поддиректории .ssh файл config с
содержимым:
Host server.somewhere.test
ProxyCommand /usr/local/bin/proxytunnel -p localhost:3128 -d
server.somewhere.test:443
(команда ProxyCommand вплоть до 443 размещается на одной строке).
- Проверяем:
ssh server.somewhere.test
Мы получили доступ в Интернет по протоколу ssh. Этот доступ уже позволяет
вздохнуть свободнее, т.к. на внешнем сервере мы можем выполнять любые
программы и соединяться с любыми адресами на любые порты.
Соединение через туннель имеет свойство отваливаться после некоторого периода
бездействия. Если доступ требуется обычно на небольшое время, то это не
вызывает особых неудобств. Если же Вам нужно соединение, которое не будет
рваться при длительном бездействии, то можете попробовать настроить это
самостоятельно.
4. Настраиваем туннелирование ppp через ssh.
Настройка туннеля затрагивает и рабочую станцию (ws.company.test), и сервер в
Интернете (server.somewhere.test).
- Проверяем, что на обоих концах туннеля ядро поддерживает протокол ppp.
Запускаем pppd под root'ом и наблюдаем несколько строк фигурных скобок и
прочих символов. Если вместо них появляется сообщение о том, что ppp не
поддерживается ядром, пробуем загрузить модуль ядра:
modprobe ppp_async
Если получилось - прописываем автоматическую загрузку модуля этой строкой в
/etc/rc.d/rc.local или в другом месте. Если не получилось - перекомпилируем
ядро с поддержкой ppp и асинхронного ppp, перезагружаем сервер и проверяем по
вышеописанному.
- Создаем пользователя sshvpn на обеих машинах. Создаем его также как
системного пользователя, для чего находим свободный uid в /etc/passwd,
допустим, свободен uid 103.
adduser -u 103 -d /opt/ssh-vpn sshvpn
- Создаем поддиректорию .ssh в домашней директории пользователя sshvpn.
Делаем это на обоих концах туннеля. Самый простой способ создания директории
с нужными правами доступа - соединиться куда-нибудь с помощью ssh. Например:
ssh localhost
- На рабочей станции создаем файл config в директории ~sshvpn/.ssh точно такой
же, какой мы делали для себя. Можно просто скопировать тот файл. Не забыть
поменять собственника файла и проверить права доступа:
chown sshvpn:sshvpn ~sshvpn/.ssh/config
chmod 600 ~sshvpn/.ssh/config
- Проверяем, что доступ с рабочей станции на сервер для пользователя sshvpn
работает:
su - sshvpn
ssh some_user@server.somewhere.test
- Создаем на рабочей станции ключ для авторизации на сервере без пароля:
su - sshvpn
ssh-keygen -t dsa
Для ключа не задаем пароль (нажимаем Enter при запросе пароля).
- Копируем файл id_dsa.pub на сервер в директорию ~sshvpn/.ssh под именем
authorized_keys.
Соединяемся с рабочей станции на сервер из-под пользователя sshvpn. Должно
пустить на сервер без пароля. Если не пустило - разбираемся с ошибками.
- Разрешаем запуск pppd пользователю sshvpn и на рабочей станции и на сервере. для этого запускаем команду visudo и дописываем в конец файла строки:
Cmnd_Alias VPN=/usr/sbin/pppd
sshvpn ALL=NOPASSWD: VPN
В принципе можно не разрешать запуск pppd на рабочей станции, если нужно
открывать канал только с консоли root'а.
- Тестируем. Запускаем под root'ом
/usr/sbin/pppd updetach noauth pty 'sudo -u sshvpn ssh -t -t server.somewhere.test sudo pppd noauth 192.168.254.254:192.168.254.253'
Вся команда набирается в одну строку. IP-адреса в конце команды можно
изменить, если эта сеть уже используется в локальной сети Вашей организации.
При успешном соединении появился новый интерфейс ppp0 с заданным адресом,
который можно увидеть командой ifconfig.
Теперь мы можем соединяться с сервером server.somewhere.test на любые порты, а
не только на ssh.
Сказанное выше про разрыв связи по ssh после некоторого бездействия относится
и к созданному сейчас туннелю.
Подробнее см. http://www.citforum.ru/operating_systems/linux/linux_vpn/ (там
имеются некоторые неточности).
5. Настраиваем маршрутизацию
Нам требуется доступ не на промежуточный сервер, а на некоторый сервер в
Интернете. Чтобы пакеты доходили туда и обратно, требуется настроить
маршрутизацию так, чтобы на рабочей станции пакеты уходили в туннель, на
промежуточном сервере выныривали из него, и на обратном пути опять заныривали.
- На промежуточном сервере server.somewhere.test настраиваем NAT. В настройках
iptables прописываем строку:
iptables -t nat -A POSTROUTING -s $PRIV254_NET -o $INET_DEVICE -j SNAT --to-source $INET_IPADDR
где:
PRIV254_NET=$PRIV254_NETWORK/$PRIV254_NETMASK
PRIV254_NETWORK=192.168.254.0 (адрес, заданный в строке /usr/sbin/pppd ...)
PRIV254_NETMASK=255.255.255.0
INET_IPADDR - адрес сервера (server.somewhere.test)
$INET_DEVICE - интерфейс, которым сервер смотрит в Интернет (например, eth0)
- На рабочей станции запускаем команду:
route add -host target.test gw 192.168.254.254
На этом шаге должен появиться доступ, ради которого мы все настраивали.
Через некоторое время бездействия канал отвалится (*). Для удобства можно создать
скрипт для запуска под root'ом в те моменты, когда требуется доступ к
удаленному серверу:
#!/bin/bash
/usr/sbin/pppd updetach noauth connect-delay 20000 pty \
'sudo -u sshvpn ssh -t -t server.somewhere.test\
sudo /usr/sbin/pppd noauth 192.168.254.254:192.168.254.253'
route add -host target.test gw 192.168.254.254
По непонятной причине соединение устанавливается обычно не с первого раза, а
со второго. Выяснение этой причины оставим читателям в качестве
самостоятельного задания.
PS. (*) Сергей Рекубратский подсказывает, что от разрыва помогает настройка "ServerAliveInterval 60" в конфиге ssh.