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}