code wiki / (root) / nx_http_tracker.nx

nx_http_tracker.nx source

↩ module page · 141 lines · 7907 B

1// nx_http_tracker.nx -- SOVEREIGN HTTP/TCP BitTorrent tracker announce (X-TORRENT-LIVE-002 R1). 2// WHY: this network blocks UDP to the usual tracker ports (:1337/:6969); HTTP trackers ride TCP 3// :80/:443 (which works -- the browser proves it), so they bypass the UDP block AND give the team a 4// second, independent peer-discovery channel. Pure-organ: composes nx_http_client (GET over TCP) + 5// nx_bencode (decode the response) + nx_dns_a (resolve the tracker host). NO curl, NO libtorrent. 6// The team decides which trackers to use + how to merge peers -- nothing external decides. 7// 8// announce GET: <path>?info_hash=%XX*20&peer_id=%XX*20&port=6881&uploaded=0&downloaded=0&compact=1 9// &left=<n>&event=started -> bencoded {interval, peers:<compact 6B/peer>} (or failure) 10// license_tier: ORIGINAL layer: peer-discovery (feeds the worker's peer set, like cl_announce/UDP) 11// module: nishi-core.torrent.http_tracker 12// depends: nishi-core.http_client, nishi-core.bencode, nishi-core.dns_a 13import "nx_http_client.nx" 14import "nx_bencode.nx" 15import "nx_dns_a.nx" 16import "nx_tracker_url.nx" 17const K_MAGIC_2048: i64 = 2048 18const K_MAGIC_131072: i64 = 131072 19const K_MAGIC_6881: i64 = 6881 20const K_MAGIC_16909060: i64 = 16909060 21 22func ht_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 23func ht_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i } 24func ht_putn(dst: *u8, off: i64, v: i64) -> i64 { 25 if v == 0 { dst[off] = 48 as u8; return off + 1 } 26 var m: i64 = v; if m < 0 { m = 0 - m } 27 let t: *u8 = sys_mmap(32); var k: i64 = 0 28 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 29 var j: i64 = 0; while j < k { dst[off+j] = t[k-1-j]; j = j + 1 } 30 return off + k 31} 32func ht_p2(s: *u8) -> i64 { sys_write(1, s, ht_strlen(s)); return 0 } 33func ht_pn2(v: i64) -> i64 { let b: *u8 = sys_mmap(28); let e: i64 = ht_putn(b, 0, v); sys_write(1, b, e); return 0 } 34func ht_report(label: *u8, ok: i64) -> i64 { if ok == 1 { ht_p2(" [PASS] " as *u8) } else { ht_p2(" [FAIL] " as *u8) } ht_p2(label); ht_p2("\n" as *u8); return 0 } 35 36// URL-encode 20 raw bytes as %XX (lowercase) x20 into out; returns bytes written (60). 37func ht_urlenc20(raw: *u8, out: *u8) -> i64 { 38 let hex: *u8 = "0123456789abcdef" as *u8 39 var o: i64 = 0; var i: i64 = 0 40 while i < 20 { 41 let b: i64 = raw[i] as i64 42 out[o] = 37 as u8; o = o + 1 43 out[o] = hex[(b >> 4) & 0xf]; o = o + 1 44 out[o] = hex[b & 0xf]; o = o + 1 45 i = i + 1 46 } 47 return o 48} 49 50// find the start of the HTTP body (byte after the "\r\n\r\n" header terminator); -1 if absent. 51func ht_find_body(buf: *u8, n: i64) -> i64 { 52 var i: i64 = 0 53 while i + 4 <= n { 54 if buf[i]==(13 as u8) { if buf[i+1]==(10 as u8) { if buf[i+2]==(13 as u8) { if buf[i+3]==(10 as u8) { return i + 4 } } } } 55 i = i + 1 56 } 57 return 0 - 1 58} 59 60// parse the bencoded tracker response (from boff..n): extract the "peers" compact string (6 bytes/peer: 61// 4 IP + 2 port BE) into ips[]/ports[] (ips packed b0<<24|b1<<16|b2<<8|b3, like the UDP path). -1 on no peers. 62func ht_parse_peers(buf: *u8, boff: i64, n: i64, ips: *i64, ports: *i64, max: i64) -> i64 { 63 let vo: i64 = nx_bc_dict_get(buf, boff, n, "peers" as *u8, 5) 64 if vo < 0 { return 0 - 1 } 65 let so: *i64 = sys_mmap(16) as *i64; let sl: *i64 = sys_mmap(16) as *i64 66 if nx_bc_str(buf, vo, n, so, sl) < 0 { return 0 - 1 } 67 let s: i64 = so[0]; let l: i64 = sl[0] 68 var cnt: i64 = 0; var i: i64 = 0 69 while i + 6 <= l { 70 if cnt < max { 71 let b0: i64 = buf[s+i] as i64; let b1: i64 = buf[s+i+1] as i64; let b2: i64 = buf[s+i+2] as i64; let b3: i64 = buf[s+i+3] as i64 72 let pp: i64 = ((buf[s+i+4] as i64) << 8) | (buf[s+i+5] as i64) 73 ips[cnt] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3 74 ports[cnt] = pp 75 cnt = cnt + 1 76 } 77 i = i + 6 78 } 79 return cnt 80} 81 82// HTTP tracker announce to an ALREADY-RESOLVED ip4 (host kept for the Host header). Returns peer count, -1 on fail. 83func ht_announce(host: *u8, ip4: *u8, port: i64, path: *u8, info_hash: *u8, peer_id: *u8, left: i64, ips: *i64, ports: *i64, max: i64) -> i64 { 84 let q: *u8 = sys_mmap(K_MAGIC_2048); var o: i64 = 0 85 o = ht_puts(q, o, path) 86 o = ht_puts(q, o, "?info_hash=" as *u8); o = o + ht_urlenc20(info_hash, q + o) 87 o = ht_puts(q, o, "&peer_id=" as *u8); o = o + ht_urlenc20(peer_id, q + o) 88 o = ht_puts(q, o, "&port=6881&uploaded=0&downloaded=0&compact=1&left=" as *u8); o = ht_putn(q, o, left) 89 o = ht_puts(q, o, "&event=started" as *u8); q[o] = 0 as u8 90 let addr: *u8 = sys_mmap(16); nx_http_client_sockaddr_ipv4(addr, ip4[0] as i64, ip4[1] as i64, ip4[2] as i64, ip4[3] as i64, port) 91 let resp: *u8 = sys_mmap(K_MAGIC_131072); let v: *i64 = sys_mmap(16) as *i64 92 let n: i64 = nx_http_client_get(addr, q, o, host, ht_strlen(host), resp, K_MAGIC_131072, v) 93 if n <= 0 { return 0 - 1 } 94 let boff: i64 = ht_find_body(resp, n) 95 if boff < 0 { return 0 - 1 } 96 return ht_parse_peers(resp, boff, n, ips, ports, max) 97} 98 99// convenience: parse a tracker URL, resolve it, announce (the worker calls this per magnet-tracker). 100func ht_announce_url(url: *u8, info_hash: *u8, peer_id: *u8, left: i64, ips: *i64, ports: *i64, max: i64) -> i64 { 101 let port: *i64 = sys_mmap(16) as *i64; let host: *u8 = sys_mmap(256); let path: *u8 = sys_mmap(512) 102 let scheme: i64 = tu_parse(url, port, host, path) 103 if scheme != 2 { if scheme != 3 { return 0 - 1 } } // http=2 / https=3 only (UDP handled elsewhere) 104 let ip4: *u8 = sys_mmap(4) 105 if nx_dns_a_resolve(host, ip4) != 1 { return 0 - 1 } 106 return ht_announce(host, ip4, port[0], path, info_hash, peer_id, left, ips, ports, max) 107} 108 109// ---- baked KAT: the NEW logic (urlencode + compact-peer bdecode) is deterministic + sovereign; 110// the GET itself reuses the already-proven nx_http_client. ---- 111func main() -> i64 { 112 var pass: i64 = 0; var tot: i64 = 0 113 114 let raw: *u8 = sys_mmap(20); var i: i64 = 0; while i < 20 { raw[i] = i as u8; i = i + 1 } 115 let enc: *u8 = sys_mmap(80); let el: i64 = ht_urlenc20(raw, enc) 116 var ok1: i64 = 0 117 if el == 60 { 118 if enc[0]==(37 as u8) { if enc[1]==(48 as u8) { if enc[2]==(48 as u8) { // "%00" 119 if enc[3]==(37 as u8) { if enc[4]==(48 as u8) { if enc[5]==(49 as u8) { // "%01" 120 if enc[57]==(37 as u8) { if enc[58]==(49 as u8) { if enc[59]==(51 as u8) { ok1 = 1 } } } // "%13" 121 } } } 122 } } } 123 } 124 tot = tot + 1; if ok1 == 1 { pass = pass + 1 } ht_report("urlenc20: 20 raw bytes -> %XX*20 (\"%00%01..%13\")" as *u8, ok1) 125 126 let body: *u8 = sys_mmap(128); var o: i64 = 0 127 o = ht_puts(body, o, "d8:intervali1800e5:peers6:" as *u8) 128 body[o]=1 as u8; o=o+1; body[o]=2 as u8; o=o+1; body[o]=3 as u8; o=o+1; body[o]=4 as u8; o=o+1 // IP 1.2.3.4 129 let phi: i64 = (K_MAGIC_6881 >> 8) & 0xff; let plo: i64 = K_MAGIC_6881 & 0xff 130 body[o] = phi as u8; o = o + 1; body[o] = plo as u8; o = o + 1 // port K_MAGIC_6881 BE 131 o = ht_puts(body, o, "e" as *u8) 132 let ips: *i64 = sys_mmap(8*8) as *i64; let ports: *i64 = sys_mmap(8*8) as *i64 133 let cnt: i64 = ht_parse_peers(body, 0, o, ips, ports, 8) 134 var ok2: i64 = 0 135 if cnt == 1 { if ips[0] == K_MAGIC_16909060 { if ports[0] == K_MAGIC_6881 { ok2 = 1 } } } // 0x01020304 = K_MAGIC_16909060 136 tot = tot + 1; if ok2 == 1 { pass = pass + 1 } ht_report("parse compact peers: 1.2.3.4:6881 from bencode" as *u8, ok2) 137 138 ht_p2("HTTP-TRACKER-GATE authored=organ pass=" as *u8); ht_pn2(pass); ht_p2("/" as *u8); ht_pn2(tot) 139 if pass == tot { ht_p2(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 140 ht_p2(" verdict=RED\n" as *u8); sys_exit(1); return 1 141}