nx_dns_test.nx source
↩ module page · 93 lines · 4772 B
1// nx_dns_test.nx -- KAT + self-consistency for the DNS stub resolver.
2//
3// Vector source: an "example.com" query/response pair derived bits-up
4// from RFC 1035 ยง4.1 wire format. IP 93.184.216.34 is the real public
5// A record for example.com -- usable as a worked example because IANA
6// reserves the example.* TLD for documentation under RFC 2606.
7//
8// expect_exit: 0
9//
10// license_tier: ORIGINAL
11
12import "nx_syscalls.nx"
13import "nx_dns.nx"
14
15func main() -> i64 {
16 // ---- Test A: encode_name("example.com", 11) -> 13 bytes. ----
17 let name: *u8 = sys_mmap(64)
18 name[0]=101; name[1]=120; name[2]=97; name[3]=109; name[4]=112
19 name[5]=108; name[6]=101 // "example"
20 name[7]=46 // '.'
21 name[8]=99; name[9]=111; name[10]=109 // "com"
22 let qname: *u8 = sys_mmap(64)
23 let n_qname: i64 = nx_dns_encode_name(name, 11, qname, 64)
24 if n_qname != 13 { return 1 }
25 if (qname[0] & 0xff) != 7 { return 2 }
26 if (qname[1] & 0xff) != 101 { return 3 }
27 if (qname[7] & 0xff) != 101 { return 4 }
28 if (qname[8] & 0xff) != 3 { return 5 }
29 if (qname[9] & 0xff) != 99 { return 6 }
30 if (qname[12] & 0xff) != 0 { return 7 }
31
32 // ---- Test B: build_query("example.com", A, tx=0x1234) = 29 bytes. ----
33 let q: *u8 = sys_mmap(128)
34 let n_q: i64 = nx_dns_build_query(name, 11, NX_DNS_TYPE_A, 0x1234, q, 128)
35 if n_q != 29 { return 10 }
36 if (q[0] & 0xff) != 0x12 { return 11 }
37 if (q[1] & 0xff) != 0x34 { return 12 }
38 if (q[2] & 0xff) != 0x01 { return 13 } // flags hi: RD set
39 if (q[3] & 0xff) != 0x00 { return 14 }
40 if (q[5] & 0xff) != 0x01 { return 15 } // QDCOUNT lo = 1
41 if (q[7] & 0xff) != 0x00 { return 16 } // ANCOUNT lo = 0
42 if (q[12] & 0xff) != 7 { return 17 } // QNAME label-len 7
43 if (q[24] & 0xff) != 0 { return 18 } // root terminator
44 if (q[26] & 0xff) != 1 { return 19 } // QTYPE = A
45 if (q[28] & 0xff) != 1 { return 20 } // QCLASS = IN
46
47 // ---- Test C: parse_response_a with a canned example.com reply. ----
48 let resp: *u8 = sys_mmap(64)
49 resp[0]=0x12; resp[1]=0x34 // tx_id
50 resp[2]=0x81; resp[3]=0x80 // QR+RD+RA, RCODE=0
51 resp[4]=0; resp[5]=1 // QDCOUNT=1
52 resp[6]=0; resp[7]=1 // ANCOUNT=1
53 resp[8]=0; resp[9]=0
54 resp[10]=0; resp[11]=0
55 resp[12]=7; resp[13]=101; resp[14]=120; resp[15]=97; resp[16]=109
56 resp[17]=112; resp[18]=108; resp[19]=101 // "example"
57 resp[20]=3; resp[21]=99; resp[22]=111; resp[23]=109 // "com"
58 resp[24]=0 // root
59 resp[25]=0; resp[26]=1 // QTYPE=A
60 resp[27]=0; resp[28]=1 // QCLASS=IN
61 resp[29]=0xc0; resp[30]=0x0c // NAME = ptr to off 12
62 resp[31]=0; resp[32]=1 // TYPE=A
63 resp[33]=0; resp[34]=1 // CLASS=IN
64 resp[35]=0; resp[36]=0; resp[37]=0; resp[38]=0x3c // TTL=60
65 resp[39]=0; resp[40]=4 // RDLENGTH=4
66 resp[41]=93; resp[42]=184; resp[43]=216; resp[44]=34 // 93.184.216.34
67 let ip: *u8 = sys_mmap(16)
68 let v: i64 = nx_dns_parse_response_a(resp, 45, 0x1234, ip)
69 if v != NX_DNS_VERDICT_OK { return 30 }
70 if (ip[0] & 0xff) != 93 { return 31 }
71 if (ip[1] & 0xff) != 184 { return 32 }
72 if (ip[2] & 0xff) != 216 { return 33 }
73 if (ip[3] & 0xff) != 34 { return 34 }
74
75 // ---- Test D: tx_id mismatch must be rejected (spoof defense). ----
76 let v2: i64 = nx_dns_parse_response_a(resp, 45, 0x9999, ip)
77 if v2 != NX_DNS_VERDICT_TXID_MISMATCH { return 40 }
78
79 // ---- Test E: pointer-loop attack terminates with PTR_LOOP verdict. ----
80 let loop_pkt: *u8 = sys_mmap(16)
81 loop_pkt[0] = 0xc0
82 loop_pkt[1] = 0x00 // ptr at off 0 -> off 0
83 let v3: i64 = nx_dns_skip_name(loop_pkt, 2, 0)
84 if v3 != -NX_DNS_VERDICT_PTR_LOOP { return 50 }
85
86 // ---- Test F: sealed-enum validity gate. ----
87 if nx_dns_verdict_is_valid(NX_DNS_VERDICT_OK) != 1 { return 60 }
88 if nx_dns_verdict_is_valid(NX_DNS_VERDICT_N) != 0 { return 61 }
89 if nx_dns_verdict_is_valid(0 - 1) != 0 { return 62 }
90 if nx_dns_verdict_is_valid(NX_DNS_VERDICT_NO_A_RECORD) != 1 { return 63 }
91
92 return 0
93}