Перехоплення та редагування файлів http-трафіку на прикладі торрента
Кілька років тому виникла ідея зробити локальний 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
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