Prosty tracker BitTorrent
Od paru dni (znów) mam konto shellowe, tym razem na innocence.pl. Nie jest może jakieś super-wypasione, ale jak na swoją cenę (35zł/miesiąc) nie jest też takie złe.
Shella fajnie mieć, można nabić sobie naprawdę dużo uploadu na popularnych wstawkach a potem spokojnie ściągać co się chce. Jedyne czego nie lubię to korzystania z FTP, niby jest dużo różnych programów ale jakoś nie lubię tak ściągać dużych plików. Fajnie byłoby korzystać po prostu z uTorrenta (lub innego dowolnego klienta torrent). Można dodać plik .torrent który pobraliśmy z trackera do lokalnego klienta ale to trochę bez sensu - download naliczony będzie podwójnie. Głupim pomysłem jest też wrzucanie go na jakiś publiczny serwer - jeśli podmienimy adres trackera to i tak mnóstwo osób będzie korzystać z naszego shella, jeśli go nie podmienimy to prawdopodobnie dostaniemy bana.
Na szczęście jest jeszcze jedna opcja - można uruchomić własny tracker i używać go do wymiany plików jedynie między shellem a naszym PC. Napisanie takiego skryptu jest w miarę łatwe, kod jest prosty i będzie wykonywany tylko kilka razy w ciągu godziny więc w żaden sposób nie obciąży serwera. Przykładowy kod jest poniżej, na tej stronie można poczytać specyfikację protokołu BitTorrent i samemu coś stworzyć.
Pozostaje jeszcze tylko jedna kwestia - tworzenie pliku torrent. Nie ma sensu na nowo hashować plików, wystarczy podmienić adres trackera i nazwę jednego z plików/katalogu. Do obu czynności przyda się hexedytor (chociaż pewnie istnieją jakieś programy które umożliwiają łatwą podmianę tych danych).
Na początku musimy znaleźć oryginalny adres trackera, powinien być gdzieś na początku pliku i wyglądać jakoś tak: "79:http://tracker.page.org/announce.php?passkey=1234567890123456789012345678901234". Liczba na początku to długość ciągu z adresem, podmieniając URL należy pamiętać też o zmianie długości na odpowiednią. Podmieniamy znaleziony adres na np. coś takiego: "27:http://moja.strona.pl/a.php", a.php to oczywiście skrypt z trackerem.
Podmiana nazwy jednego z plików przyda się, żeby zmienić info_hash torrenta - to m.in. nazw plików. Dzięki zmianie klient będzie "wiedział", żeby wysyłając plik do nas nie naliczać uploadu na trackerze. Lista plików powinna być na początku pliku, najlepiej zmienić po prostu jeden znak w nazwie sampla/pliku nfo/pliku z sumami kontrolnymi.
Po zmianie wystarczy zapisać plik, przesłać na shella (niestety, w ten sposób 'zje' nam jeden proces) i odpalić go w lokalnym kliencie.
Oto kod, pisany na szybko i testowany tylko raz ale powinien działać ;) :
<?php
/*********************************************************\
* *
* Najprostszy z mozliwych tracker BitTorrenta, posiada *
* jedynie minimalna funkcjonalnosc - zapisywanie *
* i wysylanie listy peerow. Zero obslugi bledow, zero *
* sprawdzania poprawnosci danych - nadaje sie tylko do *
* uzywania w przypadku, gdy np. chcemy przeslac cos *
* bardzo waskiej grupie osob lub przeslac sobie pliki *
* z shella za pomoca klienta torrent. *
* Zapisuje tylko ip, port, czas announce i info_hash, *
* brak jakiejkolwiek kontroli ratio, brak listy *
* dozwolonych klientow itd. *
* *
\*********************************************************/
header( "Content-type: text/plain" );
$port = (int) $_GET["port"]; //port klienta - musi byc wyslany w liscie peerow
//pobieramy i filtrujemy info_hash torrenta, potrzebny jest do rozrozniania torrentow
$infoHash = $_GET["info_hash"];
if( get_magic_quotes_gpc() ) {
$infoHash = stripslashes( $infoHash );
}
$infoHash = urlencode( $infoHash ); //na wszelki wypadek lepiej nie zapisywac w postaci binarnej
$peerList = @file_get_contents( "peers" ); //lista peerow, kazda linia w formacie ip:port|timestamp ostatniego announce|info_hash(url_encoded)
$peerList = explode( "\n", $peerList );
echo "d"; //otwieramy "dictionary" zawierajacy odpowiedz
echo "8:interval"; //czas co jaki klient bedzie odnawial liste peerow
echo "i3600e"; //3600 sekund = 1 godzina
echo "5:peers"; //bedziemy wysylac liste peerow
$peersLen = 0; //dlugosc stringu z lista peerow
$peers = ""; //lista peerow
$selfPeer = false; //klient jest juz na liscie peerow?
foreach( $peerList as $i => $peer ) //dla kazdego peera z pliku
{
$peer = explode( "|", $peer ); //[0] => ip:port, [1] => timestamp of last action, [2] => info_hash
if( count( $peer ) != 3 ) { //na wszelki wypadek sprawdzamy, czy po podzieleniu jest wlasciwa ilosc elementow
unset( $peerList[$i] );
continue;
}
if( $peer[1] < time() - 60*60*3 ) { //jesli peer byl nieaktywny przez ponad 3h
unset( $peerList[$i] ); //usuwamy go z listy
continue;
}
if( $peer[2] != $infoHash ) { //upewniamy sie, ze peer udostepnia/pobiera zadanego torrenta
continue;
}
$peer = explode( ":", $peer[0] ); //[0] => ip, [1] => port
if( $peer[0] == $_SERVER["REMOTE_ADDR"] && $peer[1] == $port ) { //jesli ip i port peera z listy == ip+port klienta
$selfPeer = true; //klient jest na liscie
continue; //nie wysylamy klientowi jego IP
}
$peers .= pack( "Nn", ip2long( $peer[0] ), $peer[1] ); //dopisujemy peera do listy
$peersLen += 6; //zwiekszamy dlugosc listy peerow (N (4 bajty) + n (2 bajty) = 6 bajtow)
}
if( !$selfPeer ) { //jesli klienta nie ma na liscie peerow
$peerList[] = "{$_SERVER["REMOTE_ADDR"]}:{$port}|" . time() . "|{$infoHash}";
}
echo "{$peersLen}:{$peers}"; //wysylamy liste peerow
echo "e"; //zamykamy "dictionary"
file_put_contents( "peers", join( "\n", $peerList ) ); //zapisujemy liste peerow do pliku
?>