BlueHell mIRC Script — File Browser
BlueHellmIRCScriptv1.0 / BlueHellmIRCScriptv1.0 / BlueHellScript / System / tracker / tracker.mrc
tracker.mrc — 42.61 KB — Download this file
; mTracker BitTorrent Tracker by Scab
;
; Scrape: http://your.own.ip.number:6969/scrape
; Announce: http://your.own.ip.number:6969/announce
;
; TODO: Support for compact=0 requests
; Client detection based on User-Agent, fall-back on peer_id
; IPv6 support
; &natmapped=1&localip=114.48.27.48&port_type=wan (some BC clients seem to send this; not sure how it's useful. localip commonly not local at all.)
; timer that clears out dead torrents (last activity more than 93 days (3 months) ago or so, configurable)
; dns-resolve ip's on info_hash web pages (set "dns" CGI data in peerdata table). configurable to avoid a ton of dns lookups?
menu menubar {
-
m&Tracker
.$iif($sock(tracker),&Stop,&Start):if ($sock(tracker)) stoptracker | else starttracker
.-
.&Options
..Change &tracker port $+ $chr(9) $+ $iif($hget(trackerinfo,tracker_port),$+($chr(91),$v1,$chr(93))):trackerport tracker $$?="New port:"
..Change &httpd port $+ $chr(9) $+ $iif($hget(trackerinfo,httpd_port),$+($chr(91),$v1,$chr(93))):trackerport httpd $$?="New port:"
..Change h&ostname $+ $chr(9) $+ $+($chr(91),$iif($hget(trackerinfo,hostname_override),$v1,not set),$chr(93)):trackerhost $input(Enter the hostname to use: $+ $crlf $+ ("-unset" to unset current hostname),e,mTracker)
..Change webadmin &username $+ $chr(9) $+ $+($chr(91),$iif($hget(trackerinfo,httpd_u),$v1,not set),$chr(93)):trackerwebadmin user $$?="New webadmin username:"
..Change webadmin &password $+ $chr(9) $+ $+($chr(91),$iif($hget(trackerinfo,httpd_p),$v1,not set),$chr(93)):trackerwebadmin pass $$?="New webadmin password:"
..-
..&Uninstall:trackerunload
.-
.$iif($sock(trackerwww),&Web Interface):run http:// $+ $iif($hget(trackerinfo,hostname_override),$v1,$iif($hget(trackerinfo,wan_ip),$v1,$sock(tracker).ip)) $+ : $+ $iif($hget(trackerinfo,httpd_port),$v1,6970) $+ /
}
; alias to change webadmin user/pass
alias trackerwebadmin {
if (($1 == user) || ($1 == pass)) && ($2) {
hadd trackerinfo httpd_ [ $+ [ $replace($1,user,u,pass,p) ] ] $2
echo -esa * Changed webadmin $1 $+ .
}
}
; alias to change ports
alias trackerport {
if (!$1) && ($isid) && ($hget(trackerinfo,tracker_port)) return $v1
elseif (($1 == tracker) || ($1 == httpd)) && ($2) {
if ($2 isnum 1-65536) {
var %hash = $+($lower($1),_port), %sock = $replace($1,httpd,trackerwww)
hadd trackerinfo %hash $2
if ($show) echo -esa * Changed $lower($1) port to $2 $+ .
if ($sock(%sock)) && ($sock(%sock).bindport != $2) {
sockclose %sock
socklisten %sock $2
if ($show) echo -esa * Restarted $lower($1) $+ .
}
}
elseif ($show) echo -esa * Port must be a number between 1 and 65536.
}
}
; alias to toggle debugging
alias trackerdebug {
if ($1 == on) {
hadd trackerinfo debug 1
if ($show) echo -esa * Turned on debugging.
}
elseif ($1 == off) {
hadd trackerinfo debug 0
if ($show) echo -esa * Turned off debugging.
}
else {
var %x = $iif($hget(trackerinfo,debug),0,1)
hadd trackerinfo debug %x
if ($show) echo -esa * Turned $iif(%x,on,off) debugging.
}
}
; alias to set tracker hostname
alias trackerhost {
if ($1 == -unset) {
if ($hget(trackerinfo,hostname_override)) {
hdel trackerinfo hostname_override
if ($show) echo -esa * Unset the tracker hostname.
}
elseif ($show) echo -esa * There is no tracker hostname set.
}
elseif ($1) {
hadd trackerinfo hostname_override $1
if ($show) echo -esa * Set the tracker hostname to $+(",$1,") $+ . Announce URL: http:// $+ $1 $+ : $+ $iif($hget(trackerinfo,tracker_port),$v1,6969) $+ /announce
}
}
on *:load:{
.loadhashes
.loadclientlist
hadd -m trackerinfo tracker_port $iif($hget(trackerinfo,tracker_port),$v1,6969)
hadd -m trackerinfo httpd_port $iif($hget(trackerinfo,httpd_port),$v1,6970)
hadd -m trackerinfo httpd_u admin
hadd -m trackerinfo httpd_p $randstr
echo -esa * mTracker was loaded successfully. A menubar popup menu has been added.
echo -esa * It is highly recommended to create a hostname to use for your tracker URL before proceeding. Please read the first question and answer in the FAQ section of trackerreadme.txt.
}
alias trackerunload {
if ($input(Are you sure you want to uninstall the tracker?,ywd,mTracker)) {
unloadcleanup
!unload -rs $qt($script)
}
}
alias -l unloadcleanup {
if ($sock(tracker)) sockclose tracker
if ($sock(trackerwww)) sockclose trackerwww
if ($sock(trackerdata.*,0) > 0) sockclose trackerdata.*
if ($hget(torrents)) hfree torrents
if ($hget(peers)) hfree peers
if ($hget(peerdata)) hfree peerdata
if ($hget(trackerinfo)) hfree trackerinfo
if ($hget(torrentclients)) hfree torrentclients
if ($hget(torrentclients_shadow)) hfree torrentclients_shadow
if ($hget(torrentclients_bram)) hfree torrentclients_bram
}
on *:unload:{
if ($hget(trackerinfo)) || ($hget(torrents)) {
; user is unloading the script with the /unload command; run the clean-up.
unloadcleanup
}
}
on *:start:{
.loadhashes
.loadclientlist
if ($hget(trackerinfo,on_on_exit)) {
starttracker
hdel trackerinfo on_on_exit
}
.timertrackerbackup 0 3600 .savehashes
}
on *:exit:{
if ($sock(tracker)) hadd trackerinfo on_on_exit 1
savehashes
saveclientlist
}
alias -l mtrackerversion return mTracker/0.2
alias starttracker {
if ($sock(tracker)) {
if ($show) echo -esa * Tracker is already running.
}
else starttrackerd
starttrackerwww
}
alias -l starttrackerd {
socklisten tracker $iif($hget(trackerinfo,tracker_port),$v1,6969)
if (!$hget(peers)) hmake peers 1000
if (!$hget(peerdata)) hmake peerdata 1000
if (!$hget(torrents)) hmake torrents 100
if ($show) {
if ($hget(trackerinfo,hostname_override)) echo -esa * Tracker started (http:// $+ $v1 $+ : $+ $sock(tracker).bindport $+ /announce $+ ).
else echo -esa * Tracker started (http:// $+ $iif($sock(tracker).ip,$v1,127.0.0.1) $+ : $+ $sock(tracker).bindport $+ /announce $+ ).
}
if (!$hget(trackerinfo,hostname_override)) wimiplookup
return
:error
if ($gettok($error,3-4,32) == bind error) {
echo -esa * Can't start tracker: port $iif($hget(trackerinfo,tracker_port),$v1,6969) is already in use.
reseterror
}
}
alias -l starttrackerwww {
if (!$sock(trackerwww)) {
socklisten trackerwww $iif($hget(trackerinfo,httpd_port),$v1,6970)
return
:error
if ($gettok($error,3-4,32) == bind error) {
echo -esa * Can't start tracker web interface: port $iif($hget(trackerinfo,httpd_port),$v1,6970) is already in use.
reseterror
}
}
}
alias stoptracker {
if (!$sock(tracker)) && ($show) echo -esa * Tracker is not running.
else {
sockclose tracker
sockclose trackerdata.*
if ($show) echo -esa * Tracker stopped.
}
if ($sock(trackerwww)) sockclose trackerwww
}
on *:socklisten:tracker:{
var %unique = $+($r(1,999999),$ticks,$longip($sock($sockname).ip),$sock($sockname).port)
sockaccept $+(trackerdata.,$sock(trackerdata.*,0),%unique)
}
on *:socklisten:trackerwww:{
var %unique = $+($r(1,999999),$ticks,$longip($sock($sockname).ip),$sock($sockname).port), %sn = $+(trackerwww.,$sock(trackerdata.*,0),%unique)
sockaccept %sn
sockmark %sn state=1
}
on *:sockread:trackerdata.*:{
if ($sockerr < 1) && ($sock(tracker)) {
:read
var %x
sockread %x
if ($sockbr > 0) && (%x) {
tokenize 32 %x
if ($1 == GET) && (HTTP/*.* iswm $3) {
var %doc = $gettok($2,1,63), %parms = $gettok($2,2-,63) $+ &null=1
if (%parms) {
var %info_hash = $resolveinfohash($cgiparm(%parms).info_hash)
var %peer_id = $+($resolvepeerid($cgiparm(%parms).peer_id),_,%info_hash)
; turn away peers that can't handle compact peerlists
if ($cgiparm(%parms).compact == 0) {
; failure reason
bset -t &nocomp 1 d14:failure reason43:This tracker only accepts compact responsese
bset -t &nocompact 1 HTTP/1.0 200 OK $+ $crlf
bset -t &nocompact $calc(1 + $bvar(&nocompact,0)) Content-Length: $bvar(&nocomp,0) $+ $crlf
bset -t &nocompact $calc(1 + $bvar(&nocompact,0)) Connection: close $+ $crlf
bset -t &nocompact $calc(1 + $bvar(&nocompact,0)) Content-Type: text/plain $+ $crlf $+ $crlf
bcopy &nocompact $calc(1 + $bvar(&nocompact,0)) &nocomp 1 -1
sw $sockname &nocompact
if ($hget(trackerinfo,debug)) {
bwrite trackerdebug.nocompact -1 $asctime($ctime) %peer $+ $crlf
bwrite trackerdebug.nocompact -1 &nocompact
bwrite trackerdebug.nocompact -1 $str($crlf,2)
}
}
}
if (%doc == /scrape) && (%info_hash) {
; scrape
var %metainfo = $hget(torrents,%info_hash)
if (%metainfo) {
var %completed = $completed(%info_hash)
var %downloaded = $cgiparm(%metainfo).downloaded
var %incomplete = $incomplete(%info_hash)
bset &binhash 1 $binhash($cgiparm(%parms).info_hash)
bset -t &scrape 1 d5:filesd20:
bcopy &scrape $calc(1 + $bvar(&scrape,0)) &binhash 1 -1
bset -t &scrape $calc(1 + $bvar(&scrape,0)) d8:completei $+ %completed $+ e
bset -t &scrape $calc(1 + $bvar(&scrape,0)) 10:downloadedi $+ %downloaded $+ e
bset -t &scrape $calc(1 + $bvar(&scrape,0)) 10:incompletei $+ %incomplete $+ e
bset -t &scrape $calc(1 + $bvar(&scrape,0)) eee
; reply
bset -t &scrapesw 1 HTTP/1.0 200 OK $+ $crlf
bset -t &scrapesw $calc(1 + $bvar(&scrapesw,0)) Content-Length: $bvar(&scrape,0) $+ $crlf
bset -t &scrapesw $calc(1 + $bvar(&scrapesw,0)) Connection: close $+ $crlf
bset -t &scrapesw $calc(1 + $bvar(&scrapesw,0)) Content-Type: text/plain $+ $crlf $+ $crlf
bcopy &scrapesw $calc(1 + $bvar(&scrapesw,0)) &scrape 1 -1
sw $sockname &scrapesw
if ($hget(trackerinfo,debug)) {
bwrite trackerdebug.scrape -1 &scrapesw
bwrite trackerdebug.scrape -1 $str($crlf,2)
}
}
}
elseif (%doc == /announce) && (%info_hash) {
; announce
if (!$hget(torrents,%info_hash)) {
; new torrent
hadd torrents %info_hash downloaded=0 $+ &last_seen= $+ $ctime
}
hadd -u7200 peers %peer_id $modcgi($modcgi(%parms,info_hash,%info_hash),peer_id,%peer_id)
; blindly honor ip field for cases where client and tracker are both on same side of NAT gateway (RFC1918 ip in socket)
; clients will presumably not provide bad data seeing how that would make them non-routable...
if (?*.?*.?*.?* iswm $cgiparm(%parms).ip) var %ip = $v2
else var %ip = $sock($sockname).ip
hadd -u7200 peerdata %peer_id $+(ip=,%ip)
if ($cgiparm(%parms).event == completed) {
if ($cgiparm($hget(torrents,%info_hash)).last_seen) hadd torrents %info_hash $calccgi($modcgi($hget(torrents,%info_hash),last_seen,$ctime),downloaded,+1)
else hadd torrents %info_hash $calccgi($hget(torrents,%info_hash),downloaded,+1) $+ &last_seen= $+ $ctime
}
else {
if ($cgiparm($hget(torrents,%info_hash)).last_seen) hadd torrents %info_hash $modcgi($hget(torrents,%info_hash),last_seen,$ctime)
else hadd torrents %info_hash $hget(torrents,%info_hash) $+ &last_seen= $+ $ctime
}
if ($cgiparm(%parms).event == stopped) {
hdel peers %peer_id
hdel peerdata %peer_id
}
; announce reply...
var %completed = $+(d8:completei,$completed(%info_hash),e)
var %downloaded = $+(10:downloadedi,$cgiparm($hget(torrents,%info_hash)).downloaded,e)
var %incomplete = $+(10:incompletei,$incomplete(%info_hash),e)
var %intervals = $+(8:intervali,1800,e,12:min intervali,900,e)
var %intropeers = 5:peers
; Algo to select which peers to suggest (IMPORTANT!)
; loop through all peers
var %x = 1, %peers = $hfind(peers,*info_hash= $+ %info_hash $+ &*,0,w).data, %peersrequested = 25
var %wn = $+(@peers,%info_hash,$ticks), %wn2 = $+(%wn,D), %wn3 = $+(%wn,S)
if ($cgiparm($hget(peers,%peer_id)).numwant isnum) var %peersrequested = $v1
if (%peersrequested > %peers) var %peersrequested = %peers
; windows should really never exist, we rely on %wn producing a string unique to this request, but just in case..
if ($window(%wn)) window -c %wn
if ($window(%wn2)) window -c %wn
if ($window(%wn3)) window -c %wn
; compile list of all known peers (this is mostly to avoid having to $hfind query the hash table repeatedly later on)
window -h %wn
while (%x <= %peers) {
var %peer = $hfind(peers,*info_hash= $+ %info_hash $+ &*,%x,w).data
aline %wn %peer
inc %x
}
; if requesting peer is a seeder, send it only leechers (should improve useful peer distribution in the swarm)
; NOTE: this client has already been hdel'd if this is the reply of an event=stopped call
if ($cgiparm($hget(peers,%peer_id)).left == 0) || (!$hget(peers,%peer_id)) {
; compile list of leechers
window -h %wn2
var %x = 1
while (%x <= $line(%wn,0)) {
var %peer = $hget(peers,$line(%wn,%x)), %left = $cgiparm(%peer).left
if (%left > 0) aline %wn2 $line(%wn,%x)
inc %x
}
window -h %wn3
; make a random selection of them
if ($line(%wn2,0) > 0) {
var %x = 1, %linestoread = %peersrequested
while (%x <= %linestoread) {
var %rand = $r(1,$line(%wn2,0)), %peer = $line(%wn2,%rand)
aline %wn3 %peer
; remove peer from list
dline %wn2 %rand
inc %x
if ($line(%wn2,0) < 1) break
}
}
}
; if requesting peer is not a seeder, proceed with regular peer selection algo
else {
; compile list of peers ordered by completion
window -hs %wn2
var %x = 1
while (%x <= $line(%wn,0)) {
var %peer = $hget(peers,$line(%wn,%x)), %left = $cgiparm(%peer).left, %padded = $+($str(0,$calc(40 - $len(%left))),%left)
aline %wn2 %padded $line(%wn,%x)
inc %x
}
if ($line(%wn2,0) > 0) {
; pick out top 5% for selection to make sure presumptive seed(s) are suggested
; THIS IS A HIGH PERCENTAGE!
; Messing with the randomness of peer selection has a negative effect on the swarm!
var %x = 1, %linestoread = $ceil($calc(%peersrequested / 20)), %linesmax = $line(%wn2,0)
window -h %wn3
while (%x <= %linestoread) {
var %selected = $line(%wn2,%x), %curpeer = $gettok(%selected,2,32)
aline %wn3 %curpeer
; remove peer from peer list
dline %wn $fline(%wn,%curpeer,1)
inc %x
if (%x > %linesmax) break
}
}
; pad out with random peers
var %x = 1, %selectedpeers = $line(%wn3,0), %linestoread = $calc(%peersrequested - %selectedpeers)
while (%x <= %linestoread) {
var %rand = $r(1,$line(%wn,0)), %peer = $line(%wn,%rand)
aline %wn3 %peer
; remove peer from list
dline %wn %rand
inc %x
if ($line(%wn,0) < 1) break
}
}
; %wn3 now has the peer selection
var %x = 1
while (%x <= $line(%wn3,0)) {
var %peer = $line(%wn3,%x), %ip = $cgiparm($hget(peerdata,%peer)).ip, %port = $cgiparm($hget(peers,%peer)).port
bset &peers $calc(1 + $bvar(&peers,0)) $binpeer(%ip,%port)
inc %x
}
; close windows
window -c %wn
window -c %wn2
window -c %wn3
; send client's own data back if it's alone, rather than 0:e
if ($bvar(&peers,0) == 0) && ($cgiparm(%parms).event != stopped) {
var %ip = $sock($sockname).ip, %port = $cgiparm(%parms).port
if (%ip) && (%port isnum) bset &peers 1 $binpeer(%ip,%port)
}
; HTTP reply
bset -t &peers $calc(1 + $bvar(&peers,0)) e
bset -t &final 1 $+(%completed,%downloaded,%incomplete,%intervals,%intropeers)
bset -t &final $calc(1 + $bvar(&final,0)) $+($calc($bvar(&peers,0) - 1),:)
bcopy &final $calc(1 + $bvar(&final,0)) &peers 1 -1
bset -t &sw 1 HTTP/1.0 200 OK $+ $crlf
bset -t &sw $calc(1 + $bvar(&sw,0)) Content-Length: $bvar(&final,0) $+ $crlf
bset -t &sw $calc(1 + $bvar(&sw,0)) Connection: close $+ $crlf
bset -t &sw $calc(1 + $bvar(&sw,0)) Content-Type: text/plain $+ $crlf $+ $crlf
bcopy &sw $calc(1 + $bvar(&sw,0)) &final 1 -1
sw $sockname &sw
if ($hget(trackerinfo,debug)) {
bwrite trackerdebug.announce -1 &sw
bwrite trackerdebug.announce -1 $str($crlf,2)
}
}
else {
; HTTP permanently moved redirect to :httpd_port
bset -t &moved 1 HTTP/1.0 301 Moved Permanently $+ $crlf
bset -t &moved $calc(1 + $bvar(&moved,0)) Location: http:// $+ $iif($hget(trackerinfo,hostname_override),$v1,$iif($hget(trackerinfo,wan_ip),$v1,$sock(tracker).ip)) $+ : $+ $iif($sock(trackerwww).bindport,$v1,$iif($hget(trackerinfo,httpd_port),$v1,6970)) $+ $2 $+ $crlf
bset -t &moved $calc(1 + $bvar(&moved,0)) Content-Length: 0 $+ $crlf
bset -t &moved $calc(1 + $bvar(&moved,0)) Connection: close $+ $str($crlf,2)
bwrite redirect 0 &moved
sw $sockname &moved
}
}
goto read
}
}
}
; Keeping the Web Interface in a separate socket for practical reasons
; (retaining ability to handle browser and torrent client requests differently if ever necessary)
on *:sockread:trackerwww.*:{
if ($sockerr < 1) {
:read
var %x, %sm = $sock($sockname).mark
sockread %x
if ($sockbr) {
tokenize 32 %x
; check for get request (only supported request atm)
if ($1 === GET) && (/* iswm $2) && (HTTP/?* iswm $3) sockmark $sockname $modcgi(%sm,state,1) %x
; read headers
elseif ($cgiparm($gettok(%sm,1,32)).state == 1) {
if ($len(%x) == 0) {
sockmark $sockname $modcgi(%sm,state,2)
if ($hget(trackerinfo,debug)) {
write $qt($+($scriptdir,trackerwww.log)) $sock($sockname).ip - - $+($chr(91),$asctime(dd/mmm/yyyy:HH:nn:ss zz),$chr(93)) %sm
}
; provide reply
var %doc = $gettok(%sm,3,32)
if ($gettok(%doc,1,63) == /) {
; generate page content
; if "GET /?info_hash=somehash"
if ($cgiparm($gettok(%doc,2,63)).info_hash) {
var %req_hash = $v1, %hashpage = $qt($+($scriptdir,trackerwww.info_hash.html)), %lof = $lof(%hashpage)
bread %hashpage 0 %lof &hashpage
; head
var %startpos = $bfind(&hashpage,1,<!-- #head -->) + 15, %endpos = $bfind(&hashpage,%startpos,<!-- #end -->) - 1
bcopy &htemplate 1 &hashpage %startpos $calc(%endpos - %startpos)
bcopy &beforehead 1 &hashpage 1 $calc(%startpos - 16)
bcopy &afterhead 1 &hashpage $calc(%endpos + 15) %lof
bset -t &head 1 $replace($bvar(&htemplate,1,$bvar(&htemplate,0)).text,info_hash,%req_hash)
bcopy &appliedhead 1 &beforehead 1 -1
bcopy &appliedhead $calc($bvar(&appliedhead,0) + 1) &head 1 -1
bcopy &appliedhead $calc($bvar(&appliedhead,0) + 1) &afterhead 1 -1
; peer list
var %startpos = $bfind(&appliedhead,1,<!-- #list -->) + 15, %endpos = $bfind(&appliedhead,%startpos,<!-- #end -->) - 1
bcopy &template 1 &appliedhead %startpos $calc(%endpos - %startpos)
bcopy &beforelist 1 &appliedhead 1 $calc(%startpos - 16)
bcopy &afterlist 1 &appliedhead $calc(%endpos + 15) %lof
var %template = $bvar(&template,1,$bvar(&template,0)).text, %peers = $getpeer(%req_hash,0)
var %x = 1
while (%x <= %peers) {
var %peer = $getpeer(%req_hash,%x)
var %downloaded = $cgiparm($hget(peers,%peer)).downloaded
var %uploaded = $cgiparm($hget(peers,%peer)).uploaded
var %client = $getclientfrompeerid(%peer)
if (!%client) {
var %client = <i>Unknown</i><!-- $deltok(%peer,-1,95) -->
if ($hget(trackerinfo,debug)) {
bwrite trackerdebug.peer_id -1 UNKNOWN %peer $+ $crlf
}
}
var %ratio = $round($calc(%uploaded / %downloaded),2)
if (%ratio == 0) {
if (%uploaded > %downloaded) var %ratio = Inf.
elseif (%uploaded == %downloaded) var %ratio = 1.00
else var %ratio = 0.00
}
var %left = $cgiparm($hget(peers,%peer)).left
; insert into the template
bset -t &peerlist $calc(1 + $bvar(&peerlist,0)) $replace(%template,peer_id,$cgiparm($hget(peerdata,%peer)).ip,client,%client,uploaded,$bytes(%uploaded).suf,downloaded,$bytes(%downloaded).suf,ratio,%ratio,left,$bytes(%left).suf) $+ $crlf
inc %x
}
bcopy &finalpage 1 &beforelist 1 -1
if ($bvar(&peerlist,0) == 0) bset -t &peerlist 1 <td colspan="6" scope="colgroup">n/a</td>
bcopy &finalpage $calc($bvar(&finalpage,0) + 1) &peerlist 1 -1
bcopy &finalpage $calc($bvar(&finalpage,0) + 1) &afterlist 1 -1
; version (god I hate this templating code..)
; NOTE: there's no version string in the default info_hash template.
; 'version' is also the only template string that can be left out; 'head' and 'list' MUST to be in the template.
; I'm not bothering with checks to allow useless template designs..
var %vstartpos = $bfind(&finalpage,1,<!-- #version -->) + 18, %vendpos = $bfind(&finalpage,%startpos,<!-- #end -->) - 1
if (%vstartpos > 18) && (%vendpos isnum) {
bcopy &vtemplate 1 &finalpage %vstartpos $calc(%vendpos - %vstartpos)
bcopy &before 1 &finalpage 1 $calc(%vstartpos - 19)
bcopy &after 1 &finalpage $calc(%vendpos + 15) -1
bset -t &version 1 $replace($bvar(&vtemplate,1,$bvar(&vtemplate,0)).text,version,$mtrackerversion on $iif($hget(trackerinfo,hostname_override),$v1,$iif($hget(trackerinfo,wan_ip),$v1,$iif($sock(tracker).ip,$v1,localhost))))
bcopy &sendout 1 &before 1 -1
bcopy &sendout $calc($bvar(&sendout,0) + 1) &version 1 -1
bcopy &sendout $calc($bvar(&sendout,0) + 1) &after 1 -1
}
else bcopy &sendout 1 &finalpage 1 -1
; serve page
bset -t &www 1 HTTP/1.1 200 OK $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Date: $asctime(ddd) $+ , $asctime(dd mmm yyyy HH:nn:ss) $gettok($asctime(zzz),2,32) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Language: en-US $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Length: $bvar(&sendout,0) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Cache-Control: no-cache, must-revalidate $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Pragma: no-cache $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Connection: close $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Type: text/html; charset=iso-8859-1 $+ $str($crlf,2)
bcopy &www $calc(1 + $bvar(&www,0)) &sendout 1 -1
sw $sockname &www
}
; if "GET /"
else {
var %index = $qt($+($scriptdir,trackerwww.index.html)), %lof = $lof(%index)
bread %index 0 %lof &index
var %startpos = $bfind(&index,1,<!-- #list -->) + 15, %endpos = $bfind(&index,%startpos,<!-- #end -->) - 1
bcopy &template 1 &index %startpos $calc(%endpos - %startpos)
bcopy &beforelist 1 &index 1 $calc(%startpos - 16)
bcopy &afterlist 1 &index $calc(%endpos + 15) %lof
var %template = $bvar(&template,1,$bvar(&template,0)).text
if ($hget(torrents,0).item > 0) {
var %x = 1
while (%x <= $hget(torrents,0).item) {
; data from torrents table
var %info_hash = $hget(torrents,%x).item, %downloaded = $cgiparm($hget(torrents,%info_hash)).downloaded, %last_seen = $cgiparm($hget(torrents,%info_hash)).last_seen
; calculated data
var %peers = $getpeer(%info_hash,0), %seeds = $completed(%info_hash), %incomplete = $incomplete(%info_hash)
; insert into the template
bset -t &torrents $calc(1 + $bvar(&torrents,0)) $replace(%template,info_hash,<a href="?info_hash= $+ %info_hash $+ "> $+ %info_hash $+ </a>,downloaded,%downloaded,peers,%peers,seeds,%seeds,incomplete,%incomplete,last_activity,$asctime(%last_seen)) $+ $crlf
inc %x
}
}
else bset -t &torrents 1 <td colspan="6">n/a</td> $+ $crlf
bcopy &finalindex 1 &beforelist 1 -1
bcopy &finalindex $calc($bvar(&finalindex,0) + 1) &torrents 1 -1
bcopy &finalindex $calc($bvar(&finalindex,0) + 1) &afterlist 1 -1
; version
var %startpos = $bfind(&finalindex,1,<!-- #version -->) + 18, %endpos = $bfind(&finalindex,%startpos,<!-- #end -->) - 1
bcopy &vtemplate 1 &finalindex %startpos $calc(%endpos - %startpos)
bcopy &before 1 &finalindex 1 $calc(%startpos - 19)
bcopy &after 1 &finalindex $calc(%endpos + 15) -1
bset -t &version 1 $replace($bvar(&vtemplate,1,$bvar(&vtemplate,0)).text,version,$mtrackerversion on $iif($hget(trackerinfo,hostname_override),$v1,$iif($hget(trackerinfo,wan_ip),$v1,$iif($sock(tracker).ip,$v1,localhost))))
bcopy &sendout 1 &before 1 -1
bcopy &sendout $calc($bvar(&sendout,0) + 1) &version 1 -1
bcopy &sendout $calc($bvar(&sendout,0) + 1) &after 1 -1
; serve page
bset -t &www 1 HTTP/1.1 200 OK $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Date: $asctime(ddd) $+ , $asctime(dd mmm yyyy HH:nn:ss) $gettok($asctime(zzz),2,32) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Language: en-US $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Length: $bvar(&sendout,0) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Cache-Control: no-cache, must-revalidate $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Pragma: no-cache $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Connection: close $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Type: text/html; charset=iso-8859-1 $+ $str($crlf,2)
bcopy &www $calc(1 + $bvar(&www,0)) &sendout 1 -1
sw $sockname &www
}
}
elseif ($gettok(%doc,1,63) == /admin/) || ($gettok(%doc,1,63) == /admin) {
if ($cgiparm($sock($sockname).mark).authorization) {
; client is trying to log in
var %str = $decode($gettok($decode($v1,m),2,32),m), %u = $gettok(%str,1,58), %p = $gettok(%str,2,58)
var %hash_u = $hget(trackerinfo,httpd_u), %hash_p = $hget(trackerinfo,httpd_p)
if (%hash_u == $null) || (%hash_p == $null) goto 401
elseif (%u === %hash_u) && (%p === %hash_p) {
; authorized
if ($cgiparm($gettok(%doc,2-,63)).starttracker) {
.starttracker
}
elseif ($cgiparm($gettok(%doc,2-,63)).stoptracker) {
if ($sock(tracker)) {
sockclose tracker
sockclose trackerdata.*
}
}
var %admindoc = $qt($+($scriptdir,trackerwww.admin.html)), %lof = $lof(%admindoc)
bread %admindoc 0 %lof &admindoc
; status
var %startpos = $bfind(&admindoc,1,<!-- #status -->) + 17, %endpos = $bfind(&admindoc,%startpos,<!-- #end -->) - 1
bcopy &stemplate 1 &admindoc %startpos $calc(%endpos - %startpos)
bcopy &sbefore 1 &admindoc 1 $calc(%startpos - 19)
bcopy &safter 1 &admindoc $calc(%endpos + 15) -1
bset -t &status 1 $replace($bvar(&stemplate,1,$bvar(&stemplate,0)).text,_status,$iif($sock(tracker),ON,OFF))
bcopy &admin 1 &sbefore 1 -1
bcopy &admin $calc($bvar(&admin,0) + 1) &status 1 -1
bcopy &admin $calc($bvar(&admin,0) + 1) &safter 1 -1
; out
bset -t &www 1 HTTP/1.1 200 OK $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Date: $asctime(ddd) $+ , $asctime(dd mmm yyyy HH:nn:ss) $gettok($asctime(zzz),2,32) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Length: $bvar(&admin,0) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Cache-Control: no-cache, must-revalidate $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Pragma: no-cache $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Connection: close $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Type: text/html; charset=iso-8859-1 $+ $str($crlf,2)
bcopy &www $calc(1 + $bvar(&www,0)) &admin 1 -1
sw $sockname &www
}
else goto 401
}
else {
:401
var %authdoc = $qt($+($scriptdir,trackerwww.401.html)), %lof = $lof(%authdoc)
bread %authdoc 0 %lof &authdoc
bset -t &www 1 HTTP/1.0 401 UNAUTHORIZED $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Date: $asctime(ddd) $+ , $asctime(dd mmm yyyy HH:nn:ss) $gettok($asctime(zzz),2,32) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) WWW-Authenticate: Basic realm="mTracker Administration Area" $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Length: $bvar(&authdoc,0) $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Connection: close $+ $crlf
bset -t &www $calc(1 + $bvar(&www,0)) Content-Type: text/html; charset=iso-8859-1 $+ $str($crlf,2)
bcopy &www $calc(1 + $bvar(&www,0)) &authdoc 1 -1
sw $sockname &www
}
}
elseif (%doc == /favicon.ico) {
var %favicon = $qt($+($scriptdir,trackerwww.favicon.ico)), %lof = $lof(%favicon)
bread %favicon 0 %lof &favicon
bset -t &fav 1 HTTP/1.1 200 OK $+ $crlf
bset -t &fav $calc(1 + $bvar(&fav,0)) Date: $asctime(ddd) $+ , $asctime(dd mmm yyyy HH:nn:ss) $gettok($asctime(zzz),2,32) $+ $crlf
bset -t &fav $calc(1 + $bvar(&fav,0)) Content-Length: $bvar(&favicon,0) $+ $crlf
bset -t &fav $calc(1 + $bvar(&fav,0)) Accept-Ranges: none $+ $crlf
bset -t &fav $calc(1 + $bvar(&fav,0)) Connection: close $+ $crlf
bset -t &fav $calc(1 + $bvar(&fav,0)) Content-Type: image/x-icon $+ $str($crlf,2)
bcopy &fav $calc(1 + $bvar(&fav,0)) &favicon 1 -1
sw $sockname &fav
}
else {
; HTTP 404
var %errordoc = $qt($+($scriptdir,trackerwww.404.html)), %lof = $lof(%errordoc)
bread %errordoc 0 %lof &errordoc
bset -t ¬found 1 HTTP/1.0 404 Not Found $+ $crlf
bset -t ¬found $calc(1 + $bvar(¬found,0)) Date: $asctime(ddd) $+ , $asctime(dd mmm yyyy HH:nn:ss) $gettok($asctime(zzz),2,32) $+ $crlf
bset -t ¬found $calc(1 + $bvar(¬found,0)) Content-Length: $bvar(&errordoc,0) $+ $crlf
bset -t ¬found $calc(1 + $bvar(¬found,0)) Connection: close $+ $crlf
bset -t ¬found $calc(1 + $bvar(¬found,0)) Content-Type: text/html; charset=iso-8859-1 $+ $str($crlf,2)
bcopy ¬found $calc(1 + $bvar(¬found,0)) &errordoc 1 -1
sw $sockname ¬found
}
}
else {
tokenize 58 %x
var %header = $1, %data = $2-
; this code may be a bit risky... sockmark can only hold so much data
if (!$cgiparm($gettok(%sm,1,32)). [ $+ [ %header ] ]) {
sockmark $sockname $gettok(%sm,1,32) $+ & $+ $replace($lower($1),$chr(32),_) $+ = $+ $encode(%data,m) $gettok(%sm,2-,32)
}
}
}
; this will trigger for any content data sent along with the headers.
; not useful right now, but maybe for some future feature..
elseif ($cgiparm($gettok(%sm,1,32)).state == 2) {
; moo
}
goto read
}
}
}
; sockwrite shorthand
alias -l sw {
sockwrite $1-
}
; alias to grab data from a RFC3875 query-string
alias -l cgiparm {
if ($1) && ($prop) {
var %a = $gettok($wildtok($1,$+($prop,=,*),1,38),2-,61)
if (%a == $null) var %a = $gettok($wildtok($1,$+($prop,=,*),1,63),2-,61)
return %a
}
}
; alias to modify data in a RFC3875 query-string
alias -l modcgi {
if ($3) {
return $puttok($1,$+($2,=,$3-),$findtok($1,$wildtok($1,$+($2,=,*),1,38),38),38)
}
}
; alias to run a basic arithmetic computation on the data in a RFC3875 query-string
alias -l calccgi {
if ($3) {
return $puttok($1,$+($2,=,$calc($gettok($wildtok($1,$+($2,=,*),1,38),2-,61) $3)),$findtok($1,$wildtok($1,$+($2,=,*),1,38),38),38)
}
}
alias -l completed {
var %x = $hfind(peers,*info_hash= $+ $1 $+ &*&left=0&*,0,w).data, %y = $hfind(peers,*left=0&*&info_hash= $+ $1 $+ &*,0,w).data, %z = %x + %y
return %z
}
alias -l incomplete return $calc($hfind(peers,*info_hash= $+ $1 $+ &*,0,w).data - $completed($1))
alias -l getpeer return $hfind(peers,*info_hash= $+ $1 $+ &*,$2,w).data
; $binpeer(ip,port)
; $binpeer(127.0.0.1,80)
alias -l binpeer {
var %x = 1, %in = $replace($1,.,$chr(32)) $2, %out
while (%x <= $numtok(%in,32)) {
var %hex = $base($gettok(%in,%x,32),10,16), %pos = 1
while (%pos <= $len(%hex)) {
var %out = %out $base($mid(%hex,%pos,2),16,10)
inc %pos 2
}
inc %x
}
return %out
}
; horribly bloated code for something similar to php's urldecode()
alias -l resolveinfohash {
var %pos = 1
while (%pos <= $len($1)) {
if ($asc($mid($1,%pos,1)) == 37) {
bset &infohash $calc(1 + $bvar(&infohash,0)) $base($mid($1,$calc(%pos +1),2),16,10)
inc %pos 3
}
else {
bset -t &infohash $calc(1 + $bvar(&infohash,0)) $mid($1,%pos,1)
inc %pos 1
}
}
var %x = 1, %dec = $bvar(&infohash,1,$bvar(&infohash,0)), %out
while (%x <= $numtok(%dec,32)) {
var %hex = $base($gettok(%dec,%x,32),10,16)
if ($len(%hex) < 2) var %hex = 0 $+ %hex
var %out = %out $+ %hex
inc %x
}
return %out
}
; 20 byte info_hash generation for scrape reply
alias -l binhash {
var %pos = 1
while (%pos <= $len($1)) {
if ($asc($mid($1,%pos,1)) == 37) {
bset &hash $calc(1 + $bvar(&hash,0)) $base($mid($1,$calc(%pos +1),2),16,10)
inc %pos 3
}
else {
bset -t &hash $calc(1 + $bvar(&hash,0)) $mid($1,%pos,1)
inc %pos 1
}
}
return $bvar(&hash,1,$bvar(&hash,0))
}
; slight variation of resolveinfohash code.
alias -l resolvepeerid {
var %pos = 1
while (%pos <= $len($1)) {
if ($asc($mid($1,%pos,1)) == 37) {
bset &peerid $calc(1 + $bvar(&peerid,0)) $base($mid($1,$calc(%pos +1),2),16,10)
inc %pos 3
}
else {
bset -t &peerid $calc(1 + $bvar(&peerid,0)) $mid($1,%pos,1)
inc %pos 1
}
}
var %x = 1, %dec = $bvar(&peerid,1,$bvar(&peerid,0)), %out
while (%x <= $numtok(%dec,32)) {
if ($gettok(%dec,%x,32) !isnum 33-122) {
var %hex = $base($gettok(%dec,%x,32),10,16)
if ($len(%hex) < 2) var %hex = 0 $+ %hex
var %out = %out $+ %hex
}
else var %out = %out $+ $chr($gettok(%dec,%x,32))
inc %x
}
return %out
}
; for TheSHAD0W's base64 version format. used in next alias below
alias -l base64version {
var %digits = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-, %x = 1
while (%x <= $len($1)) {
var %digit = $mid($1,%x,1), %y = 1
while (%y <= $len(%digits)) {
if ($mid(%digits,%y,1) === %digit) {
var %out = $+(%out,$calc(%y - 1),.)
break
}
inc %y
}
inc %x
}
var %trim = 1
; get rid of trailing 0's originating from unspecified alphabetical revision specifiers
if ($right(%out,3) == .0.) var %trim = 3
return $mid(%out,1,$calc($calc($len(%out))-%trim))
}
; it's probably wiser to go by the HTTP User-Agent header when available, but for client identification from the peer_id:
alias -l getclientfrompeerid {
; check for Bits on Wheels
if ($left($1,1) == -) && ($mid($1,2,3) === BOW) {
if ($mid($1,5,3) == A0C) var %v = 1.0.6
return Bits on Wheels $+ $iif(%v,/ $+ %v)
}
; check for Azureus-style encoding
;elseif (-??????-?* iswm $1) && ($mid($1,4,4) isalnum) {
elseif (-????????* iswm $1) && ($mid($1,4,4) isalnum) {
var %v = $v1, %c = $hget(torrentclients,$iif($mid($1,2,2) islower,$+($v1,(lower)),$v1)), %x = 1
while (%x <= $len(%v)) {
var %v2 = $+(%v2,$mid(%v,%x,1),.)
inc %x
}
var %v = $mid(%v2,1,$calc($calc($len(%v2))-1))
; libTorrent exception
if ($mid($1,2,2) === lt) var %v = $base64version($mid($1,4,4))
if (%c) && (%v) return %c %v
}
; check for Opera
elseif ($left($1,2) === OP) && ($mid($1,3,4) isnum) return Opera build $v1
; check for Qvod
elseif ($left($1,4) === QVOD) && ($mid($1,5,4) isnum) return Qvod build $v1
; check for Bram's new client style
elseif ($left($1,1) isalpha) && ($mid($1,2,1) isnum) && ($gettok($1,2,45) isnum) && ($gettok($1,3,45) isnum) {
var %c = $hget(torrentclients_bram,$left($1,1)), %v = $replace($mid($1,2,7),-,.)
if (*. iswm %v) {
var %x = 1
while (%x <= $numtok(%v,46)) {
var %v2 = $+(%v2,$gettok(%v,%x,46),.)
inc %x
}
var %v = $mid(%v2,1,$calc($calc($len(%v2))-1))
}
if (%c) && (%v) return %c %v
else return moo %c
}
; check for Shadow's encoding (always last; check will at times match some other encodings)
elseif ($left($1,1) isalpha) && ($remove($base64version($mid($gettok($1,1,45),2,$calc($len($gettok($1,1,45)) - 1))),.) isnum) && ($count($1,-) > 0) {
var %v = $base64version($mid($gettok($1,1,45),2,$calc($len($gettok($1,1,45)) - 1))), %c = $hget(torrentclients_shadow,$left($1,1))
if (%c) && (%v) return %c %v
}
}
alias -l savehashes {
if ($show) echo -esa * Saving tracker data...
write -c $qt($+($scriptdir,tracker.dat))
write -c $qt($+($scriptdir,trackerinfo.dat))
hsave -b torrents $qt($+($scriptdir,tracker.dat))
hsave -b trackerinfo $qt($+($scriptdir,trackerinfo.dat))
if ($show) echo -esa * Done saving tracker data.
}
alias -l loadhashes {
var %th = $qt($+($scriptdir,tracker.dat)), %trh = $qt($+($scriptdir,trackerinfo.dat))
if ($show) echo -esa * Loading tracker data...
if (!$hget(torrents)) hmake torrents 100
if (!$hget(trackerinfo)) hmake trackerinfo 10
if ($isfile(%th)) hload -b torrents %th
if ($isfile(%trh)) hload -b trackerinfo %trh
if ($show) echo -esa * Done loading tracker data.
}
alias -l saveclientlist {
if ($show) echo -esa * Saving client list...
write -c $qt($+($scriptdir,trackerclientlist1.dat))
write -c $qt($+($scriptdir,trackerclientlist2.dat))
write -c $qt($+($scriptdir,trackerclientlist3.dat))
hsave -b torrentclients $qt($+($scriptdir,trackerclientlist1.dat))
hsave -b torrentclients_shadow $qt($+($scriptdir,trackerclientlist2.dat))
hsave -b torrentclients_bram $qt($+($scriptdir,trackerclientlist3.dat))
if ($show) echo -esa * Done saving client list.
}
alias -l loadclientlist {
if ($show) echo -esa * Loading client list...
if (!$hget(torrentclients)) hmake torrentclients 10
if (!$hget(torrentclients_shadow)) hmake torrentclients_shadow 10
if (!$hget(torrentclients_bram)) hmake torrentclients_bram 10
hload -b torrentclients $qt($+($scriptdir,trackerclientlist1.dat))
hload -b torrentclients_shadow $qt($+($scriptdir,trackerclientlist2.dat))
hload -b torrentclients_bram $qt($+($scriptdir,trackerclientlist3.dat))
if ($show) echo -esa * Done loading client list.
}
; whatismyip.com automation for reliable WAN IP lookup
; http://www.whatismyip.com/automation/n09230945.asp
alias wimiplookup {
if ($sock(wimiplookup)) sockclose wimiplookup
sockopen wimiplookup www.whatismyip.com 80
sockmark wimiplookup $iif($show,1,0) 1
}
alias -l ipsw sockwrite -tn $sockname $1-
on *:sockopen:wimiplookup:{
ipsw GET /automation/n09230945.asp HTTP/1.1
ipsw User-Agent: $mtrackerversion (compatible; MSIE 6.0; Windows NT 5.1)
ipsw Host: www.whatismyip.com
ipsw Connection: close
ipsw $crlf
}
on *:sockread:wimiplookup:{
if ($sockerr < 1) {
:read
var %x
sockread -f %x
if ($sockbr) {
if ($gettok($sock($sockname).mark,2,32) == 1) && ($len(%x) == 0) sockmark $sockname $puttok($sock($sockname).mark,2,2,32)
elseif ($gettok($sock($sockname).mark,2,32) == 2) {
if (?*.?*.?*.?* iswm %x) && ($remove(%x,.) isnum) && ($longip(%x) isnum 1-4294967295) {
hadd trackerinfo wan_ip %x
if ($gettok($sock($sockname).mark,1,32) == 1) {
if ($sock(tracker)) && ($sock(tracker).ip != %x) echo -esa * WAN announce URL: http:// $+ %x $+ : $+ $sock(tracker).bindport $+ /announce (if in doubt, use this and forward ports $iif($hget(trackerinfo,tracker_port),$v1,6969) and $iif($hget(trackerinfo,httpd_port),$v1,6969) in your gateway)
else echo -esa * Your WAN IP is: %x
}
}
}
goto read
}
}
}
; rand
alias -l randstr {
var %x = 1, %y = $iif($1 isnum,$1,8)
while (%x <= %y) {
var %z = $r(0,2), %out = %out $+ $replace(%z,0,$r(a,z),1,$r(A,Z),2,$r(1,9))
inc %x
}
return %out
}
; EOF