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}