code wiki / _hdl_build / nx_sni_router_gate.nx

nx_sni_router_gate.nx source

↩ module page · 97 lines · 5208 B

1// nx_sni_router_gate.nx -- e2e gate for the SNI router: fork an echo backend + the router, then as a client push 2// [ClientHello + marker] through the router and verify the marker round-trips -> proves peek + route + replay + 3// duplex splice on loopback (no live deploy, no reachability dependency). license_tier: ORIGINAL expect_exit: 0 4import "nx_syscalls.nx" 5import "nx_http_server.nx" 6import "nx_sni_extract.nx" 7import "nx_tls13_ext.nx" // tls13_ext_emit_server_name -- a real CH to peek 8import "_hdl_build/nx_sni_router.nx" // sr_serve + sr_connect 9 10func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 11func g_contains(buf: *u8, n: i64, needle: *u8) -> i64 { 12 var nl: i64=0; while needle[nl]!=(0 as u8){nl=nl+1} 13 if nl==0 { return 0 } 14 var i: i64=0 15 while i+nl<=n { var j: i64=0; var ok: i64=1; while j<nl { if buf[i+j]!=needle[j] { ok=0; j=nl } else { j=j+1 } } if ok==1 { return 1 } i=i+1 } 16 return 0 17} 18 19// minimal ClientHello record carrying one SNI extension (same builder as nx_sni_extract_gate). 20func build_ch(host: *u8, host_len: i64, out: *u8) -> i64 { 21 let sni: *u8 = sys_mmap(512) 22 let sni_n: i64 = tls13_ext_emit_server_name(host, host_len, sni, 512) 23 if sni_n <= 0 { return 0 } 24 var o: i64 = 9 25 out[o]=3 as u8; out[o+1]=3 as u8; o=o+2 26 var i: i64=0; while i<32 { out[o]=0 as u8; o=o+1; i=i+1 } 27 out[o]=0 as u8; o=o+1 28 out[o]=0 as u8; out[o+1]=2 as u8; o=o+2; out[o]=0x13 as u8; out[o+1]=0x01 as u8; o=o+2 29 out[o]=1 as u8; o=o+1; out[o]=0 as u8; o=o+1 30 out[o]=((sni_n>>8)&0xff) as u8; out[o+1]=(sni_n&0xff) as u8; o=o+2 31 var j: i64=0; while j<sni_n { out[o]=sni[j]; o=o+1; j=j+1 } 32 let body_len: i64 = o - 9 33 out[5]=0x01 as u8; out[6]=((body_len>>16)&0xff) as u8; out[7]=((body_len>>8)&0xff) as u8; out[8]=(body_len&0xff) as u8 34 let rec_len: i64 = 4 + body_len 35 out[0]=0x16 as u8; out[1]=3 as u8; out[2]=3 as u8; out[3]=((rec_len>>8)&0xff) as u8; out[4]=(rec_len&0xff) as u8 36 return o 37} 38 39// one-shot echo backend on `port`: accept one conn, echo bytes until EOF. 40func run_echo(port: i64) -> i64 { 41 let addr: *u8 = sys_mmap(16); nx_http_server_addr_any(addr, port) 42 let lv: *i64 = (sys_mmap(8)) as *i64 43 let lfd: i64 = nx_http_server_listen(addr, 16, lv) 44 if lfd < 0 { sys_exit(2) } 45 let sa: *u8 = sys_mmap(64); let sl: *i64 = (sys_mmap(8)) as *i64; sl[0]=16 46 let cfd: i64 = sys_accept_with_addr(lfd, sa, sl) 47 if cfd < 0 { sys_exit(3) } 48 let buf: *u8 = sys_mmap(8192) 49 var go: i64=1 50 while go==1 { 51 let n: i64 = sys_read(cfd, buf, 8192) 52 if n<=0 { go=0 } else { var off: i64=0; while off<n { let w: i64=sys_write(cfd,(buf+off) as *u8,n-off); if w<=0 {off=n;go=0} else {off=off+w} } } 53 } 54 sys_close(cfd); sys_close(lfd) 55 return 0 56} 57 58func main() -> i64 { 59 g_puts("=== nx_sni_router gate (peek + route + replay + duplex splice, loopback) ===\n" as *u8) 60 let echo_pid: i64 = sys_fork() 61 if echo_pid==0 { run_echo(9461); sys_exit(0) } 62 let router_pid: i64 = sys_fork() 63 if router_pid==0 { sr_serve(9460, 9461); sys_exit(0) } 64 sys_sleep_ms(600) // let both bind 65 66 var fails: i64 = 0 67 let cfd: i64 = sr_connect(9460) 68 if cfd < 0 { 69 g_puts(" FAIL client could not connect to the router :9460\n" as *u8); fails=1 70 } else { 71 let msg: *u8 = sys_mmap(2048) 72 let chn: i64 = build_ch("nishifamily.com" as *u8, 15, msg) 73 let marker: *u8 = "ROUTER-RELAY-OK" as *u8 74 var o: i64 = chn; var i: i64=0; while marker[i]!=(0 as u8) { msg[o]=marker[i]; o=o+1; i=i+1 } 75 sys_write(cfd, msg, o) 76 sys_set_socket_timeout(cfd, 5) 77 let resp: *u8 = sys_mmap(4096) 78 var rn: i64=0; var tries: i64=0 79 while tries < 8 { 80 let r: i64 = sys_read(cfd, (resp+rn) as *u8, 4096-rn) 81 if r > 0 { rn = rn + r; if g_contains(resp, rn, marker)==1 { tries=8 } } else { tries=tries+1 } 82 } 83 sys_close(cfd) 84 if g_contains(resp, rn, marker)==1 { g_puts(" ok marker round-tripped client->router->echo->router->client\n" as *u8) } 85 else { g_puts(" FAIL marker did NOT round-trip\n" as *u8); fails=1 } 86 } 87 // routing-decision via the data-driven registry (rung 4): a test config drives sr_route. 88 let tcfg: *u8 = "andelinwest.com 8453 third andelin\n" as *u8 89 var tcn: i64 = 0; while tcfg[tcn]!=(0 as u8) { tcn=tcn+1 } 90 if sr_route("andelinwest.com" as *u8, 15, tcfg, tcn, 8443) == 8453 { g_puts(" ok sr_route andelinwest.com -> client daemon (:8453) via registry\n" as *u8) } else { g_puts(" FAIL andelinwest.com not routed via registry\n" as *u8); fails=fails+1 } 91 if sr_route("nishifamily.com" as *u8, 15, tcfg, tcn, 8443) == 8443 { g_puts(" ok sr_route nishifamily.com -> default (not in test cfg)\n" as *u8) } else { g_puts(" FAIL nishifamily.com not defaulted\n" as *u8); fails=fails+1 } 92 93 nx_kill(echo_pid, 9); nx_kill(router_pid, 9) 94 let st: *i64 = (sys_mmap(16)) as *i64; sys_wait4(echo_pid, st, 0); sys_wait4(router_pid, st, 0) 95 if fails==0 { g_puts("ALL GREEN (3/3)\n" as *u8); sys_exit(0); return 0 } 96 g_puts("HAD FAILURES\n" as *u8); sys_exit(1); return 1 97}