Этот репозиторий содержит клиент и сервер, которые позволяют туннелировать трафик TCP и UDP через другие сетевые протоколы.
На данный момент поддерживаются следующие туннели:
Основной инструмент написан на Rust, а сквозные тесты — на Python.
docker pull ghcr.io/dlemel8/tunneler-server:latest
docker pull ghcr.io/dlemel8/tunneler-client:latest
cargo --version || curl --proto ' =https ' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release
Существует также файл докера, если вы предпочитаете создать локальный образ докера.
docker run -e LOCAL_PORT=45301
-e REMOTE_PORT=5201
-e REMOTE_ADDRESS=localhost
-e TUNNELED_TYPE=udp
--rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp
./target/release/client
--tunneled-type tcp
--remote-address 1.1.1.1
--remote-port 53
--log-level debug
dns
--read-timeout-in-milliseconds 100
--idle-client-timeout-in-milliseconds 30000
Запустите образ Docker или скомпилированный двоичный файл с помощью --help
для получения дополнительной информации.
cargo test --all-targets
python3 -m pip install -r e2e_tests/requirements.txt
PYTHONPATH=. python3 -m pytest -v
Этот репозиторий содержит несколько примеров развертывания серверов с использованием Docker Compose:
Вы можете запустить каждый пример локально или развернуть его с помощью Terraform и Ansible. Дополнительную информацию см. здесь.
Каждый исполняемый файл содержит два компонента, взаимодействующих через канал клиентских потоков (кортеж чтения и записи байтов):
Трафик на основе TCP тривиально преобразуется в поток. Преобразование трафика на основе UDP зависит от протокола туннеля.
Для трафика на основе UDP также необходим способ идентификации существующих клиентов для продолжения их сеансов. Решением является кэш клиентов в памяти, который сопоставляет идентификатор клиента с его потоком.
Чтобы преобразовать UDP-трафик в поток, перед каждой полезной нагрузкой пакета стоит заголовок размером 2 байта (с прямым порядком байтов).
Прослушиватель UDP использует адрес узла входящего пакета в качестве ключа к своему клиентскому кэшу.
Здесь у нас есть несколько проблем:
Чтобы решить эти проблемы, каждый сеанс клиента начинается с генерации случайного идентификатора клиента (4 буквенно-цифровых символа). Клиент считывает данные для туннелирования и запускает их через конвейер кодировщиков:
Закодированные данные затем используются в качестве имени DNS-запроса TXT.
Если у вас есть авторитетный DNS-сервер, клиент может отправить запрос рекурсивному преобразователю DNS. Resolver получит ваш IP-адрес от регистратора вашего доменного имени и перенаправит запрос на ваш IP-адрес. Другой вариант (более быстрый, но более очевидный для любого анализатора трафика) — настроить клиента для отправки запроса непосредственно на ваш IP (на порт UDP/53 или любой другой порт, который прослушивает сервер).
Сервер декодирует данные (игнорируя любой неклиентский трафик) и использует идентификатор клиента в качестве ключа к своему кэшу клиентов.
Для обработки больших ответов сервера и пустых TCP ACK тайм-аут чтения используется как на клиенте, так и на сервере. Если таймаут чтения истек, будет отправлено пустое сообщение. И клиент, и сервер используют тайм-аут простоя, чтобы остановить пересылку и очистку локальных ресурсов.
Для реализации взаимной аутентификации мы используем частный центр сертификации:
И клиент, и сервер настроены на использование своего ключа и сертификата при подтверждении TLS. Сертификат CA используется в качестве корневого сертификата.
Поскольку используется расширение указания имени сервера, клиент запрашивает определенное имя сервера, а сервер выдает свой сертификат только в том случае, если это имя было запрошено. Имя сервера также должно быть частью сертификата, например, как альтернативное имя субъекта.