code wiki / (root) / nx_doctor.nx

nx_doctor.nx source

↩ module page · 195 lines · 7670 B

1// nx_doctor.nx -- the bits-up AUTO-FIX tool a regular user runs. Probes 2// the things that break (services, sites, web layer, DNS), classifies each 3// as LOCAL (auto-fixable right here) or REMOTE (report -> the network 4// self-heals), AUTO-FIXES the local ones, and prints a plain-language 5// verdict anyone can read. 6// 7// Fixes it performs locally: restart a dead service (fork+exec); flush the 8// stale Windows DNS cache (ipconfig.exe /flushdns via WSL interop) -- the 9// real cause of "site doesn't load in my browser but the server is fine". 10// 11// Capstone of NX-NETSCOPE (diagnose) + self-heal (decide/act) + the 12// easy-for-anyone verdict. Sovereign: raw syscalls, zero deps. 13// 14// license_tier: ORIGINAL 15 16import "nx_syscalls.nx" 17import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 18const DR_MAGIC_8787: i64 = 8787 19const DR_MAGIC_1500: i64 = 1500 20 21const DR_OK: i64 = 0 22const DR_LOCAL: i64 = 1 23const DR_REMOTE: i64 = 2 24 25func dr_putn(n: i64) -> i64 { 26 if n == 0 { sys_write(1, "0" as *u8, 1); return 0 } 27 var m: i64 = n 28 let d: *u8 = sys_mmap(24) 29 var k: i64 = 0 30 while m > 0 { d[k] = (0x30 + (m % 10)) as u8; m = m / 10; k = k + 1 } 31 var i: i64 = k - 1 32 while i >= 0 { let one: *u8 = sys_mmap(1); one[0] = d[i]; sys_write(1, one, 1); i = i - 1 } 33 return 0 34} 35func dr_sym(state: i64) -> i64 { 36 if state == DR_OK { sys_write(1, "[OK]", 4); return 0 } 37 if state == DR_LOCAL { sys_write(1, "[!!]", 4); return 0 } 38 sys_write(1, "[XX]", 4) 39 return 0 40} 41 42// fill a sockaddr_in (16 bytes) for ip_packed:port. 43func dr_sockaddr(sa: *u8, ip_packed: i64, port: i64) -> i64 { 44 sa[0] = (AF_INET & 0xff) as u8 45 sa[1] = ((AF_INET >> 8) & 0xff) as u8 46 sa[2] = ((port >> 8) & 0xff) as u8 47 sa[3] = (port & 0xff) as u8 48 sa[4] = ((ip_packed >> 24) & 0xff) as u8 49 sa[5] = ((ip_packed >> 16) & 0xff) as u8 50 sa[6] = ((ip_packed >> 8) & 0xff) as u8 51 sa[7] = (ip_packed & 0xff) as u8 52 var p: i64 = 8 53 while p < 16 { sa[p] = 0 as u8; p = p + 1 } 54 return 0 55} 56func dr_timeout(fd: i64, opt: i64) -> i64 { // opt 20=RCVTIMEO 21=SNDTIMEO, 1s 57 let tv: *u8 = sys_mmap(16) 58 tv[0] = 1 as u8 59 var z: i64 = 1 60 while z < 16 { tv[z] = 0 as u8; z = z + 1 } 61 sys_setsockopt(fd, SOL_SOCKET, opt, tv, 16) 62 return 0 63} 64 65// TCP reachability: is host:port accepting connections? 66func dr_tcp_ok(ip_packed: i64, port: i64) -> i64 { 67 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 68 if fd < 0 { return 0 } 69 dr_timeout(fd, 21) 70 let sa: *u8 = sys_mmap(16) 71 dr_sockaddr(sa, ip_packed, port) 72 let rc: i64 = nx_connect_bounded(fd, sa, 16, NX_CONN_DEFAULT_MS) 73 sys_close(fd) 74 if rc == 0 { return 1 } 75 return 0 76} 77 78// HTTP status of GET / on ip:port with a Host header (verifies the web 79// layer actually serves, not just TCP). Returns the 3-digit status or -1. 80func dr_http_status(ip_packed: i64, port: i64, host: *u8, hlen: i64) -> i64 { 81 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 82 if fd < 0 { return 0 - 1 } 83 dr_timeout(fd, 21); dr_timeout(fd, 20) 84 let sa: *u8 = sys_mmap(16) 85 dr_sockaddr(sa, ip_packed, port) 86 if nx_connect_bounded(fd, sa, 16, NX_CONN_DEFAULT_MS) != 0 { sys_close(fd); return 0 - 1 } 87 let req: *u8 = sys_mmap(256) 88 var n: i64 = 0 89 let g: *u8 = "GET / HTTP/1.0\r\nHost: " as *u8 90 var gi: i64 = 0 91 while g[gi] != 0 { req[n] = g[gi]; n = n + 1; gi = gi + 1 } 92 var hi: i64 = 0 93 while hi < hlen { req[n] = host[hi]; n = n + 1; hi = hi + 1 } 94 let tail: *u8 = "\r\nConnection: close\r\n\r\n" as *u8 95 var ti: i64 = 0 96 while tail[ti] != 0 { req[n] = tail[ti]; n = n + 1; ti = ti + 1 } 97 sys_write(fd, req, n) 98 let resp: *u8 = sys_mmap(512) 99 let got: i64 = sys_read(fd, resp, 512) 100 sys_close(fd) 101 if got < 12 { return 0 - 1 } 102 // "HTTP/1.x SSS" -> status at offset 9..11 103 let s: i64 = ((resp[9] as i64) - 0x30) * 100 + ((resp[10] as i64) - 0x30) * 10 + ((resp[11] as i64) - 0x30) 104 return s 105} 106 107// auto-fix: (re)start the sovereign search site. 108func dr_restart_search() -> i64 { 109 let path: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/_offc/nx_search_server.elf" as *u8 110 let pid: i64 = sys_fork() 111 if pid == 0 { 112 let argv: *i64 = sys_mmap(16) as *i64 113 argv[0] = path as i64; argv[1] = 0 114 let envp: *i64 = sys_mmap(8) as *i64 115 envp[0] = 0 116 sys_execve(path, argv, envp); sys_exit(127) 117 } 118 return pid 119} 120// auto-fix: flush the Windows DNS cache (the stale-resolution cause). 121func dr_flush_windows_dns() -> i64 { 122 let path: *u8 = "/mnt/c/Windows/System32/ipconfig.exe" as *u8 123 let pid: i64 = sys_fork() 124 if pid == 0 { 125 let argv: *i64 = sys_mmap(24) as *i64 126 argv[0] = path as i64 127 argv[1] = ("/flushdns" as *u8) as i64 128 argv[2] = 0 129 let envp: *i64 = sys_mmap(8) as *i64 130 envp[0] = 0 131 sys_execve(path, argv, envp); sys_exit(127) 132 } 133 let st: *i64 = sys_mmap(16) as *i64 134 sys_wait4(pid, st, 0) 135 return pid 136} 137 138func main() -> i64 { 139 sys_write(1, "NISHI DOCTOR -- auto-fix health check\n", 38) 140 sys_write(1, "-------------------------------------\n", 38) 141 var problems: i64 = 0 142 var fixed: i64 = 0 143 var remote: i64 = 0 144 145 let loopback: i64 = (127 << 24) | 1 146 let nas: i64 = (192 << 24) | (168 << 16) | (8 << 8) | 240 147 148 // ---- 1: sovereign search site (local, auto-fixable) ---- 149 sys_write(1, " search site (127.0.0.1:8787) ........ ", 40) 150 if dr_tcp_ok(loopback, DR_MAGIC_8787) == 1 { 151 dr_sym(DR_OK); sys_write(1, " up\n", 4) 152 } else { 153 problems = problems + 1 154 dr_sym(DR_LOCAL); sys_write(1, " DOWN -- auto-fixing (restart) ... ", 35) 155 dr_restart_search(); sys_sleep_ms(DR_MAGIC_1500) 156 if dr_tcp_ok(loopback, DR_MAGIC_8787) == 1 { fixed = fixed + 1; sys_write(1, "FIXED [OK]\n", 11) } 157 else { sys_write(1, "still down\n", 11) } 158 } 159 160 // ---- 2: sites web server serving? (TCP + HTTP layer) ---- 161 sys_write(1, " sites server (192.168.8.240) ....... ", 39) 162 if dr_tcp_ok(nas, 443) == 0 { 163 problems = problems + 1; remote = remote + 1 164 dr_sym(DR_REMOTE); sys_write(1, " DOWN -- remote; reported for network heal\n", 43) 165 } else { 166 // web-layer check: HTTP/80 should redirect (3xx) to HTTPS -> serving 167 let st: i64 = dr_http_status(nas, 80, "nishifamily.com" as *u8, 15) 168 if st >= 200 { 169 dr_sym(DR_OK); sys_write(1, " up + serving (HTTP ", 20); dr_putn(st); sys_write(1, ")\n", 2) 170 } else { 171 problems = problems + 1; remote = remote + 1 172 dr_sym(DR_REMOTE); sys_write(1, " TCP up but not serving -- remote; reported\n", 44) 173 } 174 } 175 176 // ---- 3: stale-DNS auto-fix (the 'works in curl, not my browser' cause) ---- 177 sys_write(1, " browser DNS cache .................. ", 39) 178 dr_sym(DR_LOCAL); sys_write(1, " flushing (local) ... ", 22) 179 dr_flush_windows_dns() 180 fixed = fixed + 1 181 sys_write(1, "FLUSHED [OK]\n", 13) 182 183 // ---- summary + guidance ---- 184 sys_write(1, "\n Summary: ", 12) 185 dr_putn(problems); sys_write(1, " problem(s) -- ", 15) 186 dr_putn(fixed); sys_write(1, " auto-fixed locally, ", 21) 187 dr_putn(remote); sys_write(1, " need the network.\n", 19) 188 if problems == 0 { 189 sys_write(1, " All servers healthy. If a site still won't load in YOUR browser:\n", 67) 190 sys_write(1, " - turn OFF the browser's 'Secure DNS' (it bypasses your LAN resolver), and\n", 78) 191 sys_write(1, " - clear that site's cached security (edge://net-internals/#hsts -> delete domain).\n", 86) 192 } 193 if remote > 0 { return 2 } 194 return 0 195}