14 October 2010

Перехват и редактирование файлов http-трафика на примере торрента

System administration
From Sandbox
Пару лет назад возникла идея сделать локальный bittorrent-ретрекер для пользователей нашей «домашней» городской сети, чтобы и пользователи быстрее скачивали и у нас меньше трафика было. Установкой самого ретрекера дело только начиналось, необходимо было как-то анонсировать его для скачиваемых торрентов. В процессе выяснения способов и механизмов анонса я пришёл к достаточно общему и универсальному алгоритму, с которым и предлагаю познакомиться.

Итак, первое:

Что делать


Существуют три способа обьявить о существовании трекера в локальной сети:
  • Использовать добавляемыми некоторыми трекерами адрес retracker.local
  • Анонсировать локальный трекер посредством механизма isp.bep22
  • Перехватывать скачиваемые торрент-файлы и редактировать их, добавляя адрес нашего торрента, «на лету»

Каждый из них имеет свои преимущества и недостатки, соответственно:
  • Использование зоны .local противоречит черновику RFC «Multicast DNS» и вызывает проблемы в работе zeroconf-сервисов Linux и Apple; добавляется лишь немногими трекерами
  • Isp.bep22 работает, насколько мне известно, лишь в клиенте µTorrent и то выключен по умолчанию
  • О перехвате трафика нет никаких упоминаний с success stories, за исключением единственного опыта дружественной сети

Для начала сделали поддержку первых двух вариантов, благо никаких особых усилий для этого не требовалось: добавить в DNS несколько записей (retracker.local IN A и retracker.smarthome.spb.ru _SRV_) просто. На несовместимость .local с zeroconf в данном случае можно закрыть глаза, поскольку в идеале DNS-запросы клиента с включенным zeroconf даже не должны доходить до нашего сервера. Update: Важная ремарка cadmi — для работоспособности .local у пользователя и нашего ретрекера нужно создавать зону не .local, а .retracker.local, что как раз и позволит совместить оба варианта.

Но всё же наиболее интересным и заманчивым выглядел третий вариант, так что я решил поискать информацию об общей технике изменения скачиваемых файлов на лету. Требования к серверу были просты:
  • Работа во FreeBSD
  • Open-source
  • Прозрачность (незаметность) работы для клиента
  • Определение трафика 7 уровня и восстановление файлов из http-потока
  • Передача этих файлов редактирующему скрипту и получение их обратно
  • Передача отредактированных файлов клиенту


Чем делать


К своему удивлению я обнаружил, что техник и open-source программ для такого перехвата и редактирования файлов практически нет. По большому счёту, их всего две: это Squid с экспериментальными модулями ICAP/ECAP и некий фильтрующий прокси под названием "MiddleMan", последний релиз которого вышел в далёком 2004 году, но который продолжает поддерживаться в портах.

От использований Squid я отказался практически сразу: несмотря на наличие сразу двух экспериментальных модулей для работы с проходящим трафиком, решение оказалось чрезвычайно «кривым» и неустойчивым даже в установке и настройке, не говоря уж о работе.

Перешёл к middleman. Поразительно, но факт — старая программа оказалась функциональней и удобней современного монстра Squid. В сущности, он удовлетворяет всем требованиям, кроме полной прозрачности для пользователя — source ip пользователя переписывается на ip сервера с прокси. Замечу, что возможность оставлять source ip есть только у Squid с модулем TPROXY под Linux. Более того, у него есть уникальная опция — при превышении настраиваемого таймаута ожидания прокси отдаёт пользователю неизменённый исходный файл.

Как делать


1. Определение самых популярных торрент-серверов

Для начала я написал небольшой perl'овый скрипт, который через pcap слушает 80 порт и собирает ip-адреса, на которые идут запросы с «Content-Type: application/x-bittorrent». Нужно это для того, чтобы перехватывать не весь http-трафик, а только тот, который принадлежит крупным трекерам.

Затем путём нехитрых манипуляций эти ip-адреса заносятся в таблицу ipfw, используемую при перенаправлении на наш прокси:

${ipfw} add fwd ${proxy_ip}, ${proxy_port} tcp from $lan_customers to 'table(15)' dst-port 80 in via ${int_if}

2. Конфигурация прокси-сервера middleman
Секция, ответственная за отдачу файлов редактирующему скрипту, называется external в mman.xml.

3. Редактирующий «внешний» скрипт


Скрипту mypatcher.pl передаются файлы с mime-типом «application/x-bittorrent», он добавляет в него запись локального трекера (убирая при этом retracker.local, если он там есть, что решает проблемы клиентов с zeroconf) и передаёт содержимое обратно прокси, попутно сохраняя файл ещё и на диск, в таком виде:

#for i in `find /home/torrents/patched/ -type d`; do echo -n "$i" && ls -1 $i| wc -l; done | awk '{print $2" "$1}' | sort -rn | head -n 10

24103 /home/torrents/patched/dl.rutracker.org
7817 /home/torrents/patched/dl.torrents.ru
6184 /home/torrents/patched/tfile.ru
3744 /home/torrents/patched/kinozal.tv
2928 /home/torrents/patched/rutor.org
2872 /home/torrents/patched/torrents.thepiratebay.org
2583 /home/torrents/patched/www.tfile.ru
2582 /home/torrents/patched/www.torrentino.ru
2531 /home/torrents/patched/pornolab.net
1032 /home/torrents/patched/www.rutor.org


Итог работы: на сервере, который выполняет NAT, шейпинг и роутинг сети из 3000 пользователей, загрузка mman вообще не ощутима. В день сейчас таким образом редактируется порядка 200-400 файлов. Нареканий за почти год работы не было, все довольны.

Update 1. «Сохранение файлов на диск» служит исключительно для сбора обезличенной статистики в виде, указанном выше. Ну и попросту я забыл отключить этот механизм отладки скрипта. :) Cadm
Tags: bittorrent isp patcher proxy middleman
Hubs: System administration
+110
10k 115
Comments 104
Ads