code wiki / _hdl_build / nx_socks5_client_gate.nx

nx_socks5_client_gate.nx source

↩ module page · 216 lines · 12354 B

1// nx_socks5_client_gate.nx -- GATE for the sovereign SOCKS5 client + the anon transport interface. 2// TWO proofs, fail-closed: 3// PART A RFC 1928 KNOWN-ANSWER TEST (pure codec, NO network): greeting + CONNECT request bytes are 4// byte-exact vs the spec; replies parse; and every negative control (wrong version, REJECT 5// method, REP!=0 refusal, truncation, bad ATYP) is REFUSED. This is the liar-kill core. 6// PART B LIVE LOOPBACK TUNNEL: fork a mock SOCKS5 server on 127.0.0.1, drive the REAL s5_connect 7// through it via anon_connect(ANON_SOCKS5,...), and prove the returned fd carries app bytes 8// end-to-end (echo round-trip). Closes "codec correct" -> "the live socket path works". 9// Plus HONESTY invariants: anon_is_anonymizing(SOCKS5)==0 and anon_connect(ANON_TOR)->NOTIMPL -- 10// the interface never pretends a bare proxy is anonymity nor fakes an unbuilt Tor backend. 11// GREEN iff every row passes. NO external network call (loopback only). Durable 12// knowledge/status/socks5_client_gate.log. license_tier: ORIGINAL expect_exit: 0 13import "nx_syscalls.nx" 14import "nx_socks5_client.nx" 15import "nx_anon_transport.nx" 16 17func g_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 18func g_n(v: i64) -> i64 { var m: i64=v; if m<0{g_w("-" as *u8);m=0-m} let t:*u8=sys_mmap(24); 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} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 } 19func g_fw(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 } 20func g_fn(fd: i64, v: i64) -> i64 { var m: i64=v; let t:*u8=sys_mmap(24); 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} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(fd,o,k); return 0 } 21 22// record one gate row: bump total, bump pass iff ok==1, print OK/FAIL. 23func g_row(id: *u8, ok: i64, pass: *i64, tot: *i64) -> i64 { 24 tot[0] = tot[0] + 1 25 g_w(" " as *u8); g_w(id) 26 if ok == 1 { g_w(": OK\n" as *u8); pass[0] = pass[0] + 1 } else { g_w(": FAIL\n" as *u8) } 27 return 0 28} 29 30// nap `ms` milliseconds via poll(NULL,0,ms) -- the sovereign bounded wait (no busy spin). 31func g_nap(ms: i64) -> i64 { sys_poll(0 as *u8, 0, ms); return 0 } 32 33// byte-compare buf[0..n) vs exp[0..n); 1 if identical, else 0. 34func g_bytes_eq(buf: *u8, exp: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if buf[i]!=exp[i] { return 0 } i=i+1 } return 1 } 35 36// ---------- PART A: RFC 1928 codec known-answer test ---------- 37func part_a(pass: *i64, tot: *i64) -> i64 { 38 g_w("-- PART A: RFC 1928 codec KAT (byte-exact + fail-closed negatives) --\n" as *u8) 39 40 // T1 greeting bytes == 05 01 00 41 let gb: *u8 = sys_mmap(8); let gn: i64 = s5_build_greeting(gb) 42 let ge: *u8 = sys_mmap(8); ge[0]=5 as u8; ge[1]=1 as u8; ge[2]=0 as u8 43 var ok: i64 = 0; if gn==3 { if g_bytes_eq(gb, ge, 3)==1 { ok=1 } } 44 g_row("T1 greeting bytes == 05 01 00" as *u8, ok, pass, tot) 45 46 // T2 method reply 05 00 -> no-auth (0) 47 let m1: *u8 = sys_mmap(4); m1[0]=5 as u8; m1[1]=0 as u8 48 ok = (s5_parse_method_reply(m1, 2) == 0) as i64 49 g_row("T2 method reply 05 00 -> no-auth selected" as *u8, ok, pass, tot) 50 51 // T3 method reply 05 FF -> REJECT (fail-closed) 52 let m2: *u8 = sys_mmap(4); m2[0]=5 as u8; m2[1]=0xff as u8 53 ok = (s5_parse_method_reply(m2, 2) < 0) as i64 54 g_row("T3 method reply 05 FF (no acceptable methods) -> REFUSED" as *u8, ok, pass, tot) 55 56 // T4 wrong version 04 00 -> refused 57 let m3: *u8 = sys_mmap(4); m3[0]=4 as u8; m3[1]=0 as u8 58 ok = (s5_parse_method_reply(m3, 2) < 0) as i64 59 g_row("T4 method reply wrong version (04) -> REFUSED" as *u8, ok, pass, tot) 60 61 // T5 truncated method reply (1 byte) -> refused 62 let m4: *u8 = sys_mmap(4); m4[0]=5 as u8 63 ok = (s5_parse_method_reply(m4, 1) < 0) as i64 64 g_row("T5 truncated method reply (1 byte) -> REFUSED" as *u8, ok, pass, tot) 65 66 // T6 CONNECT domain example.com:443 == 05 01 00 03 0B <example.com> 01 BB 67 let cb: *u8 = sys_mmap(64); let cn: i64 = s5_build_connect_domain("example.com" as *u8, 11, 443, cb) 68 let ce: *u8 = sys_mmap(64) 69 ce[0]=5 as u8; ce[1]=1 as u8; ce[2]=0 as u8; ce[3]=3 as u8; ce[4]=11 as u8 70 ce[5]=101 as u8; ce[6]=120 as u8; ce[7]=97 as u8; ce[8]=109 as u8; ce[9]=112 as u8; ce[10]=108 as u8; ce[11]=101 as u8; ce[12]=46 as u8; ce[13]=99 as u8; ce[14]=111 as u8; ce[15]=109 as u8 71 ce[16]=1 as u8; ce[17]=0xbb as u8 // port 443 = 0x01BB 72 ok = 0; if cn==18 { if g_bytes_eq(cb, ce, 18)==1 { ok=1 } } 73 g_row("T6 CONNECT domain example.com:443 byte-exact (incl port 01BB)" as *u8, ok, pass, tot) 74 75 // T7 CONNECT reply success, ATYP=IPv4 -> parsed OK 76 let r1: *u8 = sys_mmap(16); var i: i64=0; while i<10 { r1[i]=0 as u8; i=i+1 } r1[0]=5 as u8; r1[3]=1 as u8 77 ok = (s5_parse_connect_reply(r1, 10) == 0) as i64 78 g_row("T7 CONNECT reply success (ATYP=IPv4) -> parsed OK" as *u8, ok, pass, tot) 79 80 // T8 CONNECT reply REP=5 (proxy refused) -> refused 81 let r2: *u8 = sys_mmap(16); i=0; while i<10 { r2[i]=0 as u8; i=i+1 } r2[0]=5 as u8; r2[1]=5 as u8; r2[3]=1 as u8 82 ok = (s5_parse_connect_reply(r2, 10) < 0) as i64 83 g_row("T8 CONNECT reply REP=5 (proxy refused) -> REFUSED" as *u8, ok, pass, tot) 84 85 // T9 CONNECT reply success, ATYP=domain (len-prefixed) -> parsed OK ; total = 4+1+5+2 = 12 86 let r3: *u8 = sys_mmap(32); i=0; while i<12 { r3[i]=0 as u8; i=i+1 } r3[0]=5 as u8; r3[3]=3 as u8; r3[4]=5 as u8 87 ok = (s5_parse_connect_reply(r3, 12) == 0) as i64 88 g_row("T9 CONNECT reply success (ATYP=domain, len-prefixed) -> parsed OK" as *u8, ok, pass, tot) 89 90 // T10 truncated CONNECT reply (ATYP=IPv4 but only 6 bytes) -> refused 91 let r4: *u8 = sys_mmap(16); i=0; while i<6 { r4[i]=0 as u8; i=i+1 } r4[0]=5 as u8; r4[3]=1 as u8 92 ok = (s5_parse_connect_reply(r4, 6) < 0) as i64 93 g_row("T10 truncated CONNECT reply -> REFUSED" as *u8, ok, pass, tot) 94 95 // T11 CONNECT IPv4 127.0.0.1:8080 == 05 01 00 01 7F 00 00 01 1F 90 96 let ip: *u8 = sys_mmap(4); ip[0]=127 as u8; ip[1]=0 as u8; ip[2]=0 as u8; ip[3]=1 as u8 97 let ib: *u8 = sys_mmap(16); let iln: i64 = s5_build_connect_ipv4(ip, 8080, ib) 98 let ie: *u8 = sys_mmap(16); ie[0]=5 as u8; ie[1]=1 as u8; ie[2]=0 as u8; ie[3]=1 as u8; ie[4]=127 as u8; ie[5]=0 as u8; ie[6]=0 as u8; ie[7]=1 as u8; ie[8]=0x1f as u8; ie[9]=0x90 as u8 99 ok = 0; if iln==10 { if g_bytes_eq(ib, ie, 10)==1 { ok=1 } } 100 g_row("T11 CONNECT IPv4 127.0.0.1:8080 byte-exact (port 1F90)" as *u8, ok, pass, tot) 101 102 // T12 HONESTY: a bare SOCKS5 proxy is NOT anonymity 103 ok = (anon_is_anonymizing(ANON_SOCKS5) == 0) as i64 104 g_row("T12 HONESTY anon_is_anonymizing(SOCKS5)==0 (proxy alone is not anonymity)" as *u8, ok, pass, tot) 105 106 // T13 the interface routes ANON_TOR to NOTIMPL (honest stub, never a silent fake) 107 let ti: *u8 = sys_mmap(4); ti[0]=1 as u8 108 ok = (anon_connect(ANON_TOR, ti, 9050, "x" as *u8, 1, 443) == ANON_E_NOTIMPL) as i64 109 g_row("T13 anon_connect(ANON_TOR) -> NOTIMPL (no fake anonymity)" as *u8, ok, pass, tot) 110 return 0 111} 112 113// ---------- mock SOCKS5 server (child) ---------- 114// Speaks just enough RFC 1928 to accept our client: no-auth negotiation, CONNECT (any ATYP), success 115// reply, then ONE echo round. Proves the REAL client drives a real socket. Fails closed on bad input. 116func mock_socks5_server(lfd: i64) -> i64 { 117 let cfd: i64 = sys_accept(lfd) 118 if cfd < 0 { return 1 } 119 s5_set_rcv_timeout(cfd, 5) 120 // greeting: VER NMETHODS METHODS... (read 2 header bytes, then NMETHODS method bytes) 121 let hdr: *u8 = sys_mmap(8) 122 if s5_read_full(cfd, hdr, 2) < 0 { sys_close(cfd); return 1 } 123 let nm: i64 = hdr[1] as i64 124 let methods: *u8 = sys_mmap(260) 125 if nm > 0 { if s5_read_full(cfd, methods, nm) < 0 { sys_close(cfd); return 1 } } 126 // reply: select no-auth -> 05 00 127 let mr: *u8 = sys_mmap(4); mr[0]=5 as u8; mr[1]=0 as u8 128 sys_write(cfd, mr, 2) 129 // CONNECT request: VER CMD RSV ATYP (4), then addr by ATYP, then 2 port bytes. 130 let req: *u8 = sys_mmap(512) 131 if s5_read_full(cfd, req, 4) < 0 { sys_close(cfd); return 1 } 132 let atyp: i64 = req[3] as i64 133 if atyp == 3 { 134 if s5_read_full(cfd, (req as i64 + 4) as *u8, 1) < 0 { sys_close(cfd); return 1 } 135 let dl: i64 = req[4] as i64 136 if s5_read_full(cfd, (req as i64 + 5) as *u8, dl + 2) < 0 { sys_close(cfd); return 1 } 137 } else { 138 var addrn: i64 = 0 139 if atyp == 1 { addrn = 4 } 140 if atyp == 4 { addrn = 16 } 141 if s5_read_full(cfd, (req as i64 + 4) as *u8, addrn + 2) < 0 { sys_close(cfd); return 1 } 142 } 143 // reply success, bound 0.0.0.0:0 (ATYP=IPv4) -> 05 00 00 01 00 00 00 00 00 00 144 let cr: *u8 = sys_mmap(16); var i: i64=0; while i<10 { cr[i]=0 as u8; i=i+1 } cr[0]=5 as u8; cr[3]=1 as u8 145 sys_write(cfd, cr, 10) 146 // echo one app payload back through the tunnel. 147 let app: *u8 = sys_mmap(1024) 148 let an: i64 = sys_read(cfd, app, 1024) 149 if an > 0 { sys_write(cfd, app, an) } 150 sys_close(cfd) 151 return 0 152} 153 154func main() -> i64 { 155 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0 156 let tot: *i64 = sys_mmap(8) as *i64; tot[0]=0 157 g_w("=== NX-SOCKS5-CLIENT GATE (RFC 1928 CONNECT: byte-exact KAT + live loopback tunnel) ===\n" as *u8) 158 159 part_a(pass, tot) 160 161 g_w("-- PART B: live loopback -- real s5_connect through a mock SOCKS5 server on 127.0.0.1 --\n" as *u8) 162 let port: i64 = 20600 + (sys_now_ms() % 800) // clock-derived port avoids rerun collisions 163 164 // bind+listen in the PARENT (queues our connect in the backlog -> no bind race), then fork the server. 165 let addr: *u8 = sys_mmap(16) 166 addr[0]=2 as u8; addr[1]=0 as u8; addr[2]=((port>>8)&0xff) as u8; addr[3]=(port&0xff) as u8 167 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8 168 var z: i64=8; while z<16 { addr[z]=0 as u8; z=z+1 } 169 let lfd: i64 = sys_socket(2, 1, 0) 170 let optv: *u8 = sys_mmap(4); optv[0]=1 as u8; optv[1]=0 as u8; optv[2]=0 as u8; optv[3]=0 as u8 171 sys_setsockopt(lfd, 1, 2, optv, 4) // SO_REUSEADDR 172 var bound: i64 = 0 173 if sys_bind(lfd, addr, 16) == 0 { if sys_listen(lfd, 8) == 0 { bound = 1 } } 174 if bound == 0 { 175 g_row("PART B loopback bind/listen 127.0.0.1" as *u8, 0, pass, tot) 176 } else { 177 let pid: i64 = sys_fork() 178 if pid == 0 { 179 mock_socks5_server(lfd) 180 sys_close(lfd) 181 sys_exit(0) 182 return 0 183 } 184 sys_close(lfd) 185 g_nap(30) // let the child reach accept() (belt-and-braces) 186 let pip: *u8 = sys_mmap(4); pip[0]=127 as u8; pip[1]=0 as u8; pip[2]=0 as u8; pip[3]=1 as u8 187 // connect the TARGET "media.example":443 THROUGH the proxy at 127.0.0.1:port, via the interface. 188 let fd: i64 = anon_connect(ANON_SOCKS5, pip, port, "media.example" as *u8, 13, 443) 189 var conn_ok: i64 = 0; if fd >= 0 { conn_ok = 1 } 190 g_row("PART B anon_connect(SOCKS5) returns a live tunnel fd" as *u8, conn_ok, pass, tot) 191 192 var echo_ok: i64 = 0 193 if fd >= 0 { 194 let msg: *u8 = "PING-NISHI-ANON" as *u8 195 anon_send(fd, msg, 15) 196 let rb: *u8 = sys_mmap(64) 197 let rn: i64 = s5_read_full(fd, rb, 15) 198 if rn == 15 { if g_bytes_eq(rb, msg, 15)==1 { echo_ok = 1 } } 199 anon_close(fd) 200 } 201 g_row("PART B tunnel carries app bytes end-to-end (echo round-trip matches)" as *u8, echo_ok, pass, tot) 202 203 nx_kill(pid, 9) 204 let st: *i64 = sys_mmap(8) as *i64 205 sys_wait4(pid, st, 0) 206 } 207 208 g_w("SOCKS5-CLIENT-GATE rows=" as *u8); g_n(tot[0]); g_w(" pass=" as *u8); g_n(pass[0]) 209 if pass[0] == tot[0] { 210 g_w(" verdict=GREEN\n" as *u8) 211 let lg: i64 = sys_openat_append("knowledge/status/socks5_client_gate.log" as *u8, 0x1a4) 212 if lg >= 0 { g_fw(lg, "SOCKS5-CLIENT-GATE pass=" as *u8); g_fn(lg, pass[0]); g_fw(lg, "/" as *u8); g_fn(lg, tot[0]); g_fw(lg, " verdict=GREEN rfc1928=byte-exact loopback=live-tunnel epoch=" as *u8); g_fn(lg, sys_now_realtime_sec()); g_fw(lg, "\n" as *u8); sys_close(lg) } 213 sys_exit(0); return 0 214 } 215 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1 216}