Обход блокировок, анонимность или как я свою проксю писал
Привет Хабр! Это моя первая статья и в ней я хотел бы поделиться одним интересным проектом, но сначала небольшая предыстория.
Всё началось с того, что у меня перестал работать тор. Вот прям совсем. Я сначала подумал что это очередная блокировка моста или какой-то сбой, но нет. после пары дней попыток и экспериментов я обнаружил что он не работает повсеместно в сети моего провайдера. Я в полной уверенности что такую махину как тор нереально заблокировать начал искать в чем же проблема и как оказалось я не один столкнулся с этим.
Я начал изучать что да как и меня это довольно сильно увлекло. В тот момент я работал над проектом в котором без прокси ну никак не обойтись и тут меня осенило - почему бы не написать приблуду, чтобы всё и сразу. В общем, свой тор с бэкендом и шлюзами.
Ближе к делу
Детально изучив механизм работы тор и проштудировав пару десятков статей я сел за работу... А в прочем это совсем другая история. Это обзор результата, а процесс создания сего чуда - тема для отдельной статьи (намёк вы поняли).
После пары недель проб и ошибок моё детище наконец-то было готово. Я бы сказал что получилось мягко говоря... интересно.
Основным отличием от того же Тора было то, что для каждого подключения (сокета) создавался новый туннель. Затратно? с одной стороны да, но оптимизация берёт своё. Плюс небольшой финт ушами позволил добиться в определённых случаях даже большей производительность чем обычный http-прокси. А самое весёлое что написано всё на Python. Да да, на том самом гибриде улитки и змеи. Он по прежнему занимает особое место в моём сердечке, да и на самом деле, если верить нагрузочным тестам, то он неплохо справляется с поставленной задачей. Впрочем я далеко ушел.
Использование этого инструмента подразумевает создание сети из одной или более ноды, через которые туннелируется весь трафик. сами идею с такой структурой сети я позаимствовал у одной известной луковицы. Можете почитать об этом если вам интересно. Я же просто скажу что в отличае от тор в моей сети может быть неограниченное количество промежуточных точек, а все служебные данные шифруются с помощью написанного на коленке протокола RecRoll.
И так, давайте же пощупаем наконец сам проект.
Практическая часть
Проект можно найти на гите. Или установив пакет через pip.
Я собственно воспользуюсь пипом.
pip install NREP
После установки создаём папку проекта и берём стандартный "маяк" из примеров проекта.
from NREP.beacon import Beacon
from NREP.utils.spec import Config
config = Config('beacon_config.json')
node = Beacon(config)
Создаём файл beacon_config.json и кладём туда следующее:
{
"location": "asshole",
"host": "",
"port": 80,
"nodelist": "nodes.json"
}
чтобы запустить на локалхосте, оставим поле host пустым
Создаём nodes.json. Это список (листинг) всех доступных нод.
{
"RU": {
"REGION1": {
"node1": {
"host": "localhost",
"port": "5689",
"publickey": "-----BEGIN RSA PUBLIC KEY-----\nMEgCQQCsZGoibHma36u1koAw82g6xyqQlPdOuedBehc0xLhzJlh5yqc31pwotrYD\n42fZWua+OUGPjOFiDHpnCYw0jHTvAgMBAAE=\n-----END RSA PUBLIC KEY-----\n"
}
}
}
}
Ах да, чуть не забыл. генерируем пару aes ключей и кладём паблик в конфиг ноды (в маяке). Очень муторно, но уже скоро появится автолистинг и вам не придётся так извращаться с настройками. Для ленивых на гите есть готовый маяк, просто покрутите конфиги.
Готово, теперь осталось собрать ноду и мост.
Здесь думаю пришло время сделать небольшое отступление и объяснить какого черта мы делаем.
Как я уже говорил основу сети составляют ноды, но так же есть и маяки. Они нужны для того, чтобы сообщить пользователю через что он может проложить "трубу". а мосты здесь, в отличие от тора нужны для трансляции из различных протоколов к nrep/recroll. Пока есть только http2nrep.
Вернёмся к вакханалии с настройкой сетевого окружения.
Создаём node.py
from NREP.node import Node
from NREP.utils.spec import Config
config = Config('config.json')
node = Node(config)
И конфиг к нему
{
"location": "asshole",
"max_connections": 100,
"host": "",
"port": 5689,
"clean_interval": 0.1,
"privatekey": "-----BEGIN RSA PRIVATE KEY-----\nMIIBPgIBAAJBAKxkaiJseZrfq7WSgDDzaDrHKpCU906550F6FzTEuHMmWHnKpzfW\nnCi2tgPjZ9la5r45QY+M4WIMemcJjDSMdO8CAwEAAQJBAKWEJ67zbXI4bHmBtljJ\navp8PS7iB+xra1Cfc2ZztVcqs8p+fhWKeMSbsQZ9MG2PoFZ7aJifq7Cq9zUAmmPN\nWJkCIwDBS/NZiv7PUFRX/3zjFUUB5dwG9HHY3xvDw+JBkCKF9izlAh8A5FB8DQfo\nU8RXlhKv0FjE2bFE5ibFmC+rGHrk3ZFDAiMAsyOxbv37MqTO1hMIaefvYVfmt2da\nD1SOBbsHeB2dcSt55QIfAL9OeUNp9tAJ2uIS8mJ/nyJRmUvH/RWSC6lNgGvvhQIi\nDuryDswMdPn5jm2LaLDqg/rzyGNfx5DsuuByZbUUWttTCQ==\n-----END RSA PRIVATE KEY-----\n"
}
Кидаем сюда приватный ключ rsa, сгенерированный нами ранее. Из параметров, можно отметить max_connections - максимальное количество труб, и clean_interval - время очистки пула труб в секундах. Порт смысла трогать нет, а вот хост пишите тот, на котором поднимаете ноду. Не забудьте и в маяке его прописать.
С мостом всё куда проще, просто тянем его из пакета.
from NREP.bridge.http2nrep import Bridge
Bridge("127.0.0.1", 8080)
Вот и всё. Маяк запускаете на локальной машине, а за ним и мост. Именно в таком порядке. Мост кэширует конфиг из маяка и запускает http/https proxy. У меня лично винда, я прописываю его настройках. После запускаем ноду на удаленной/локальной машине.
Можно приступать к тестированию. Теперь каждое новое подключение будет проходить через наш импровизированный прокси. Запускаем спид-тест из примеров и нет, я не буду его сюда писать)) Получаем следующие результаты:
With NREP (no piping): 0.7313602799999999s
With NREP (piping): 0.24336806599999947s
Without NREP (first request): 0.7303720800000001s
Without NREP (second request): 0.2465090479999998s
NREP is 0.1 % slower
NREP (piping) is 1.3 % faster
Довольно неплохие результаты, учитывая что это avg из 50 тестов.
Подводя итоги могу сказать что эксперимент удался. Оно даже тянет ютуб в 4К) Но есть над чем поработать. Надеюсь, проект будет вам полезен. Планирую и дальше его развивать, так что присоединяйтесь.
Благодарю, что дочитали до конца. Спасибо всем. Надеюсь на вашу поддержку и не судите слишком строго. Это как ни как мой первый пост.