code wiki / (root) / nx_tool_http_backend_gate.nx

nx_tool_http_backend_gate.nx source

↩ module page · 72 lines · 3975 B

1// nx_tool_http_backend_gate.nx -- proves the HTTP-backend execution mode: url-encode forecloses injection on the 2// only caller input; the TAB registry parses; an unregistered tool -> THB_NOROUTE (falls back to fork-exec); a 3// registered-but-unreachable backend -> THB_ERR (fail-closed). The successful loopback fetch is proven LIVE on the 4// NAS against the real search service. license_tier: ORIGINAL expect_exit: 0 5import "nx_tool_http_backend.nx" // thb_urlenc / thb_field / thb_atoi / thb_dispatch_from + THB_* 6import "nx_gate.nx" 7 8func hg_eq(a: *u8, alen: i64, b: *u8) -> i64 { 9 var i: i64 = 0 10 while i < alen { if b[i] == (0 as u8) { return 0 } if a[i] != b[i] { return 0 } i = i + 1 } 11 if b[alen] != (0 as u8) { return 0 } 12 return 1 13} 14func hg_write(path: *u8, content: *u8) -> i64 { 15 let fd: i64 = __syscall(257, 0 - 100, path, 0x241, 0x1a4, 0, 0) 16 if fd < 0 { return 0 - 1 } 17 var n: i64 = 0; while content[n] != (0 as u8) { n = n + 1 } 18 sys_write(fd, content, n); sys_close(fd) 19 return 0 20} 21func hg_expect(cond: i64, pass: *i64, tot: *i64, label: *u8) -> i64 { 22 tot[0] = tot[0] + 1 23 if cond == 1 { pass[0] = pass[0] + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 24 gw(label); gw("\n" as *u8) 25 return 0 26} 27 28func main() -> i64 { 29 gw("=== nx_tool_http_backend_gate: HTTP-backend execution mode (data-driven, SSRF-safe, fail-closed) ===\n" as *u8) 30 let pbox: *i64 = sys_mmap(16) as *i64; pbox[0] = 0 31 let tbox: *i64 = sys_mmap(16) as *i64; tbox[0] = 0 32 let d: *u8 = sys_mmap(512) 33 34 // T1: url-encode -- space + reserved chars -> %XX (no path/param/header injection through the query) 35 let l1: i64 = thb_urlenc("a b&c" as *u8, 5, d) 36 hg_expect(hg_eq(d, l1, "a%20b%26c" as *u8), pbox, tbox, "T1 url-encode: space+ampersand -> %20 %26 (injection foreclosed)" as *u8) 37 38 // T2: registry row parses -- port field 3 and path field 4 extract correctly 39 let line: *u8 = "nishi_search\tGET\t127.0.0.1\t18456\t/api/search\tq" as *u8 40 let ll: i64 = thb_slen(line) 41 let f: *i64 = sys_mmap(16) as *i64 42 var t2: i64 = 0 43 if thb_field(line, 0, ll, 3, f) == 1 { 44 let port: i64 = thb_atoi(line, f[0], f[1]) 45 if port == 18456 { if thb_field(line, 0, ll, 4, f) == 1 { if hg_eq(((line as i64) + f[0]) as *u8, f[1], "/api/search" as *u8) == 1 { t2 = 1 } } } 46 } 47 hg_expect(t2, pbox, tbox, "T2 registry parse: port=18456, path=/api/search from the TAB row" as *u8) 48 49 // shared argv (argv[0] reserved; argv[1] = the query value) 50 let av: *i64 = sys_mmap(128) as *i64 51 av[1] = "hello world" as *u8 as i64 52 let obuf: *u8 = sys_mmap(65536) 53 let olen: *i64 = sys_mmap(16) as *i64 54 55 // T3: an UNREGISTERED tool -> THB_NOROUTE (so ta_mcp_call falls through to the fork-exec path unchanged) 56 hg_write("/tmp/hg_backends.conf" as *u8, "nishi_search\tGET\t127.0.0.1\t18456\t/api/search\tq\n" as *u8) 57 let r3: i64 = thb_dispatch_from("/tmp/hg_backends.conf" as *u8, "unknowntool" as *u8, 11, av, 1, obuf, 65536, olen) 58 var t3: i64 = 0 59 if r3 == THB_NOROUTE { t3 = 1 } 60 hg_expect(t3, pbox, tbox, "T3 unregistered tool -> THB_NOROUTE (fork-exec fallback preserved)" as *u8) 61 62 // T4: a REGISTERED but UNREACHABLE backend (dead port) -> THB_ERR (fail-closed, no crash) 63 hg_write("/tmp/hg_backends2.conf" as *u8, "deadtool\tGET\t127.0.0.1\t59999\t/x\tq\n" as *u8) 64 let r4: i64 = thb_dispatch_from("/tmp/hg_backends2.conf" as *u8, "deadtool" as *u8, 8, av, 1, obuf, 65536, olen) 65 var t4: i64 = 0 66 if r4 == THB_ERR { t4 = 1 } 67 hg_expect(t4, pbox, tbox, "T4 registered-but-unreachable backend -> THB_ERR (fail-closed)" as *u8) 68 69 gw("\n=== nx_tool_http_backend_gate " as *u8); gn(pbox[0]); gw("/" as *u8); gn(tbox[0]); gw(" ===\n" as *u8) 70 if pbox[0] == tbox[0] { gw("HTTP-BACKEND GREEN -- url-safe, parses, fail-closed on no-route + unreachable\n" as *u8); sys_exit(0); return 0 } 71 gw("HTTP-BACKEND RED\n" as *u8); sys_exit(1); return 1 72}