code wiki / (root) / nx_peer_metadata.nx

nx_peer_metadata.nx source

↩ module page · 182 lines · 10540 B

1// nx_peer_metadata.nx -- BEP-9 ut_metadata FETCH + sha1-verify the info-dict (X-TORRENT-LIVE-001 2// R3b): COMPLETES the engine. A magnet has no .torrent, so the client fetches the info-dict from a 3// peer over BEP-10/BEP-9: ext handshake -> learn ut_metadata id + metadata_size -> request each 4// metadata piece -> peer replies a bencoded header + RAW info-dict bytes -> assemble -> the BEP-9 5// integrity check sha1(info-dict)==info_hash -> nx_bc_dict_get the piece map (name/piece length/ 6// length). Reuses nx_peerwire + nx_bencode + nx_sha1. GATE = SOVEREIGN LOOPBACK: a synthetic 7// info-dict whose sha1 IS the handshake info_hash; the mock serves it; the client fetches, 8// assembles, verifies, and parses. license_tier: ORIGINAL 9// 10// module: nishi-core.torrent.peer_metadata 11// depends: nishi-core.torrent.peerwire, nishi-core.torrent.bencode, nishi-core.crypto.sha1 12import "nx_peerwire.nx" 13import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 14import "nx_bencode.nx" 15import "nx_sha1.nx" 16const PW_MAGIC_65536: i64 = 65536 17const PW_MAGIC_53461: i64 = 53461 18const PW_MAGIC_1024: i64 = 1024 19const PW_MAGIC_2048: i64 = 2048 20 21const PW_EXTENDED: i64 = 20 22 23func md_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 24func md_wn(fd: i64, v: i64) -> i64 { 25 let t: *u8=sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)} 26 var k: i64=0; if m==0 {t[0]=48 as u8;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1} 27 let b: *u8=sys_mmap(28); var i: i64=0; while i<k {b[i]=t[k-1-i]; i=i+1}; sys_write(fd,b,k); return 0 28} 29func md_bstr(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8) { buf[off+i]=s[i]; i=i+1 } return off+i } 30func md_bint(buf: *u8, off: i64, v: i64) -> i64 { 31 let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0 {t[0]=48 as u8;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1} 32 var o: i64=off; var j: i64=0; while j<k { buf[o]=t[k-1-j]; o=o+1; j=j+1 } return o 33} 34func md_sockaddr(sa: *u8, port: i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64 { 35 sa[0]=2 as u8; sa[1]=0 as u8 36 sa[2]=((port>>8)&0xff) as u8; sa[3]=(port&0xff) as u8 37 sa[4]=i0 as u8; sa[5]=i1 as u8; sa[6]=i2 as u8; sa[7]=i3 as u8 38 var k: i64=8; while k<16 { sa[k]=0 as u8; k=k+1 } 39 return 0 40} 41func md_read_n(fd: i64, buf: *u8, n: i64) -> i64 { 42 var got: i64 = 0 43 while got < n { let r: i64 = sys_read(fd, buf + got, n - got); if r <= 0 { return 0 - 1 } got = got + r } 44 return got 45} 46func md_write_n(fd: i64, buf: *u8, n: i64) -> i64 { 47 var off: i64 = 0 48 while off < n { let w: i64 = sys_write(fd, buf + off, n - off); if w <= 0 { return 0 - 1 } off = off + w } 49 return n 50} 51func md_read_msg(fd: i64, mb: *u8, cap: i64) -> i64 { 52 if md_read_n(fd, mb, 4) != 4 { return 0 - 1 } 53 let blen: i64 = _pw_get_u32(mb, 0) 54 if blen == 0 { return 0 } 55 if blen > cap - 4 { return 0 - 1 } 56 if md_read_n(fd, mb + 4, blen) != blen { return 0 - 1 } 57 return blen 58} 59// extended message id=20 with EXPLICIT data length (data may contain NUL -- raw metadata). out=msg. 60func md_build_ext(ext_id: i64, data: *u8, dlen: i64, out: *u8) -> i64 { 61 let pl: *u8 = sys_mmap(PW_MAGIC_65536) 62 pl[0] = ext_id as u8 63 var i: i64 = 0; while i < dlen { pl[1 + i] = data[i]; i = i + 1 } 64 return nx_pw_build_msg(PW_EXTENDED, pl, 1 + dlen, out) 65} 66 67func main() -> i64 { 68 let PORT: i64 = PW_MAGIC_53461 69 // synthetic info-dict; info_hash = sha1(info-dict) (BEP-9 identity) 70 let idd: *u8 = sys_mmap(512) 71 var p: i64 = md_bstr(idd, 0, "d6:lengthi32e4:name8:test.bin12:piece lengthi16384e6:pieces20:" as *u8) 72 var i: i64 = 0; while i < 20 { idd[p] = (i+1) as u8; p = p + 1; i = i + 1 } 73 idd[p] = 101 as u8; p = p + 1 // 'e' closes the dict 74 let N: i64 = p 75 let info_hash: *u8 = sys_mmap(20); sha1(idd, N, info_hash) 76 let pidb: *u8 = sys_mmap(20); var z: i64 = 0; while z < 20 { pidb[z] = 80 as u8; z = z + 1 } 77 let sa: *u8 = sys_mmap(16); md_sockaddr(sa, PORT, 127, 0, 0, 1) 78 79 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 80 var bound: i64 = 0 81 if lfd >= 0 { 82 let one: *u8 = sys_mmap(4); one[0]=1 as u8; one[1]=0 as u8; one[2]=0 as u8; one[3]=0 as u8 83 sys_setsockopt(lfd, SOL_SOCKET, 2, one, 4) 84 sys_set_socket_timeout(lfd, 3) 85 if sys_bind(lfd, sa, 16) >= 0 { if sys_listen(lfd, 1) >= 0 { bound = 1 } } 86 } 87 if bound == 0 { md_w(1, "META-GATE authored=organ bound=0 verdict=RED\n" as *u8); sys_exit(1); return 1 } 88 89 let pid: i64 = sys_fork() 90 if pid == 0 { 91 // MOCK PEER 92 let afd: i64 = sys_accept(lfd) 93 if afd >= 0 { 94 sys_set_socket_timeout(afd, 3) 95 let hb: *u8 = sys_mmap(128); md_read_n(afd, hb, 68) 96 let oh: *u8 = sys_mmap(128); nx_pw_build_handshake(info_hash, pidb, oh); oh[25] = (oh[25] as i64 | 0x10) as u8; md_write_n(afd, oh, 68) 97 let mb: *u8 = sys_mmap(PW_MAGIC_1024); md_read_msg(afd, mb, PW_MAGIC_1024) // client ext handshake 98 // mock ext handshake: ut_metadata=2, metadata_size=N 99 let eb: *u8 = sys_mmap(256) 100 var o: i64 = md_bstr(eb, 0, "d1:md11:ut_metadatai2ee13:metadata_sizei" as *u8) 101 o = md_bint(eb, o, N); o = md_bstr(eb, o, "ee" as *u8) 102 let om: *u8 = sys_mmap(512); let oml: i64 = md_build_ext(0, eb, o, om); md_write_n(afd, om, oml) 103 md_read_msg(afd, mb, PW_MAGIC_1024) // client ut_metadata request 104 // ut_metadata data: header + RAW info-dict 105 let db: *u8 = sys_mmap(PW_MAGIC_1024) 106 var d: i64 = md_bstr(db, 0, "d8:msg_typei1e5:piecei0e10:total_sizei" as *u8) 107 d = md_bint(db, d, N); d = md_bstr(db, d, "ee" as *u8) 108 var j: i64 = 0; while j < N { db[d + j] = idd[j]; j = j + 1 } 109 let dm: *u8 = sys_mmap(PW_MAGIC_2048); let dml: i64 = md_build_ext(1, db, d + N, dm); md_write_n(afd, dm, dml) 110 sys_close(afd) 111 } 112 sys_close(lfd) 113 sys_exit(0) 114 } 115 116 // CLIENT 117 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 118 sys_set_socket_timeout(cfd, 3) 119 var conn_ok: i64 = 0 120 if nx_connect_bounded(cfd, sa, 16, NX_CONN_DEFAULT_MS) >= 0 { conn_ok = 1 } 121 var hs_ok: i64 = 0; var size_ok: i64 = 0; var fetched: i64 = 0; var verify: i64 = 0; var name_ok: i64 = 0 122 if conn_ok == 1 { 123 let ch: *u8 = sys_mmap(128); nx_pw_build_handshake(info_hash, pidb, ch); ch[25] = (ch[25] as i64 | 0x10) as u8; md_write_n(cfd, ch, 68) 124 let ph2: *u8 = sys_mmap(128) 125 if md_read_n(cfd, ph2, 68) == 68 { 126 let gih: *u8 = sys_mmap(20); let gpid: *u8 = sys_mmap(20) 127 if nx_pw_parse_handshake(ph2, 68, gih, gpid) == 1 { hs_ok = 1 } 128 } 129 if hs_ok == 1 { 130 // client ext handshake (ut_metadata=1) 131 let ceb: *u8 = sys_mmap(64); let cebl: i64 = md_bstr(ceb, 0, "d1:md11:ut_metadatai1eee" as *u8) 132 let cm: *u8 = sys_mmap(256); let cml: i64 = md_build_ext(0, ceb, cebl, cm); md_write_n(cfd, cm, cml) 133 let mb: *u8 = sys_mmap(PW_MAGIC_2048); let blen: i64 = md_read_msg(cfd, mb, PW_MAGIC_2048) 134 var utm_id: i64 = 0; var msize: i64 = 0 135 if blen > 2 { if nx_pw_msg_id(mb) == PW_EXTENDED { if (mb[5] as i64) == 0 { 136 let ntot: i64 = 4 + blen 137 let m_off: i64 = nx_bc_dict_get(mb, 6, ntot, "m" as *u8, 1) 138 if m_off >= 0 { let uo: i64 = nx_bc_dict_get(mb, m_off, ntot, "ut_metadata" as *u8, 11); if uo >= 0 { let iv: *i64 = sys_mmap(16) as *i64; if nx_bc_int(mb, uo, ntot, iv) >= 0 { utm_id = iv[0] } } } 139 let so: i64 = nx_bc_dict_get(mb, 6, ntot, "metadata_size" as *u8, 13); if so >= 0 { let iv2: *i64 = sys_mmap(16) as *i64; if nx_bc_int(mb, so, ntot, iv2) >= 0 { msize = iv2[0] } } 140 } } } 141 if msize == N { size_ok = 1 } 142 if utm_id > 0 { 143 // request metadata piece 0 144 let rqb: *u8 = sys_mmap(64); let rqbl: i64 = md_bstr(rqb, 0, "d8:msg_typei0e5:piecei0ee" as *u8) 145 let rm: *u8 = sys_mmap(128); let rml: i64 = md_build_ext(utm_id, rqb, rqbl, rm); md_write_n(cfd, rm, rml) 146 // read data msg 147 let db2: *u8 = sys_mmap(PW_MAGIC_2048); let dblen: i64 = md_read_msg(cfd, db2, PW_MAGIC_2048) 148 if dblen > 2 { if nx_pw_msg_id(db2) == PW_EXTENDED { if (db2[5] as i64) == 1 { 149 let dtot: i64 = 4 + dblen 150 let raw_off: i64 = nx_bc_skip(db2, 6, dtot) // end of bencoded header = start of raw info-dict 151 if raw_off > 0 { 152 let rawlen: i64 = dtot - raw_off 153 if rawlen == N { fetched = 1 } 154 // assemble (single piece) + verify 155 let meta: *u8 = sys_mmap(512); var q: i64 = 0; while q < rawlen { meta[q] = db2[raw_off + q]; q = q + 1 } 156 let gh: *u8 = sys_mmap(20); sha1(meta, rawlen, gh) 157 var se: i64 = 1; var x: i64 = 0; while x < 20 { if gh[x] != info_hash[x] { se = 0; x = 20 } else { x = x + 1 } } 158 verify = se 159 // parse the info-dict piece map 160 let nm: i64 = nx_bc_dict_get(meta, 0, rawlen, "name" as *u8, 4) 161 if nm >= 0 { let so2: *i64 = sys_mmap(16) as *i64; let sl2: *i64 = sys_mmap(16) as *i64 162 if nx_bc_str(meta, nm, rawlen, so2, sl2) >= 0 { if sl2[0] == 8 { if meta[so2[0]] == (116 as u8) { name_ok = 1 } } } } // 't' of test.bin 163 } 164 } } } 165 } 166 } 167 } 168 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0); sys_close(cfd); sys_close(lfd) 169 170 md_w(1, "META-GATE authored=organ conn_ok=" as *u8); md_wn(1, conn_ok) 171 md_w(1, " handshake_ok=" as *u8); md_wn(1, hs_ok) 172 md_w(1, " metadata_size_ok=" as *u8); md_wn(1, size_ok) 173 md_w(1, " fetched_len_ok=" as *u8); md_wn(1, fetched) 174 md_w(1, " sha1_eq_info_hash=" as *u8); md_wn(1, verify) 175 md_w(1, " name_parsed=" as *u8); md_wn(1, name_ok) 176 md_w(1, " N=" as *u8); md_wn(1, N) 177 var allok: i64 = 0 178 if conn_ok==1 { if hs_ok==1 { if size_ok==1 { if fetched==1 { if verify==1 { if name_ok==1 { allok = 1 } } } } } } 179 if allok == 1 { md_w(1, " verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 180 md_w(1, " verdict=RED\n" as *u8); sys_exit(1) 181 return 1 182}