nx_netscope_dns_test.nx source
↩ module page · 158 lines · 7932 B
1// nx_netscope_dns_test.nx -- 1:1 KAT for NX-NETSCOPE L0+L1
2// (nx_netscope_dns.nx). Per the charter's KAT spec + the cardinal
3// "1:1 proof, no proxy". HARD assertions are deterministic (no network
4// needed); the live 8.8.8.8 probe is INFORMATIONAL (printed, not
5// asserted) so the gate stays deterministic where internet is absent.
6//
7// T1 wire encode/decode: build_query tx_id round-trips
8// T2 dead-IP 192.0.2.1 -> NXNS_TIMEOUT, bounded wall (THE no-hang proof)
9// T3 WOULD-POISON race detector fires on a synthetic OK_A vs NXDOMAIN
10// T4 PUBLIC-vs-RFC1918 hairpin detector fires on a public-IP OK_A
11// T5 no false positive: when all resolvers AGREE (both OK_A) -> no race
12// (live) 8.8.8.8 / example.com probe -- printed, not asserted
13//
14// expect_exit: 0
15// license_tier: ORIGINAL
16
17import "nx_netscope_dns.nx"
18
19func nxns_put_dec(n: i64) -> i64 {
20 if n == 0 { sys_write(1, "0" as *u8, 1); return 0 }
21 var m: i64 = n
22 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
23 let d: *u8 = sys_mmap(24)
24 var k: i64 = 0
25 while m > 0 { d[k] = (0x30 + (m % 10)) as u8; m = m / 10; k = k + 1 }
26 var i: i64 = k - 1
27 while i >= 0 { let one: *u8 = sys_mmap(1); one[0] = d[i]; sys_write(1, one, 1); i = i - 1 }
28 return 0
29}
30
31// set ProbeCell fields at row-major slot `idx` in a cells buffer.
32func nxns_set_cell(cells: *ProbeCell, idx: i64, verdict: i64, ipv4: i64, rfc1918: i64) -> i64 {
33 let base: i64 = cells as i64
34 let c: *ProbeCell = (base + idx * NXNS_PROBECELL_BYTES) as *ProbeCell
35 c.server_ip = 0
36 c.host_idx = 0
37 c.verdict = verdict
38 c.rcode = 0
39 c.ancount = 0
40 c.ipv4_packed = ipv4
41 c.latency_ms = 0
42 c.is_rfc1918 = rfc1918
43 return 0
44}
45
46func main() -> i64 {
47 // ---- T1: wire encode/decode round-trip ----
48 let host: *u8 = "example.com" as *u8
49 let q: *u8 = sys_mmap(512)
50 let tx1: i64 = 0x4d2e
51 let qlen: i64 = nx_dns_build_query(host, 11, NX_DNS_TYPE_A, tx1, q, 512)
52 if qlen <= 12 { return 1 }
53 if nx_dns_get_u16_be(q, 0) != (tx1 & 0xffff) { return 2 } // tx_id encoded
54 if nx_dns_get_u16_be(q, 4) != 1 { return 3 } // QDCOUNT == 1
55 sys_write(1, "T1 encode/decode OK (qlen=", 26); nxns_put_dec(qlen); sys_write(1, ")\n" as *u8, 2)
56
57 // ---- T2: L0 recv-timed keystone -- a SILENT socket MUST time out and
58 // return (never hang). Tested directly (no DNS), so WSL's transparent
59 // :53 DNS proxy can't confound it the way it does a "dead-IP" probe.
60 let sfd: i64 = sys_socket(AF_INET, SOCK_DGRAM, 0)
61 if sfd < 0 { return 4 }
62 let rbuf: *u8 = sys_mmap(512)
63 let rfrom: *u8 = sys_mmap(16)
64 let rflen: *i64 = sys_mmap(16) as *i64
65 *rflen = 16
66 let t0: i64 = sys_now_ms()
67 let got: i64 = nx_dns_recv_timed(sfd, rbuf, 512, 400, rfrom, rflen) // nothing sent -> nothing arrives
68 let wall: i64 = sys_now_ms() - t0
69 sys_close(sfd)
70 sys_write(1, "T2 recv-timed got=", 18); nxns_put_dec(got)
71 sys_write(1, " wall_ms=", 9); nxns_put_dec(wall); sys_write(1, "\n" as *u8, 1)
72 if got > 0 { return 5 } // got NO data (nothing was sent)
73 if wall < 200 { return 6 } // actually WAITED the ~400ms budget (not an instant error)
74 if wall > 3000 { return 7 } // and did NOT hang past it -- the no-hang keystone
75
76 // ---- T3: synthetic WOULD-POISON race (2 servers x 1 host) ----
77 let cells: *ProbeCell = sys_mmap(4 * NXNS_PROBECELL_BYTES) as *ProbeCell
78 let rfc: i64 = (192 << 24) | (168 << 16) | (8 << 8) | 240 // 192.168.8.240
79 nxns_set_cell(cells, 0, NXNS_OK_A, rfc, 1) // server0: has the A (internal)
80 nxns_set_cell(cells, 1, NXNS_NXDOMAIN, 0, 0) // server1: NXDOMAIN (the poisoner)
81 if nx_dns_host_would_poison(cells, 2, 1, 0) != 1 { return 8 }
82 sys_write(1, "T3 WOULD-POISON race detected (OK_A vs NXDOMAIN same host)\n", 58)
83
84 // ---- T4: PUBLIC-vs-RFC1918 hairpin ----
85 let pub_ip: i64 = (75 << 24) | (28 << 16) | (18 << 8) | 94 // 75.28.18.94 (public)
86 nxns_set_cell(cells, 0, NXNS_OK_A, pub_ip, 0) // resolves to PUBLIC
87 nxns_set_cell(cells, 1, NXNS_OK_A, pub_ip, 0)
88 if nx_dns_host_hairpin_risk(cells, 2, 1, 0) != 1 { return 9 }
89 sys_write(1, "T4 PUBLIC-vs-RFC1918 hairpin detected\n", 38)
90
91 // ---- T5: no false positive when resolvers AGREE (both OK_A) ----
92 nxns_set_cell(cells, 0, NXNS_OK_A, rfc, 1)
93 nxns_set_cell(cells, 1, NXNS_OK_A, rfc, 1)
94 if nx_dns_host_would_poison(cells, 2, 1, 0) != 0 { return 10 } // agreement -> no race
95 if nx_dns_host_hairpin_risk(cells, 2, 1, 0) != 0 { return 11 } // both RFC1918 -> no hairpin
96 sys_write(1, "T5 no-false-positive (resolvers agree -> no race/hairpin)\n", 58)
97
98 // ---- (live, informational) probe 8.8.8.8 for example.com ----
99 let g8: i64 = (8 << 24) | (8 << 16) | (8 << 8) | 8
100 let lc: *ProbeCell = nx_dns_probe_one(g8, host, 11, 0, 1500, 0x2222)
101 sys_write(1, "LIVE 8.8.8.8 example.com verdict=", 33); nxns_put_dec(lc.verdict)
102 sys_write(1, " ip=", 4)
103 nxns_put_dec((lc.ipv4_packed >> 24) & 0xff); sys_write(1, "." as *u8, 1)
104 nxns_put_dec((lc.ipv4_packed >> 16) & 0xff); sys_write(1, "." as *u8, 1)
105 nxns_put_dec((lc.ipv4_packed >> 8) & 0xff); sys_write(1, "." as *u8, 1)
106 nxns_put_dec(lc.ipv4_packed & 0xff)
107 sys_write(1, " latency_ms=", 12); nxns_put_dec(lc.latency_ms); sys_write(1, "\n" as *u8, 1)
108
109 // ---- T6: L1.1 parallel poll() fan-in -- 4 SILENT sockets time out in
110 // ONE shared deadline (~400ms), NOT 4 x 400ms. The parallel EXCEED. ----
111 let nf: i64 = 4
112 let pf: *u8 = sys_mmap(nf * 8)
113 var fi: i64 = 0
114 while fi < nf {
115 let sd: i64 = sys_socket(AF_INET, SOCK_DGRAM, 0)
116 if sd < 0 { return 12 }
117 nxns_pollfd_set_fd(pf, fi, sd)
118 nxns_pollfd_set_events(pf, fi, NXNS_POLLIN)
119 fi = fi + 1
120 }
121 let pt0: i64 = sys_now_ms()
122 let pr: i64 = sys_poll(pf, nf, 400) // nothing sent -> nothing readable
123 let pwall: i64 = sys_now_ms() - pt0
124 sys_write(1, "T6 parallel poll fan-in r=", 26); nxns_put_dec(pr)
125 sys_write(1, " wall_ms=", 9); nxns_put_dec(pwall); sys_write(1, " (4 fds, 1 deadline)\n", 20)
126 if pr != 0 { return 13 } // poll timed out (0 ready)
127 if pwall < 200 { return 14 } // actually waited the ~400ms
128 if pwall > 1000 { return 15 } // NOT 4x400=1600 -> parallel proven
129 var fc: i64 = 0
130 while fc < nf { sys_close(nxns_pollfd_get_fd(pf, fc)); fc = fc + 1 }
131
132 // ---- T7: parallel matrix resolves ALL cells (none left PENDING) ----
133 let psrv: *i64 = sys_mmap(2 * 8) as *i64
134 psrv[0] = (8 << 24) | (8 << 16) | (8 << 8) | 8 // 8.8.8.8
135 psrv[1] = (1 << 24) | (1 << 16) | (1 << 8) | 1 // 1.1.1.1
136 let phosts: *i64 = sys_mmap(2 * 8) as *i64
137 let plens: *i64 = sys_mmap(2 * 8) as *i64
138 phosts[0] = host as i64; plens[0] = 11 // example.com
139 phosts[1] = host as i64; plens[1] = 11
140 let pcells: *ProbeCell = sys_mmap(4 * NXNS_PROBECELL_BYTES) as *ProbeCell
141 let mt0: i64 = sys_now_ms()
142 nx_dns_probe_matrix_parallel(psrv, 2, phosts, plens, 2, 1500, 0x3c5a, pcells)
143 let mwall: i64 = sys_now_ms() - mt0
144 var ci: i64 = 0
145 var resolved: i64 = 0
146 while ci < 4 {
147 let pbase: i64 = pcells as i64
148 let cc: *ProbeCell = (pbase + ci * NXNS_PROBECELL_BYTES) as *ProbeCell
149 if cc.verdict != NXNS_PENDING { resolved = resolved + 1 }
150 ci = ci + 1
151 }
152 sys_write(1, "T7 parallel matrix resolved ", 28); nxns_put_dec(resolved)
153 sys_write(1, "/4 cells wall_ms=", 17); nxns_put_dec(mwall); sys_write(1, "\n" as *u8, 1)
154 if resolved != 4 { return 16 } // every cell got a verdict (no PENDING leak)
155
156 sys_write(1, "NETSCOPE L0+L1+L1.1 KAT PASS (recv-timed no-hang + RCODE dissection + poison/hairpin + parallel poll fan-in)\n", 108)
157 return 0
158}