Обходим блокировки с помощью ICMP-туннеля

30 августа 2023

Введение:

  • в августе 2023 года суверенный российский интернет покорил новую вершину — зарубежные ресурсы впервые начали блокироваться не только по IP-адресам и DNS-именам, но и по сигнатурам используемых протоколов,
  • главной жертвой оказались протоколы, используемые в том числе (но не только и не столько) для обхода блокировок — например, OpenVPN, WireGuard и IPSec,
  • в этих условиях IT-специалистам, продолжающим работать из России с зарубежными ресурсами, жизненно необходимы инструменты, обеспечивающие устойчивую связь по мере нарастания ограничений.

Какими должны быть эти инструменты?

  • не массовыми — чем популярнее сервис, утилита или протокол, тем вероятнее они попадут под блокировку,
  • разнотипными — чтобы не попасть под сигнатурную блокировку всем одновременно,
  • размещёнными у разных провайдеров, в разных странах, на разных доменах — чтобы не попасть под одновременную блокировку по IP или DNS,
  • необязательно быстрыми — лучше иметь работающий SSH со скоростью модема, чем полностью остаться без связи с внешним миром.

Попробуем туннелировать через ICMP:

  • этот способ малоизвестен и непопулярен,
  • он медленный — а значит, лишён риска стать популярным даже в том случае, если все прочие станут жертвами блокировок,
  • скорее всего, на ТСПУ несложно обнаружить такой туннель — например, по непрерывному потоку ICMP-пакетов большого размера между двумя узлами — но низкая популярность повышает шанс на то, что блокировки по такой сигнатуре будут внедрены не слишком скоро,
  • изначально протокол ICMP разработан для сетевой диагностики и используется утилитами ping, mtr, tracert и т.д. — благодаря этому его привыкли воспринимать как сугубо вспомогательный и крайне редко принимают во внимание возможность передавать данные с его помощью.

Окно возможностей:

  • не имеет смысла делать ICMP-туннель основным инструментом — лучше держать его про запас до тех пор, пока более быстрые, привычные и функциональные альтернативы не окажутся под запретом,
  • в свою очередь, нельзя полагаться на то, что ICMP минует общая участь — для него так же следует иметь запасной вариант,
  • например, таким вариантом может быть туннелирование через DNS с помощью iodine — соответствующую инструкцию уважаемый amarao-san любезно предоставил сообществу 10 лет назад.

Исходные данные:

  • IP-адрес сервера = 1.2.3.4
  • сеть для туннеля = 10.1.2.0/24
  • ключ шифрования, общий для сервера и клиентов = ОЧЕНЬ_СЕКРЕТНАЯ_СТРОКА

Общие сведения:

  • приложение для организации ICMP-туннеля состоит из одного исполняемого файла,
  • один и тот же файл используется и на стороне сервера, и на стороне клиента,
  • сервер может работать только под Линуксом,
  • клиента можно собрать для Linux, Windows, MacOS и FreeBSD,
  • на Github'e доступны два варианта — старый скомпилированный (для Ubuntu и MacOS) и новый в исходных текстах.

Скачиваем готовый бинарник для Ubuntu:

  • wget -O /usr/local/sbin/hans https://github.com/albertzak/hanstunnel/raw/master/bin/hans-ubuntu
  • chmod +x /usr/local/sbin/hans

Или собираем более свежую версию из исходных текстов:

  • apt install git make gcc g++
  • git clone https://github.com/friedrich/hans.git
  • cd hans
  • make
  • sudo install hans /usr/local/sbin/

Настраиваем автозапуск сервера:

  • создаём /etc/systemd/system/icmptunnel.service
  • systemctl daemon-reload
  • systemctl enable --now icmptunnel
  • journalctl -xeu icmptunnel

Содержимое icmptunnel.service:

[Unit]
Description = ICMP tunnel
Docs  = https://cdnnow.ru/blog/icmp-tunnel/
After = network-online.target
Wants = network-online.target

[Service]
ExecStartPre = /bin/sh -c 'echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all'
ExecStart    = /usr/local/sbin/hans -s 10.1.2.0 -r -p ОЧЕНЬ_СЕКРЕТНАЯ_СТРОКА -u nobody -f -v
ExecStopPost = /bin/sh -c 'echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all'
Restart      = on-failure

[Install]
WantedBy = multi-user.target

Настраиваем клиента:

  • создаём /sbin/ifconfig
  • делаем его исполняемым: chmod +x /sbin/ifconfig

Содержимое /sbin/ifconfig:

#!/bin/sh

case "$2" in
   mtu    ) ip link set "$1" mtu "$3" ;;
   [1-9]* ) ip addr add "$2/24" dev "$1" && ip link set "$1" up ;;
   *      ) echo "Bad params" ;;
esac

Зачем он нужен?

  • hans вызывает /sbin/ifconfig после установки соединения — для настройки туннельного MTU и IP-адреса,
  • в современных Линуксах утилиты ifconfig, netstat и route из пакета net-tools по умолчанию не устанавливаются — их заменила утилита ip из пакета iproute2,
  • поэтому место в каталоге /sbin, принадлежащее древней общесистемной утилите, теперь вакантно, и мы можем поместить вместо неё наш самодельный суперкостыль без риска повредить систему,
  • тем не менее, мы подготовили для hans замену вызова /sbin/ifconfig на /sbin/ip и ждём его принятия в upstream: https://github.com/friedrich/hans/pull/25.

Запускаем клиента:

  • sudo hans -c 1.2.3.4 -p ОЧЕНЬ_СЕКРЕТНАЯ_СТРОКА -u nobody -f -v

Проверяем на клиенте состояние туннеля (в отдельной консоли):

  • ip addr list dev tun0
  • ip route list dev tun0

Проверяем на клиенте доступ к серверу через туннель:

  • ping 10.1.2.1
  • ssh 10.1.2.1


← Назад в Блог

Подпишитесь на новые статьи: