code wiki / (root) / nx_peer_ext_handshake.nx

nx_peer_ext_handshake.nx source

↩ module page · 138 lines · 7110 B

1// nx_peer_ext_handshake.nx -- BEP-10 extension-protocol handshake (X-TORRENT-LIVE-001 R3a): the 2// gateway to BEP-9 ut_metadata (fetch the info-dict for a magnet). After the BEP-3 handshake with 3// the extension bit set (reserved[5] |= 0x10), peers exchange an extended message id=20, ext-id=0, 4// payload = a bencoded dict advertising their extensions: {m:{ut_metadata:<id>}, metadata_size:N}. 5// This rung exchanges them over loopback and PARSES the peer's ut_metadata ext-id + metadata_size 6// (via nx_bencode: nx_bc_dict_get + nx_bc_int). Reuses nx_peerwire (BEP-3 + nx_pw_build_msg) + 7// nx_bencode (DECODE). GATE = SOVEREIGN LOOPBACK; the small bencoded dicts are built BY HAND (no 8// encoder needed). license_tier: ORIGINAL 9// 10// module: nishi-core.torrent.peer_ext_handshake 11// depends: nishi-core.torrent.peerwire, nishi-core.torrent.bencode 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" 15const PW_MAGIC_53431: i64 = 53431 16const PW_MAGIC_1234: i64 = 1234 17 18const PW_EXTENDED: i64 = 20 19 20func eh_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 } 21func eh_wn(fd: i64, v: i64) -> i64 { 22 let t: *u8=sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)} 23 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} 24 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 25} 26func eh_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 27func eh_sockaddr(sa: *u8, port: i64, i0: i64, i1: i64, i2: i64, i3: i64) -> i64 { 28 sa[0]=2 as u8; sa[1]=0 as u8 29 sa[2]=((port>>8)&0xff) as u8; sa[3]=(port&0xff) as u8 30 sa[4]=i0 as u8; sa[5]=i1 as u8; sa[6]=i2 as u8; sa[7]=i3 as u8 31 var k: i64=8; while k<16 { sa[k]=0 as u8; k=k+1 } 32 return 0 33} 34func eh_read_n(fd: i64, buf: *u8, n: i64) -> i64 { 35 var got: i64 = 0 36 while got < n { let r: i64 = sys_read(fd, buf + got, n - got); if r <= 0 { return 0 - 1 } got = got + r } 37 return got 38} 39func eh_write_n(fd: i64, buf: *u8, n: i64) -> i64 { 40 var off: i64 = 0 41 while off < n { let w: i64 = sys_write(fd, buf + off, n - off); if w <= 0 { return 0 - 1 } off = off + w } 42 return n 43} 44func eh_read_msg(fd: i64, mb: *u8, cap: i64) -> i64 { 45 if eh_read_n(fd, mb, 4) != 4 { return 0 - 1 } 46 let blen: i64 = _pw_get_u32(mb, 0) 47 if blen == 0 { return 0 } 48 if blen > cap - 4 { return 0 - 1 } 49 if eh_read_n(fd, mb + 4, blen) != blen { return 0 - 1 } 50 return blen 51} 52// build an extended message (id=20): payload = [ext_id] + bencoded; returns total bytes in out. 53func eh_build_ext(ext_id: i64, ben: *u8, out: *u8) -> i64 { 54 let bl: i64 = eh_len(ben) 55 let pl: *u8 = sys_mmap(512) 56 pl[0] = ext_id as u8 57 var i: i64 = 0; while i < bl { pl[1 + i] = ben[i]; i = i + 1 } 58 return nx_pw_build_msg(PW_EXTENDED, pl, 1 + bl, out) 59} 60 61func main() -> i64 { 62 let PORT: i64 = PW_MAGIC_53431 63 let ih: *u8 = sys_mmap(20); var z: i64 = 0; while z < 20 { ih[z] = (z+1) as u8; z = z + 1 } 64 let pidb: *u8 = sys_mmap(20); z = 0; while z < 20 { pidb[z] = 80 as u8; z = z + 1 } 65 let sa: *u8 = sys_mmap(16); eh_sockaddr(sa, PORT, 127, 0, 0, 1) 66 // peer advertises ut_metadata=2, metadata_size=1234 67 let peer_ben: *u8 = "d1:md11:ut_metadatai2ee13:metadata_sizei1234ee" as *u8 68 let cli_ben: *u8 = "d1:md11:ut_metadatai1eee" as *u8 69 70 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 71 var bound: i64 = 0 72 if lfd >= 0 { 73 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 74 sys_setsockopt(lfd, SOL_SOCKET, 2, one, 4) 75 sys_set_socket_timeout(lfd, 3) 76 if sys_bind(lfd, sa, 16) >= 0 { if sys_listen(lfd, 1) >= 0 { bound = 1 } } 77 } 78 if bound == 0 { eh_w(1, "EXTHS-GATE authored=organ bound=0 verdict=RED\n" as *u8); sys_exit(1); return 1 } 79 80 let pid: i64 = sys_fork() 81 if pid == 0 { 82 // MOCK PEER 83 let afd: i64 = sys_accept(lfd) 84 if afd >= 0 { 85 sys_set_socket_timeout(afd, 3) 86 let hb: *u8 = sys_mmap(128); eh_read_n(afd, hb, 68) 87 let oh: *u8 = sys_mmap(128); nx_pw_build_handshake(ih, pidb, oh); oh[25] = (oh[25] as i64 | 0x10) as u8; eh_write_n(afd, oh, 68) 88 let mb: *u8 = sys_mmap(512); eh_read_msg(afd, mb, 512) // client ext handshake 89 let om: *u8 = sys_mmap(512); let oml: i64 = eh_build_ext(0, peer_ben, om); eh_write_n(afd, om, oml) 90 sys_close(afd) 91 } 92 sys_close(lfd) 93 sys_exit(0) 94 } 95 96 // CLIENT 97 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 98 sys_set_socket_timeout(cfd, 3) 99 var conn_ok: i64 = 0 100 if nx_connect_bounded(cfd, sa, 16, NX_CONN_DEFAULT_MS) >= 0 { conn_ok = 1 } 101 var hs_ok: i64 = 0; var ext_ok: i64 = 0; var utm_ok: i64 = 0; var size_ok: i64 = 0 102 if conn_ok == 1 { 103 let ch: *u8 = sys_mmap(128); nx_pw_build_handshake(ih, pidb, ch); ch[25] = (ch[25] as i64 | 0x10) as u8; eh_write_n(cfd, ch, 68) 104 let ph2: *u8 = sys_mmap(128) 105 if eh_read_n(cfd, ph2, 68) == 68 { 106 let gih: *u8 = sys_mmap(20); let gpid: *u8 = sys_mmap(20) 107 if nx_pw_parse_handshake(ph2, 68, gih, gpid) == 1 { hs_ok = 1 } 108 } 109 if hs_ok == 1 { 110 let cm: *u8 = sys_mmap(512); let cml: i64 = eh_build_ext(0, cli_ben, cm); eh_write_n(cfd, cm, cml) 111 let mb: *u8 = sys_mmap(512); let blen: i64 = eh_read_msg(cfd, mb, 512) 112 // mb[4]=msg id(20), mb[5]=ext id(0), mb[6..]=bencoded dict; n=4+blen 113 if blen > 2 { if nx_pw_msg_id(mb) == PW_EXTENDED { if (mb[5] as i64) == 0 { 114 ext_ok = 1 115 let ntot: i64 = 4 + blen 116 let m_off: i64 = nx_bc_dict_get(mb, 6, ntot, "m" as *u8, 1) 117 if m_off >= 0 { 118 let utm_off: i64 = nx_bc_dict_get(mb, m_off, ntot, "ut_metadata" as *u8, 11) 119 if utm_off >= 0 { let iv: *i64 = sys_mmap(16) as *i64; if nx_bc_int(mb, utm_off, ntot, iv) >= 0 { if iv[0] == 2 { utm_ok = 1 } } } 120 } 121 let ms_off: i64 = nx_bc_dict_get(mb, 6, ntot, "metadata_size" as *u8, 13) 122 if ms_off >= 0 { let iv2: *i64 = sys_mmap(16) as *i64; if nx_bc_int(mb, ms_off, ntot, iv2) >= 0 { if iv2[0] == PW_MAGIC_1234 { size_ok = 1 } } } 123 } } } 124 } 125 } 126 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0); sys_close(cfd); sys_close(lfd) 127 128 eh_w(1, "EXTHS-GATE authored=organ conn_ok=" as *u8); eh_wn(1, conn_ok) 129 eh_w(1, " handshake_ok=" as *u8); eh_wn(1, hs_ok) 130 eh_w(1, " ext_ok=" as *u8); eh_wn(1, ext_ok) 131 eh_w(1, " ut_metadata_id_ok=" as *u8); eh_wn(1, utm_ok) 132 eh_w(1, " metadata_size_ok=" as *u8); eh_wn(1, size_ok) 133 var allok: i64 = 0 134 if conn_ok==1 { if hs_ok==1 { if ext_ok==1 { if utm_ok==1 { if size_ok==1 { allok = 1 } } } } } 135 if allok == 1 { eh_w(1, " verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 136 eh_w(1, " verdict=RED\n" as *u8); sys_exit(1) 137 return 1 138}