nx_dht.nx source
↩ module page · 185 lines · 11635 B
1// nx_dht.nx -- SOVEREIGN DHT (BEP-5 / Kademlia) KRPC primitives (X-TORRENT-LIVE-002 R4 foundation).
2// WHY: the operator's magnets are TRACKERLESS (magnet:?xt=urn:btih:..&dn=.. with no tr=). The ONLY
3// way to find peers for a trackerless magnet is the DHT -- a global Kademlia network queried with
4// KRPC (bencode over UDP). This rung = the message layer: build ping/get_peers queries + parse the
5// responses (values=peers, nodes=closer-nodes, token). The team's own organ speaks the protocol;
6// nothing external decides. Composes nx_bencode. UDP transport + iterative lookup = next rungs.
7//
8// KRPC (BEP-5), keys bencode-sorted:
9// ping q: d1:ad2:id20:<nid>e1:q4:ping1:t2:<tx>1:y1:qe
10// get_peers q: d1:ad2:id20:<nid>9:info_hash20:<ih>e1:q9:get_peers1:t2:<tx>1:y1:qe
11// response: d1:rd2:id20:<id>[5:token..][6:valuesl6:<peer>..e | 5:nodes<26B*k>]e1:t2:<tx>1:y1:re
12// license_tier: ORIGINAL layer: peer-discovery (trackerless)
13// module: nishi-core.torrent.dht
14// depends: nishi-core.bencode
15import "nx_bencode.nx"
16const K_MAGIC_6881: i64 = 6881
17const K_MAGIC_16909060: i64 = 16909060
18
19func dht_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
20func dht_put(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 }
21func dht_putraw(dst: *u8, off: i64, raw: *u8, len: i64) -> i64 { var i: i64 = 0; while i < len { dst[off+i] = raw[i]; i = i + 1 } return off + len }
22func dht_putn(dst: *u8, off: i64, v: i64) -> i64 { if v==0 { dst[off]=48 as u8; return off+1 } let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1} var o: i64=off; var i: i64=k-1; while i>=0 {dst[o]=t[i];o=o+1;i=i-1} return o }
23func dht_p2(s: *u8) -> i64 { sys_write(1, s, dht_strlen(s)); return 0 }
24func dht_pn2(v: i64) -> i64 { let b: *u8 = sys_mmap(28); var m: i64 = v; var k: i64 = 0; if m == 0 { b[0] = 48 as u8; k = 1 } let t: *u8 = sys_mmap(28); while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; let o: *u8 = sys_mmap(28); while i < k { o[i] = t[k-1-i]; i = i + 1 } sys_write(1, o, k); return 0 }
25func dht_report(label: *u8, ok: i64) -> i64 { if ok == 1 { dht_p2(" [PASS] " as *u8) } else { dht_p2(" [FAIL] " as *u8) } dht_p2(label); dht_p2("\n" as *u8); return 0 }
26
27// build a KRPC ping query. nid = our 20-byte node id, tx = 2-byte transaction id. returns length.
28func dht_build_ping(nid: *u8, tx: *u8, out: *u8) -> i64 {
29 var o: i64 = 0
30 o = dht_put(out, o, "d1:ad2:id20:" as *u8); o = dht_putraw(out, o, nid, 20)
31 o = dht_put(out, o, "e1:q4:ping1:t2:" as *u8); o = dht_putraw(out, o, tx, 2)
32 o = dht_put(out, o, "1:y1:qe" as *u8)
33 return o
34}
35// build a KRPC get_peers query for info_hash ih (20 bytes). returns length.
36func dht_build_get_peers(nid: *u8, ih: *u8, tx: *u8, out: *u8) -> i64 {
37 var o: i64 = 0
38 o = dht_put(out, o, "d1:ad2:id20:" as *u8); o = dht_putraw(out, o, nid, 20)
39 o = dht_put(out, o, "9:info_hash20:" as *u8); o = dht_putraw(out, o, ih, 20)
40 o = dht_put(out, o, "e1:q9:get_peers1:t2:" as *u8); o = dht_putraw(out, o, tx, 2)
41 o = dht_put(out, o, "1:y1:qe" as *u8)
42 return o
43}
44
45// build a KRPC announce_peer query (BEP-5): tells the node "a peer at <our external ip>:<port> holds ih".
46// token = the opaque token from a PRIOR get_peers response to that same node (proves we queried it recently).
47// a-dict keys bencode-sorted: id < info_hash < port < token. returns length.
48func dht_build_announce_peer(nid: *u8, ih: *u8, port: i64, token: *u8, tlen: i64, tx: *u8, out: *u8) -> i64 {
49 var o: i64 = 0
50 o = dht_put(out, o, "d1:ad2:id20:" as *u8); o = dht_putraw(out, o, nid, 20)
51 o = dht_put(out, o, "9:info_hash20:" as *u8); o = dht_putraw(out, o, ih, 20)
52 o = dht_put(out, o, "4:porti" as *u8); o = dht_putn(out, o, port); out[o]=101 as u8; o=o+1 // porti<port>e
53 o = dht_put(out, o, "5:token" as *u8); o = dht_putn(out, o, tlen); out[o]=58 as u8; o=o+1; o = dht_putraw(out, o, token, tlen) // token<tlen>:<bytes>
54 o = dht_put(out, o, "e1:q13:announce_peer1:t2:" as *u8); o = dht_putraw(out, o, tx, 2)
55 o = dht_put(out, o, "1:y1:qe" as *u8)
56 return o
57}
58// extract the opaque "token" from a get_peers response -> out (raw). returns token length, or -1 if absent.
59func dht_parse_token(buf: *u8, n: i64, out: *u8, max: i64) -> i64 {
60 let r: i64 = nx_bc_dict_get(buf, 0, n, "r" as *u8, 1)
61 if r < 0 { return 0-1 }
62 let to: i64 = nx_bc_dict_get(buf, r, n, "token" as *u8, 5)
63 if to < 0 { return 0-1 }
64 let so: *i64 = sys_mmap(16) as *i64; let sl: *i64 = sys_mmap(16) as *i64
65 if nx_bc_str(buf, to, n, so, sl) < 0 { return 0-1 }
66 let s: i64 = so[0]; var l: i64 = sl[0]; if l > max { l = max }
67 var i: i64 = 0; while i < l { out[i] = buf[s+i]; i = i + 1 }
68 return l
69}
70// is this a KRPC RESPONSE (y=r, has "r" dict) rather than an error? used to ack an announce_peer.
71func dht_is_response(buf: *u8, n: i64) -> i64 { if nx_bc_dict_get(buf, 0, n, "r" as *u8, 1) >= 0 { return 1 } return 0 }
72
73// parse the "values" peer list from a KRPC response -> ips[]/ports[] (compact 6B/peer). returns count
74// (0 if no values, -1 if not a valid response). ips packed b0<<24|b1<<16|b2<<8|b3 (UDP-path convention).
75func dht_parse_values(buf: *u8, n: i64, ips: *i64, ports: *i64, max: i64) -> i64 {
76 let r: i64 = nx_bc_dict_get(buf, 0, n, "r" as *u8, 1)
77 if r < 0 { return 0 - 1 }
78 let vo: i64 = nx_bc_dict_get(buf, r, n, "values" as *u8, 6)
79 if vo < 0 { return 0 }
80 if buf[vo] != (108 as u8) { return 0 } // 'l' = list
81 var o: i64 = vo + 1; var cnt: i64 = 0
82 let so: *i64 = sys_mmap(16) as *i64; let sl: *i64 = sys_mmap(16) as *i64
83 while o < n {
84 if buf[o] == (101 as u8) { o = n } else { // 'e' ends the list
85 if nx_bc_str(buf, o, n, so, sl) < 0 { o = n } else {
86 if sl[0] == 6 { if cnt < max {
87 let s: i64 = so[0]
88 let b0: i64 = buf[s] as i64; let b1: i64 = buf[s+1] as i64; let b2: i64 = buf[s+2] as i64; let b3: i64 = buf[s+3] as i64
89 ips[cnt] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3
90 ports[cnt] = ((buf[s+4] as i64) << 8) | (buf[s+5] as i64)
91 cnt = cnt + 1
92 } }
93 o = nx_bc_skip(buf, o, n)
94 }
95 }
96 }
97 return cnt
98}
99
100// parse the "nodes" compact list (26B each: 20 id + 4 ip + 2 port) -> node ip4s/ports for iterative
101// lookup. returns count. (kademlia walk toward the info_hash uses these when "values" is absent.)
102func dht_parse_nodes(buf: *u8, n: i64, ips: *i64, ports: *i64, max: i64) -> i64 {
103 let r: i64 = nx_bc_dict_get(buf, 0, n, "r" as *u8, 1)
104 if r < 0 { return 0 - 1 }
105 let no: i64 = nx_bc_dict_get(buf, r, n, "nodes" as *u8, 5)
106 if no < 0 { return 0 }
107 let so: *i64 = sys_mmap(16) as *i64; let sl: *i64 = sys_mmap(16) as *i64
108 if nx_bc_str(buf, no, n, so, sl) < 0 { return 0 }
109 let s: i64 = so[0]; let l: i64 = sl[0]
110 var cnt: i64 = 0; var i: i64 = 0
111 while i + 26 <= l {
112 if cnt < max {
113 let p: i64 = s + i + 20 // skip the 20-byte node id -> ip:port
114 let b0: i64 = buf[p] as i64; let b1: i64 = buf[p+1] as i64; let b2: i64 = buf[p+2] as i64; let b3: i64 = buf[p+3] as i64
115 ips[cnt] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3
116 ports[cnt] = ((buf[p+4] as i64) << 8) | (buf[p+5] as i64)
117 cnt = cnt + 1
118 }
119 i = i + 26
120 }
121 return cnt
122}
123
124// ---- baked KAT: deterministic + sovereign (no network). proves the KRPC wire format + value parse. ----
125func main() -> i64 {
126 var pass: i64 = 0; var tot: i64 = 0
127 let nid: *u8 = sys_mmap(20); var i: i64 = 0; while i < 20 { nid[i] = 0xaa as u8; i = i + 1 }
128 let ih: *u8 = sys_mmap(20); i = 0; while i < 20 { ih[i] = 0xbb as u8; i = i + 1 }
129 let tx: *u8 = sys_mmap(2); tx[0] = 97 as u8; tx[1] = 98 as u8 // "ab"
130
131 // KAT1: ping query well-formed
132 let pbuf: *u8 = sys_mmap(128); let pl: i64 = dht_build_ping(nid, tx, pbuf)
133 var ok1: i64 = 0
134 // d1:ad2:id20:<20>e1:q4:ping1:t2:ab1:y1:qe -- check structure (top dict + q + a keys), not brittle length
135 if pl > 40 { if pbuf[0]==(100 as u8) { if nx_bc_dict_get(pbuf, 0, pl, "q" as *u8, 1) >= 0 { if nx_bc_dict_get(pbuf, 0, pl, "a" as *u8, 1) >= 0 { ok1 = 1 } } } }
136 tot = tot + 1; if ok1 == 1 { pass = pass + 1 } dht_report("build ping: well-formed KRPC (top dict + q + a)" as *u8, ok1)
137
138 // KAT2: get_peers query carries the info_hash
139 let gbuf: *u8 = sys_mmap(128); let gl: i64 = dht_build_get_peers(nid, ih, tx, gbuf)
140 var ok2: i64 = 0
141 let qv: i64 = nx_bc_dict_get(gbuf, 0, gl, "q" as *u8, 1)
142 let av: i64 = nx_bc_dict_get(gbuf, 0, gl, "a" as *u8, 1)
143 if qv >= 0 { if av >= 0 { if nx_bc_dict_get(gbuf, av, gl, "info_hash" as *u8, 9) >= 0 { ok2 = 1 } } }
144 tot = tot + 1; if ok2 == 1 { pass = pass + 1 } dht_report("build get_peers: a.info_hash present" as *u8, ok2)
145
146 // KAT3: parse a response with one value peer 1.2.3.4:6881
147 let rbuf: *u8 = sys_mmap(256); var o: i64 = 0
148 o = dht_put(rbuf, o, "d1:rd2:id20:" as *u8); o = dht_putraw(rbuf, o, nid, 20)
149 o = dht_put(rbuf, o, "5:token2:zz6:valuesl6:" as *u8)
150 rbuf[o]=1 as u8; o=o+1; rbuf[o]=2 as u8; o=o+1; rbuf[o]=3 as u8; o=o+1; rbuf[o]=4 as u8; o=o+1
151 let phi: i64 = (K_MAGIC_6881 >> 8) & 0xff; let plo: i64 = K_MAGIC_6881 & 0xff
152 rbuf[o] = phi as u8; o = o + 1; rbuf[o] = plo as u8; o = o + 1
153 o = dht_put(rbuf, o, "ee1:t2:ab1:y1:re" as *u8)
154 let ips: *i64 = sys_mmap(8*16) as *i64; let ports: *i64 = sys_mmap(8*16) as *i64
155 let cnt: i64 = dht_parse_values(rbuf, o, ips, ports, 16)
156 var ok3: i64 = 0
157 if cnt == 1 { if ips[0] == K_MAGIC_16909060 { if ports[0] == K_MAGIC_6881 { ok3 = 1 } } }
158 tot = tot + 1; if ok3 == 1 { pass = pass + 1 } dht_report("parse response values: 1.2.3.4:6881" as *u8, ok3)
159
160 // KAT4: announce_peer query carries info_hash + port(=6881) + token, keys sorted, q=announce_peer
161 let tok: *u8 = sys_mmap(8); tok[0]=122 as u8; tok[1]=122 as u8 // "zz" (as returned by KAT3's response)
162 let abuf: *u8 = sys_mmap(160); let al: i64 = dht_build_announce_peer(nid, ih, K_MAGIC_6881, tok, 2, tx, abuf)
163 var ok4: i64 = 0
164 let aav: i64 = nx_bc_dict_get(abuf, 0, al, "a" as *u8, 1)
165 let aqv: i64 = nx_bc_dict_get(abuf, 0, al, "q" as *u8, 1)
166 if aav >= 0 { if aqv >= 0 {
167 let ihp: i64 = nx_bc_dict_get(abuf, aav, al, "info_hash" as *u8, 9)
168 let prt: i64 = nx_bc_dict_get(abuf, aav, al, "port" as *u8, 4)
169 let tkp: i64 = nx_bc_dict_get(abuf, aav, al, "token" as *u8, 5)
170 if ihp >= 0 { if prt >= 0 { if tkp >= 0 {
171 let iv: *i64 = sys_mmap(8) as *i64
172 nx_bc_int(abuf, prt, al, iv); if iv[0] == K_MAGIC_6881 { ok4 = 1 }
173 } } }
174 } }
175 tot = tot + 1; if ok4 == 1 { pass = pass + 1 } dht_report("build announce_peer: a.{info_hash,port=6881,token}" as *u8, ok4)
176
177 // KAT5: parse the token back out of KAT3's get_peers response ("2:zz")
178 let tkb: *u8 = sys_mmap(32); let tkl: i64 = dht_parse_token(rbuf, o, tkb, 32)
179 var ok5: i64 = 0; if tkl == 2 { if tkb[0]==(122 as u8) { if tkb[1]==(122 as u8) { ok5 = 1 } } }
180 tot = tot + 1; if ok5 == 1 { pass = pass + 1 } dht_report("parse token from get_peers response: zz" as *u8, ok5)
181
182 dht_p2("DHT-KRPC-GATE authored=organ pass=" as *u8); dht_pn2(pass); dht_p2("/" as *u8); dht_pn2(tot)
183 if pass == tot { dht_p2(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
184 dht_p2(" verdict=RED\n" as *u8); sys_exit(1); return 1
185}