Общество

[Перевод] PPP-over-HTTP/2: развлекаемся с dumbproxy и pppd

Краткое резюме

Автор статьи модифицировал прокси-сервер dumbproxy, добавив возможность запуска как подпроцесса и передачи данных через stdin/stdout. Цель — экспериментальная реализация передачи PPP через HTTP/2.

Для личных нужд я применяю несколько копий dumbproxy — простого, но весьма универсального прокси-сервера. Недавно я добавил в него новый режим работы: теперь можно запускать dumbproxy как подпроцесс и передавать данные через stdin/stdout, не дожидаясь соединения на порту. Это удобно для использования в качестве ProxyCommand для клиента OpenSSH. Но главное — это подтолкнуло меня к идее, что я всего в одном шаге от реализации давно задуманного: передачи PPP через HTTP/2! Dumbproxy уже обладает защитой соединения с помощью TLS, гибкой аутентификацией, опциональной защитой от активного зондирования и хорошей устойчивостью к фильтрации протокола. Было бы полезно интегрировать эти преимущества с известными протоколами частных сетей. Мне захотелось поэкспериментировать с PPP и отдать дань одному из самых старых фундаментальных туннельных протоколов. Ведь так интересно соединить сетевой протокол эпохи dial-up с современным HTTP/2! ### Исходная конфигурация Я буду использовать простейшую конфигурацию dumbproxy на своём сервере, которая описана здесь и имеет несколько дополнений: * кэш сертификатов хранится в общем Redis, чтобы сделать экземпляры серверов полностью статичными; * несколько доменов фильтруются скриптом на JavaScript; * домен .onion перенаправляется в демон Tor. В целом, это обычный форвард-прокси с автоматическими сертификатами от LetsEncrypt и локальной базой паролей в файле. Кстати, есть готовая спецификация cloud-init для быстрой настройки сервера при его создании в облаке. ### Настройка сервера Рассмотрим скрипт перенаправления на JavaScript (опция -js-proxy-router). У меня он выглядит так: ``` /etc/dumbproxy-route.js: function getProxy(req, dst, username) { if (dst.originalHost.replace(/\.$/, "").toLowerCase().endsWith(".onion")) { return "socks5://127.0.0.1:9050" } return "" } ``` Здесь уже есть одно правило, не относящееся к текущей задаче. Добавим новое, чтобы определённый адрес перенаправлять в подпроцесс pppd с нужным файлом опций: ``` /etc/dumbproxy-route.js: function getProxy(req, dst, username) { if (dst.originalHost.replace(/\.$/, "").toLowerCase().endsWith(".onion")) { return "socks5://127.0.0.1:9050" } if (dst.originalHost.toLowerCase() == "pppd") { return "cmd://?cmd=pppd&arg=file&arg=/etc/ppp/options.vpn" } return "" } ``` Установите pppd — он есть в пакете ppp практически во всех дистрибутивах Linux: ``` apt install ppp ``` Параметры pppd будут такими: ``` /etc/ppp/options.vpn: nodetach notty noauth 172.22.255.1:172.22.255.2 ms-dns 1.1.1.1 ms-dns 8.8.8.8 ``` Этого достаточно для установления туннеля. Однако, чтобы трафик действительно пересылался, нужно кое-что ещё. Включите пересылку IP-пакетов: ``` echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf && sysctl -p ``` Добавьте правило трансляции исходящего адреса в iptables: ``` iptables -t nat -I POSTROUTING -o $(ip route show default | head -1 | grep -Po '(?<=dev\s)\s*\S+') -j MASQUERADE iptables -t mangle -I FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu ```

Фильтры и сортировка