Пользователь
0,0
рейтинг
9 марта 2015 в 14:51

Разработка → Опыт маскировки OpenVPN-туннеля с помощью obfsproxy tutorial

Преамбула


В связи с наметившимися тенденциями решил я обфусцировать свой скромный OpenVPN-туннель, просто чтобы набить руку — мало ли пригодится…

Дано: дешевая VPS с белым IP, работающая под Ubuntu Trusty Server Edition и служащая OpenVPN сервером.
Требуется: по-возможности скрыть OpenVPN туннель, желательно без изобретения велосипедов.

obfsproxy


Поскольку на VPS уже была поднята Tor-нода, мысль об obfsproxy пришла сама собой. Как оказалось, утилита действительно умеет притворяться SOCKS-proxy, а значит, обфусцировать не только соединения Tor, но и практически произвольный трафик. Пошарившись по Сети, я нашел несколько мануалов, но многие были либо устаревшими, либо выпускали из виду необходимые подробности.
Важно! Версии.
  • OpenVPN версий младше 2.3.4 содержит баг, мешающей нормальной работе с SOCKS прокси. Если вы хотите использовать режим socks, убедитесь, что у вас установлена подходящая версия OpenVPN.
  • Судя по всему, obfsproxy до сих пор не включен в репозиторий Tor, а в репозиториях Debian/Ubuntu могут лежать старые версии без подержки scramblesuit. В этом случае obfsproxy нужно устанавливать с помощью утилиты pip (пакет python-pip):
     pip install obfsproxy
    

    По окончании установки убедитесь, что используется версия obfsproxy с поддержкой scramblesuit:
     obfsproxy scramblesuit -h
    

  • Версию obfsproxy для Windows можно извлечь из пакета Tor Browser, найдя подкаталог Tor\PluggableTransports.


Из man obfsproxy можно почерпнуть следующее
 obfsproxy [logging_options] [--data-dir path] transport [--dest destination] [--password BASE32PASS] mode listen_addr

Чуть подробнее:
  • --data-dir statepath — каталог для размещения временных данных. Необходим, если obfsproxy работает не в managed режиме.
  • transport — выбирает метод обфускации трафика и режим его передачи. Нас интересуют следующие транспорты:
    • scramblesuit — сравнительно новый метод, который мы и будем использовать.
    • dummy — отладочный метод, при котором трафик передаётся как есть, без обфускации.

  • mode — выбирает режим работы прокси. Нас интересуют следующие режимы:
    • server — принимает клиентские соединения, деобфусцирует и перенаправляет на адрес destination. Этот режим пригодится на стороне сервера.
    • client — прозрачное проксирование: принимает данные, обфусцирует и отправляет серверу по адресу destination. То, что мы будем использовать на клиентской стороне.
    • socks — имитация socks-прокси.

    Разница между режимами client и socks в том, что в первом случае адрес удаленного хоста, к которому пытается подключиться целевое приложение, должен быть заменен на адрес opbfsproxy-клиента, тогда как во втором случае целевое приложение использует obfsproxy как SOCKS-прокси. Для наших целей подойдёт и client.
  • --dest destination — для сервера: задаёт пару адрес-порт, куда будут перенаправляться деобфусцированные соединения. Для клиента: задаёт адрес obfsproxy сервера.
  • --password BASE32PASS — задание ключа(pre-shared key) для метода scramblesuit. Ключ должен быть строкой длиной не менее 20 символов, закодированной в base32, и совпадать на клиенте и на сервере. Подходящий ключ можно сгенерировать так:
    python -c "import os,base64; print base64.b32encode(os.urandom(20))"
    

  • --password-file filepath — альтернативный метод задания ключа для метода scramblesuit, на случай если вы не хотите писать pre-shared key в открытом виде.
  • log_options включает в себя следующие ключи:
    • --log-file path — задает расположение журнала.
    • --log-min-severity level — События какого уровня (debug, info, warning, error) записывать.
    • --no-safe-logging — по умолчанию obfsproxy вырезает адреса из лога, но данный ключ позволяет изменить это поведение.
    • --no-log — отключает ведение журнала совсем (по умолчанию).


Сам VPN-сервер можно либо спрятать за obfsproxy полностью (заставив слушать 127.0.0.1), либо оставить его на внешнем сетевом интерфейсе на случай отказа obfsproxy. Я выбрал второй вариант как более надежный.
Таким образом, для запуска obfsproxy на серверной стороне достаточно выполнить что-то вроде:
obfsproxy --log-file /var/log/obfsproxy-openvpn.log --log-min-severity info scramblesuit --password BASE32LONGPASS --dest 1.2.3.4:1800 server 1.2.3.4:81

где 1.2.3.4 — внешний IP хоста, 1800 — порт, который слушает OpenVPN, 81 — порт, который будет слушать obfsproxy.
Серьезным недостатком является неумение obfsproxy запускаться в режиме демона, но это можно обойти.

Запуск на клиенте практически идентичен серверу:
obfsproxy scramblesuit --password BASE32LONGPASS --dest 1.2.3.4:81 {client|socks} 127.0.0.1:81

где 1.2.3.4:81 — адрес, который слушает obfsproxy-сервер, 127.0.0.1:81 — адрес, который слушает клиент.

Настройка OpenVPN


Важно: OpenVPN должен использовать протокол TCP.
Если мы используем режим client, то просто заменяем адрес удаленного сервера в конфигурационном файле openvpn на адрес локального obfsproxy:
#remote 1.2.3.4 1800 #заменяем старый адрес сервера 
remote 127.0.0.1 81 #вместо этого пытаемся подключиться к клиентской части obfsproxy

Режим socks
Для работы в режиме socks настраиваем OpenVPN немножко по-другому:
#remote 1.2.3.4 1800 #заменяем старый адрес сервера 
remote 1.2.3.4 81 #на адрес obfsproxy-сервера (важно! иначе работать не будет)
socks-proxy-retry
socks-proxy 127.0.0.1 81 #пытаемся задействовать socks proxy

Учитывая необходимость заменять адрес OpenVPN-сервера на адрес obfsproxy-сервера, я не вижу особой пользы от режима прокси — приложения, в которых адреса подключения зашиты намертво, так все равно не запроксируешь.

Если openvpn-трафик блокируется лишь иногда (например, только в рабочей сети), можно использовать следующий прием. В файле конфигурации OpenVPN запишем следующее:
<connection>
    remote 1.2.3.4 1800 #сначала пытаемся подключиться напрямую
</connection>
<connection>
    remote 127.0.0.1 81 #если не удалось, подключаемся через obfsproxy
</connection>

OpenVPN будет пытаться задействовать каждую секцию <connection> поочередно, пока не произведет успешное подключение.

Что касается запуска obfsproxy, к сожалению, сам OpenVPN не поддерживает pre-connect скрипты (запуск команды перед попыткой подключения). Вы можете попытаться установить один из неофициальных патчей, запускать obfsproxy вручную, либо воспользоваться одним из следующих методов.

openvpn-gui для Windows


Если вы используете обертку openvpn-gui для подключения вручную (или автоматически с ключом --connect), то проще всего будет создать в папке config файл XXXXXX_pre.bat, где XXXXXX — имя файла конфигурации (без расширения .ovpn). Этот файл будет автоматически выполнен перед тем как openvpn-gui попытается подключиться. Содержимое файла будет выглядеть примерно так:
start "window title" /MIN "%USERPROFILE%\Tor Browser\Tor\PluggableTransports\obfsproxy.exe" --log-min-severity info --data-dir "%TEMP%\obfs-openvpn" scramblesuit --password-file obfsproxy.key --dest 1.2.3.4:81 client 127.0.0.1:81

  • window title — заголовок окна, необходим.
  • %USERPROFILE%\Desktop\Tor Browser\Tor\PluggableTransports\obfsproxy.exe — путь к исполняемому файлу obfsproxy. По умолчанию Tor Browser ставится на рабочий стол, хотя это и не обязательно.
  • %TEMP%\obfs-openvpn — путь для размещения файлов состояния obfsproxy.
  • obfsproxy.key — путь к файлу с ключом, если вы его используете.
  • 1.2.3.4:81 — адрес, который слушает серверная часть obfsproxy.
  • 127.0.0.1:81 — адрес, который будет слушать клиентская часть.

Использование команды start (без ключа /wait она работает как аналог оператора & в shell) необходимо, так как openvpn-gui ожидает завершения pre-up скрипта перед попыткой подключения. Недостатком этого метода является консольное окно, постоянно висящее в фоне. При желании его можно спрятать утилитой hidcon или аналогичной.

obfsproxy как сервис


Если OpenVPN запускается как сервис, то имеет смысл организовать запуск obfsproxy таким же образом.
Создать сервис можно утилитой srvany от MS или какой-либо альтернативной утилитой, вроде NSSM. Вопрос запуска приложения как службы Windows выходит за рамки статьи, так что я просто укажу, что такой подход позволит задавать зависимости от и для других сервисов, тем самым гарантируя что obfsproxy будет доступен в момент запуска OpenVPN.

Этот подход можно совместить с предыдущим, используя bat-файл, запускаемый openvpn-gui, для запуска созданного сервиса командой net start.

Влияние на скорость


Последняя проверка проводилась 7 февраля 2016 посредством старого доброго speedtest.net, используя один и тот же сервер в Лондоне (OpenVPN-сервер хостится в Латвии, клиент — в европейской части России) с клиентской машины под Windows 7. Измерения производились в десятикратной повторности. Из результатов следует, что как минимум в моем случае значительного влияния на скорость obfsproxy не оказывает. Так что, если до вашего VPN-сервера хороший канал, то хуже не будет.

Режим Ping, ms Download, MB/s Upload, MB/s
direct среднее 56 20,18 21,03
коэфф. вариации 3,6% 0,6% 1,2%
openvpn среднее 56 20,21 21,29
коэфф. вариации 2,3% 1,0% 1,0%
openvpn+obfsproxy среднее 55 20,24 21,15
коэфф. вариации 4,0% 0,73% 1,34%


Запуск obfs-proxy как init.d сервиса


init.d/obfs-openvpn
#! /bin/sh
### BEGIN INIT INFO
# Provides: obfsproxy-openvpn
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: obfsproxy wrapper for openvpn
# Description: This file starts up obfsproxy configured to process obfuscated openvpn client connections.
### END INIT INFO

# Author: Vindicar <the.vindicar@gmail.com>

# Do NOT «set -e»

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin"
DESC=«obfsproxy wrapper for openvpn»
NAME=obfs-openvpn
DAEMON="/usr/local/bin/obfsproxy"

OBFSPROXY_KEYFILE="/etc/obfsproxy-openvpn.key"
SERVER_IP=?.?.?.? #<<< TODO: insert server address here
OPENVPN_PORT=443 #port 443 due to use of sslh
OBFSPROXY_PORT=81

DAEMON_ARGS="--log-file /var/log/obfs-openvpn.log --log-min-severity warning \
--data-dir /tmp/obfs-openvpn \
scramblesuit --password-file $OBFSPROXY_KEYFILE \
--dest $SERVER_IP:$OPENVPN_PORT server $SERVER_IP:$OBFSPROXY_PORT"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] &&. /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --background --quiet --make-pidfile --pidfile $PIDFILE --exec $DAEMON — \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
# EDIT: removed --name parameter since s-s-d matches it against process name which is 'python'
# will be relying on the pidfile to stop it.
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
#start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
#[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE
return 0
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg «Starting $DESC» "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg «Stopping $DESC» "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg «Reloading $DESC» "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the «reload» option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg «Restarting $DESC» "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo «Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}» >&2
echo «Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}» >&2
exit 3
;;
esac
@Vindicar
карма
7,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (31)

  • +3
    OpenVPN на TCP 443 c TLS.
    • +1
      По умолчанию да, но это уже смотря как настроить. Особенно если на том же хосте размещен сайт с HTTPS.
      Конечно, можно поставить мультиплексор вроде sslh, но зачем?
      • +6
        Можно использовать встроенный в openvpn (опция port-share) для проскирования не openvpn трафика на 443 порт на веб-сервер.
        • 0
          Есть еще очень классная штука под названием sslh. Умеет на одном 443 порту держать HTTPS, SSH, OpenVPN, XMPP и еще кучу сервисов. Для нагруженых серверов конечно не годится, но если HTTPS используется, скажем, для вебморды к личной почте, то очень даже ничего.
          • 0
            Есть у неё один солидный недостаток: все подключения будут с 127.0.0.1, а для понимания кто есть кто надо парсить лог утилиты. Есть какой-то патч, который позволяет sslh перенаправлять пакеты целиком, но я так и не разобрался как им воспользоваться.
    • +3
      Хендшейк у опенвпна «особенный», что позволяет легко его зафингерпринтить, с чем успешно справляется великий китайский (для тех кто не понял — опенвпном в Китае пользоваться не получится)
      • +1
        Эти сказки про всесильность китайского фаервола давно и безуспешно пытаются стать былью. В тред приглашается Sakuya, которая, возможно, из первых рук прокомментирует как там у них. Ну или может кто еще, кто расскажет не по статьям-страшилкам, а с той стороны огненной стены.
        • +1
          Это вполне себе реальность, просто не во всех районах Китая, и не всегда.
          Сильно зависит от политических событий в Китае.
          Вон, перед годовщинами событий Тяньаньмэнь в некоторых районах интернет превращается в тыкву.
        • +1
          Ну всесильность всесильностью, но упомянутый мной выше sslh справляется с задачей отличения по хэндшейку openvpn от https/ssh на ура — значит, и любой стоящий DPI-пакет сможет. Другое дело что не все VPN соединения одинаково вредны, так что едва ли протокол запретят целиком, но вот какие-нибудь лицензии ввести, да и просто попортить кровь урезанием скорости могут.
        • 0
          А че не сказки, стена режет например здесь «чистый openvpn» не работает, пробовал разные вариации.Места серверов были разные.

          В разные моменты просто есть сезонные обострения, это как правило сентябрь и октябрь, перед съездом партии интернет тупо умирает.

          PPTP трафик давно режется.
          Например провайдер China Telecom откинул всех за нат, реальных айпи адресов для ADSL Больше нет…
        • +3
          Нет, это, к сожалению, не сказки. Работает IPsec и решения вроде Psiphon, но не OpenVPN с TLS.
  • +1
    А для людей, которые вообще не имели дел с серверами, VPS и VPN — на всякий случай (в связи с наметившимися тенденциями), с чего нужно начинать?
    Сколько такая услуга (VPS) стоит? Можно ли совместить это с обычным хостингом сайта?
    • 0
      VPS (virtual private server) — стоит очень по разному, в зависимости от задач. Для этой обычно хватает и минимального плана.
      Я в таких случаях ориентируюсь на этот каталог. Правда, нужно быть осторожным: самый дешевый VPS-хостинг я находил у GreenValueHost ($9 в год), но это был клинический случай «за что заплатили, то и получили» — у меня за пол года так и не получилось проработать дольше двух недель без обращения в техподдержку.
      Общие советы простые: ищите предложения с внешним IPv4, большим объемом месячного трафика и поближе к вам (чтобы пинг не сильно поднимался), но, само собой, за рубежом. Требования по памяти и CPU у VPN-решений обычно сравнительно невелики.

      Совместить с хостингом возможно в том плане что на рынке есть VPS, заточенные именно под хостинг. Туда вполне возможно вкрячить нужный софт, хотя я бы не стал так делать с любым сколь-нибудь важным проектом. Небольшая машинка «для экспериментов» для таких целей и то предпочтительнее (если, конечно, VPN организуется для себя).
    • 0
      Здесь часто бывают интересные акции www.lowendtalk.com/categories/offers Бывают вплоть до KVM VPS 256MB за 3$ в год (nexhost.net такое раздавал).
      • 0
        А как у KVM c пропусканием l2tp+ipsec в случае, когда нельзя менять настройки хостовой машины? OpenVPN не всегда удобен, а на OpenVZ у меня понадобилось таки менять настройки хоста, что в случае с VPS почти нереально.
        • 0
          А что значит менять настройки хостовой машины? На KVM я допустим могу поставить любой линукс какой хочу (и Win тоже, но этим не занимался), просто кидаю ссылку на образ дистрибутива суппортам, они добавляют мне этот iso в список доступных, далее просто гружусь с iso и ставлю систему с нуля (через VNC). OpenVZ я не люблю, лучше чуть доплатить и иметь больше свободы.
        • +1
          OpenVZ — контейнер ОС GNU/Linux. KVM — полноценная виртуальная машина.

          Возможности L2TP+IPsec требуются настолько редко, что вопросы по его использованию лично у меня вызывают удивление: зачем городить велосипед L2, неужели в туннеле Вам нужен ARP и прочие пакеты канального уровня? Если уж заморачиваться с IPsec, tunnel mode несколько проще.
          • +1
            Вот, вменяемый человек!
            habrahabr.ru/post/250859/
            • 0
              Ту статью я читал, понравилась. И я (в который раз) забыл упомянуть, что L2TP+IPsec использует транспортный режим IPsec и не прячет адреса IP, а в туннельном режиме они спрятаны.

              Но к топику IPsec никак не применим: он не работает через Socks. Разве что использовать туннель IP-over-TCP, но тогда можно и IP-over-ICMP :)
  • 0
    Эмм, это всё только для того, чтобы SOCKS организовать?
    Куда проще в putty перед подключением к серверу добавить порт для проброса. Как результат получаем сокс-прокси на своем локалхосте, который трафик через наш vps отправит.
    • 0
      Эм, вопрос «для чего будет использоваться этот VPN» немного выходит за рамки статьи. Скажу лишь что прокси дело не ограничивается. =)

      В простых случаях можно, конечно, обойтись и ssh port forwarding. Я так и делал поначалу. Вот только:
      1. он не позволяет задать шлюз по умолчанию (завернув вообще весь трафик через туннель, а не только проксируемый).
      2. в этом случае несколько сложнее подменить DNS сервер, а то некоторые провайдеры имеют милую привычку весь трафик по UDP:53 принудительно заворачивать на свои DNS сервера.
      3. ну и посыл статьи в том, что obfsproxy можно использовать отдельно от сети Tor для маскировки любого трафика (особенно в режиме client). Хотите — заворачивайте ваш SSH в него, сработает не хуже.
      • 0
        думаю bondbig имеет ввиду гонять openvpn через ssh-туннель.

        т.е. использовать ssh как сокс-прокси вместо obfsproxy, тогда снаружи не видно будет openvpn, только ssh.
        • 0
          Нет, я имел в виду, что если нужно обойти фильтры и не палиться с openvpn, то покупаем vps, настраивает стандартно nat и подключаемся к серверу при помощи putty/любого другого ssh-клиента, пробрасываем порт и получаем socks-прокси, который слушает у нас на десктопе на локалхосте (например 127.0.0.1:3333), а вторым концом выходит на vps. Прописываем в браузере настройки socks и ходим через VPS безо всякого дополнительного софта типа obfsproxy, Tor-нод, openvpn и т.п.
          Да, не все программы умеют socks, но это уже совсем другая история, верно?
          • 0
            Я так и понял. И даже поначалу так и делал. Вот только когда количество пробрасываемых портов приблизилось к полудюжине (прокси-порт Tor-ноды, BTSync web-ui, ну и так далее, и не все можно запроксировать), то захотелось какого-то более кардинального решения. OpenVPN в этом плане оказался удобнее, особенно благодаря умению работать сервисом «из коробки».
            Хотя настройки для SSH-туннеля остались. А до машины, помимо прямого ssh соединения и VPN/obfsproxy, можно достучаться еще и через Tor hidden service. А может, даже iodine заморочусь, просто по принципу «хоть что-то да сработает».
            • +3
              Тогда уже проще переехать с openvpn на SoftEther (к тому же он поддерживает простую миграцию с openvpn).
              Его способ установки туннеля не отличается от стандартного HTTP CONNECT и, соответственно, не детектируется, в отличии от openvpn.
              • 0
                А вот это уже интереснее, спасибо! Если список фич не врет, оно умеет работать с родными Win/Android/etc клиентами, что было бы замечательно.
                • 0
                  С родными может по стандартному l2tp, да. Естественно, в этом случае никакой мимикрии под https не будет.
                • 0
                  Softether клиент для винды есть родной,
                  для андроида — нету.
                  Зато для андроида есть SSTP-клиент. И Softether-сервер также умеет SSTP-сервер.
  • 0
    По поводу чего-то, что «не работает в режиме демона» — напишите upstart-скрипт!
    Мы когда на него напоролись, делали обратную задачу — выпиливали собственный режим демона, покуда с upstart получалась ненужная интерференция.
    • 0
      Ну сейчас obfsproxy у меня и стартует из init.d с помощью start-stop-daemon. Спасибо s-s-d за ключ --background. =)
      Единственный минус — PID-файл не создаёт почему-то, хотя ключ указал.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.