nx_iot_discover_test.nx source
↩ module page · 180 lines · 8485 B
1// nx_iot_discover_test.nx -- gate for the universal discovery brain.
2//
3// Proves the operator's "discovery mechanism like all the hardware
4// discovery" across ALL five vendor families from canned beacons, with NO
5// sockets (deterministic), and proves the duplicate-on-repair killer +
6// the measured phantom-device count.
7//
8// Grounded in the live fleet: device A is the operator's REAL TP-Link Kasa
9// HS210 (SSID TP-LINK_HS210_C209, BSSID d8:0d:17:a1:c2:09), and its :9999
10// reply is built by ENCRYPTING a sysinfo plaintext with the same autokey
11// XOR a real bulb uses -- so the decode path is exercised end to end.
12//
13// Coverage:
14// - discovery-verdict sealed-enum validity gate
15// - Kasa (:9999, XOR) -> decrypt + classify KASA + NEW
16// - WiZ (:38899, cleartext) -> classify WIZ + NEW
17// - MagicHome (service :5577) -> classify MAGICHOME by port + NEW
18// - Tuya (:6667, devId) -> classify TUYA + NEW
19// - NEG control: garbage + off-table port + no MAC -> UNKNOWN, but STILL
20// anchored (UNKNOWN is first-class; no silent drop)
21// - LIAR-KILL: the Kasa XOR decode must round-trip byte-exact + read as
22// sysinfo (break the codec -> RED)
23// - DEDUP: re-discover A (roamed IP) -> SAME logical id, NO new row
24// - MEASURED EXCEED: duplicates_prevented == naive_adopts - count == 1
25// - NEG control: bad arg (hwid_n=0) -> DISC_BAD_ARG, no state change
26//
27// expect_exit: 0
28//
29// license_tier: ORIGINAL
30
31import "nx_syscalls_x86_64.nx"
32import "nx_iot_discover.nx"
33
34// Byte-equal over n bytes (keep-flag walk; NishiLang family idiom).
35func dt_buf_eq(a: *u8, b: *u8, n: i64) -> i64 {
36 var i: i64 = 0
37 var eq: i64 = 1
38 var keep: i64 = 1
39 while keep == 1 {
40 if i >= n {
41 keep = 0
42 } else {
43 if (a[i] as i64) != (b[i] as i64) {
44 eq = 0
45 keep = 0
46 } else {
47 i = i + 1
48 }
49 }
50 }
51 return eq
52}
53
54func main() -> i64 {
55 // ---- discovery-verdict sealed-enum gate ------------------------
56 if nx_iot_disc_verdict_is_valid(NX_IOT_DISC_NEW) != 1 { return 1 }
57 if nx_iot_disc_verdict_is_valid(NX_IOT_DISC_READOPTED) != 1 { return 2 }
58 if nx_iot_disc_verdict_is_valid(NX_IOT_DISC_N) != 0 { return 3 }
59 if nx_iot_disc_verdict_is_valid(-1) != 0 { return 4 }
60
61 // ---- alloc registry + scratch ----------------------------------
62 let reg: *IotAnchorReg = sys_mmap(64) as *IotAnchorReg
63 let metas: *IotDeviceMeta = sys_mmap(512) as *IotDeviceMeta
64 let blob: *u8 = sys_mmap(512)
65 let qv: *i64 = sys_mmap(8) as *i64
66 let dv: *i64 = sys_mmap(8) as *i64
67 let plain: *u8 = sys_mmap(512)
68 if nx_iot_anchor_init(reg, 8) != 0 { return 10 }
69
70 // ===== Device A: Kasa HS210 (:9999, autokey XOR) ================
71 // Build the DECRYPTED sysinfo plaintext (markers mic_type + relay_state).
72 let ksys: *u8 = sys_mmap(256)
73 let kL: i64 = nx_iot_kasa_puts_z(ksys, 0, "{\"system\":{\"get_sysinfo\":{\"mic_type\":\"IOT.SMARTPLUGSWITCH\",\"relay_state\":1}}}")
74 // Encrypt it -> the raw datagram as it would arrive on :9999.
75 let kcipher: *u8 = sys_mmap(256)
76 nx_iot_kasa_encrypt(ksys, kL, kcipher)
77 // Real HS210 MAC for the OUI signal + the anchor hardware id.
78 let macA: *u8 = sys_mmap(8)
79 macA[0] = 0xD8 as u8
80 macA[1] = 0x0D as u8
81 macA[2] = 0x17 as u8
82 macA[3] = 0xA1 as u8
83 macA[4] = 0xC2 as u8
84 macA[5] = 0x09 as u8
85 let la: i64 = nx_iot_disc_ingest(reg, metas, blob, kcipher, kL, NX_IOT_KASA_PORT, 0xC0A80878, macA, 1, "d8:0d:17:a1:c2:09", 17, 1000, plain, 512, qv, dv)
86 if la != 1 { return 20 }
87 if dv[0] != NX_IOT_DISC_NEW { return 21 }
88 if qv[0] != NX_IOT_VENDOR_KASA { return 22 }
89 if nx_iot_anchor_count(reg) != 1 { return 23 }
90
91 // LIAR-KILL: the XOR decode the classification leaned on must
92 // round-trip byte-exact + still read as sysinfo. Break the codec -> RED.
93 let kplain2: *u8 = sys_mmap(256)
94 nx_iot_kasa_decrypt(kcipher, kL, kplain2)
95 if dt_buf_eq(kplain2, ksys, kL) != 1 { return 24 }
96 if nx_iot_kasa_looks_like_sysinfo(kplain2, kL) != 1 { return 25 }
97
98 // ===== Device B: WiZ (:38899, cleartext getPilot reply) ========
99 let bwiz: *u8 = sys_mmap(256)
100 let bL: i64 = nx_iot_kasa_puts_z(bwiz, 0, "{\"method\":\"getPilot\",\"result\":{\"mac\":\"a8bb50112233\",\"state\":1}}")
101 let macB: *u8 = sys_mmap(8)
102 macB[0] = 0xA8 as u8
103 macB[1] = 0xBB as u8
104 macB[2] = 0x50 as u8
105 macB[3] = 0x11 as u8
106 macB[4] = 0x22 as u8
107 macB[5] = 0x33 as u8
108 let lb: i64 = nx_iot_disc_ingest(reg, metas, blob, bwiz, bL, 38899, 0xC0A80850, macB, 1, "a8:bb:50:11:22:33", 17, 1100, plain, 512, qv, dv)
109 if lb != 2 { return 30 }
110 if dv[0] != NX_IOT_DISC_NEW { return 31 }
111 if qv[0] != NX_IOT_VENDOR_WIZ { return 32 }
112 if nx_iot_anchor_count(reg) != 2 { return 33 }
113
114 // ===== Device C: Magic Home (service :5577) ====================
115 // Reply has no keyword + MagicHome OUI not seeded -> classified by the
116 // service port 5577. (Honest: real MH discovery replies from :48899;
117 // mapping 48899 in classify_by_port is a queued additive enhancement.)
118 let cmh: *u8 = sys_mmap(256)
119 let cL: i64 = nx_iot_kasa_puts_z(cmh, 0, "192.168.8.51,AABBCCDDEEFF,AK001-ZJ100")
120 let lc: i64 = nx_iot_disc_ingest(reg, metas, blob, cmh, cL, 5577, 0xC0A80851, cmh, 0, "magichome-aabbccddeeff", 22, 1200, plain, 512, qv, dv)
121 if lc != 3 { return 40 }
122 if qv[0] != NX_IOT_VENDOR_MAGICHOME { return 41 }
123 if dv[0] != NX_IOT_DISC_NEW { return 42 }
124 if nx_iot_anchor_count(reg) != 3 { return 43 }
125
126 // ===== Device D: Tuya (:6667, devId marker) ====================
127 let dtu: *u8 = sys_mmap(256)
128 let dL: i64 = nx_iot_kasa_puts_z(dtu, 0, "{\"devId\":\"bf1234567890\",\"dps\":{\"1\":1}}")
129 let ld: i64 = nx_iot_disc_ingest(reg, metas, blob, dtu, dL, 6667, 0xC0A80852, dtu, 0, "tuya-bf1234567890", 17, 1300, plain, 512, qv, dv)
130 if ld != 4 { return 50 }
131 if qv[0] != NX_IOT_VENDOR_TUYA { return 51 }
132 if dv[0] != NX_IOT_DISC_NEW { return 52 }
133 if nx_iot_anchor_count(reg) != 4 { return 53 }
134
135 // ===== Device E: UNKNOWN (negative control) ====================
136 // Garbage bytes, off-table port, no MAC -> all four signals UNKNOWN.
137 // Proves (a) no false-positive classification, (b) the device STILL
138 // anchors (UNKNOWN is first-class -> no silent drop; hub can probe it).
139 let egar: *u8 = sys_mmap(64)
140 egar[0] = 0xDE as u8
141 egar[1] = 0xAD as u8
142 egar[2] = 0xBE as u8
143 egar[3] = 0xEF as u8
144 egar[4] = 0x01 as u8
145 egar[5] = 0x02 as u8
146 egar[6] = 0x03 as u8
147 egar[7] = 0x04 as u8
148 let le: i64 = nx_iot_disc_ingest(reg, metas, blob, egar, 8, 12345, 0xC0A80853, egar, 0, "unknown-deadbeef01", 18, 1400, plain, 512, qv, dv)
149 if le != 5 { return 60 }
150 if qv[0] != NX_IOT_VENDOR_UNKNOWN { return 61 }
151 if dv[0] != NX_IOT_DISC_NEW { return 62 }
152 if nx_iot_anchor_count(reg) != 5 { return 63 }
153
154 // ===== DEDUP: re-discover A (the duplicate-on-repair killer) ====
155 // Same hwid, new IP (it roamed). Must RE-ADOPT: same logical id 1, NO
156 // new row -- the structural fix for "they duplicate in the app".
157 let la2: i64 = nx_iot_disc_ingest(reg, metas, blob, kcipher, kL, NX_IOT_KASA_PORT, 0xC0A8087E, macA, 1, "d8:0d:17:a1:c2:09", 17, 2000, plain, 512, qv, dv)
158 if la2 != 1 { return 70 }
159 if dv[0] != NX_IOT_DISC_READOPTED { return 71 }
160 if qv[0] != NX_IOT_VENDOR_KASA { return 72 }
161 if nx_iot_anchor_count(reg) != 5 { return 73 }
162 if nx_iot_anchor_logical_ip(reg, metas, 1) != 0xC0A8087E { return 74 }
163
164 // ===== MEASURED EXCEED =========================================
165 // 6 discovery events (A,B,C,D,E,A); 5 distinct devices kept. A dedup-
166 // free cloud-token app = 6 rows; we keep 5. duplicates_prevented = 1
167 // (the exact phantom the re-pair would have created).
168 if nx_iot_anchor_naive_adopts(reg) != 6 { return 80 }
169 if nx_iot_anchor_count(reg) != 5 { return 81 }
170 if nx_iot_disc_duplicates_prevented(reg) != 1 { return 82 }
171
172 // ===== NEG control: bad arg -> DISC_BAD_ARG, no state change ====
173 let cbefore: i64 = nx_iot_anchor_count(reg)
174 let bad: i64 = nx_iot_disc_ingest(reg, metas, blob, kcipher, kL, NX_IOT_KASA_PORT, 0, macA, 1, "d8:0d:17:a1:c2:09", 0, 9000, plain, 512, qv, dv)
175 if bad != -1 { return 90 }
176 if dv[0] != NX_IOT_DISC_BAD_ARG { return 91 }
177 if nx_iot_anchor_count(reg) != cbefore { return 92 }
178
179 return 0
180}