code wiki / _hdl_build / nx_sites_reconciled.nx

nx_sites_reconciled.nx source

↩ module page · 269 lines · 13104 B

1// nx_sites_reconciled.nx -- the ONE reconciled sovereign sites daemon (R3-assembly): cleanly LAYERED + fully 2// DATA-DRIVEN, replacing the two divergent F-level daemons. Composes the PROVEN TLS primitives (handshake/recv/ 3// send, reused unchanged) with the GATED data-driven cores: 4// io: accept (fork-per-conn) -> MSG_PEEK ClientHello -> scs_pick_from_clienthello -> SNI host 5// data: cl_load(certs_generated.conf, sni) -> chain+key bytes (default-cert fallback) ; tables read at startup 6// TLS: nx_tls13_server_session_run(cfd, rnd, priv, chain, len, key) [proven] 7// logic: sh_handle(request, proxy_routes.conf, sites_generated.conf) -> PROXY-signal | static-200 | 404 8// io: PROXY -> buffered reverse-proxy relay to the backend ; else app_send the response 9// NO hardcoded routes/certs/hosts -- routes/certs/vhosts are the 3 data tables nx_domain_forge emits. Operator: 10// "fix the hardcoding, s-class exceed; append a domain -> the builders emit it." (Buffered proxy; streaming large 11// media = a later perf rung.) license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 14import "nx_csprng.nx" 15import "nx_tls13_server_session.nx" 16import "nx_tls13_server_session_run.nx" 17import "nx_tls13_server_session_app_data.nx" 18import "nx_sni_cert_select.nx" 19import "nx_cert_loader.nx" 20import "nx_site_handler.nx" 21import "nx_tls13_read_record_from_fd.nx" // robust TLS record reader (reassembles a record split across sys_reads) -- for the full-body receive loop 22const RD_MAGIC_20480: i64 = 20480 23 24const RD_PORT: i64 = 8443 25const RD_MSG_PEEK: i64 = 2 26const RD_PEEK_CAP: i64 = 8192 27const RD_OUTCAP: i64 = 4194304 28const RD_RELAYCAP: i64 = 4194304 29const RD_BUDGET: i64 = 1000000000 30const RD_MAXCHILD: i64 = 64 31 32const RD_REG: *u8 = "/volume1/homes/elderwesto/nishihost/certs_generated.conf" as *u8 33const RD_RT: *u8 = "/volume1/homes/elderwesto/nishihost/proxy_routes.conf" as *u8 34const RD_VT: *u8 = "/volume1/homes/elderwesto/nishihost/sites_generated.conf" as *u8 35const RD_DEF_CHAIN: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_fullchain.der" as *u8 36const RD_DEF_KEY: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_ecdsa_key.bin" as *u8 37 38func rd_readfile(path: *u8, szbox: *i64) -> *u8 { szbox[0] = 0; return sys_read_file(path, szbox) } 39 40// ---- ADDITIVE full-body receive (crown-jewel edge fix 2026-07-02) -------------------------------------------- 41// The v1-style receive (single sys_read + one app_recv into a 20KB buffer) dropped any request body spanning >1 42// TLS record: a chunked-upload POST > ~16KB was truncated, so the backend saw a short body and reset (rc=-2). 43// rd_recv_request loop-reads complete records and reassembles the FULL request (headers + whole Content-Length 44// body) up to RD_PLAINCAP before relaying. Pattern adapted from the GATED nx_sites_daemon_v2 sd2_recv_request. 45// GET/no-body still returns at the headers; a small request completes in one record (behaviour unchanged). 46const RD_RECCAP: i64 = 20480 // one TLS record (16384 payload + header/tag slack) 47const RD_PLAINCAP: i64 = 65536 // full-request reassembly cap: headers + up to a ~63KB chunked-upload chunk 48 49func rd_lower(c: u8) -> u8 { 50 if c >= (65 as u8) { if c <= (90 as u8) { return (c + (32 as u8)) } } 51 return c 52} 53 54func rd_contains(hay: *u8, hlen: i64, needle: *u8, nlen: i64) -> i64 { 55 if nlen <= 0 { return 0 } 56 if hlen < nlen { return 0 } 57 var i: i64 = 0 58 let last: i64 = hlen - nlen 59 while i <= last { 60 var j: i64 = 0 61 var ok: i64 = 1 62 while j < nlen { 63 if hay[i + j] != needle[j] { ok = 0; j = nlen } else { j = j + 1 } 64 } 65 if ok == 1 { return 1 } 66 i = i + 1 67 } 68 return 0 69} 70 71func rd_body_start(hay: *u8, hlen: i64) -> i64 { 72 if hlen < 4 { return hlen } 73 var i: i64 = 0 74 let last: i64 = hlen - 4 75 while i <= last { 76 if hay[i] == (0x0D as u8) { if hay[i + 1] == (0x0A as u8) { if hay[i + 2] == (0x0D as u8) { if hay[i + 3] == (0x0A as u8) { 77 return i + 4 78 } } } } 79 i = i + 1 80 } 81 return hlen 82} 83 84func rd_content_length(req: *u8, reqn: i64) -> i64 { 85 let key: *u8 = "content-length:" as *u8 86 var i: i64 = 0 87 while i + 15 <= reqn { 88 var j: i64 = 0 89 var ok: i64 = 1 90 while j < 15 { 91 if rd_lower(req[i + j]) != key[j] { ok = 0; j = 15 } else { j = j + 1 } 92 } 93 if ok == 1 { 94 var k: i64 = i + 15 95 var run0: i64 = 1 96 while run0 == 1 { if k < reqn { if req[k] == (32 as u8) { k = k + 1 } else { run0 = 0 } } else { run0 = 0 } } 97 var v: i64 = 0 98 var got: i64 = 0 99 var run: i64 = 1 100 while run == 1 { 101 if k >= reqn { run = 0 } else { 102 let c: i64 = req[k] as i64 103 var dig: i64 = 0 104 if c >= 48 { if c <= 57 { dig = 1 } } 105 if dig == 1 { v = v * 10 + (c - 48); got = 1; k = k + 1 } else { run = 0 } 106 } 107 } 108 if got == 1 { return v } 109 return 0 - 1 110 } 111 i = i + 1 112 } 113 return 0 - 1 114} 115 116// Loop-read complete TLS records + app-decrypt+append until headers (CRLFCRLF) AND the full Content-Length body 117// are buffered (<= plain_cap), then return plaintext length. Bounded to 16 records. GET/no-body -> at headers. 118func rd_recv_request(s: *Tls13ServerSession, cfd: i64, rec_buf: *u8, plain: *u8, plain_cap: i64) -> i64 { 119 var total: i64 = 0 120 var recs: i64 = 0 121 var need: i64 = 0 122 while recs < 16 { 123 let rn: i64 = nx_tls13_read_record_from_fd(cfd, rec_buf, RD_RECCAP) 124 if rn <= 0 { if total > 0 { return total } return 0 - 1 } 125 let pn: i64 = nx_tls13_server_session_app_recv(s, rec_buf, rn, ((plain as i64) + total) as *u8, plain_cap - total) 126 if pn <= 0 { if total > 0 { return total } return 0 - 1 } 127 total = total + pn 128 if need == 0 { 129 if rd_contains(plain, total, "\r\n\r\n" as *u8, 4) == 1 { 130 let cl: i64 = rd_content_length(plain, total) 131 if cl <= 0 { return total } 132 let bs: i64 = rd_body_start(plain, total) 133 need = bs + cl 134 if need > plain_cap { need = plain_cap } 135 if total >= need { return total } 136 } 137 } else { 138 if total >= need { return total } 139 } 140 if total >= plain_cap { return total } 141 recs = recs + 1 142 } 143 return total 144} 145 146// buffered reverse-proxy relay: connect 127.0.0.1:port, send the decrypted request, read the backend response, 147// app_send it over the TLS session. (buffered; streaming for large media is a later perf rung.) 148func rd_relay(s: *Tls13ServerSession, port: i64, plain: *u8, plain_n: i64, out_rec: *u8, cfd: i64) -> i64 { 149 let fd: i64 = sys_socket(2, 1, 0) 150 if fd < 0 { return 0 - 1 } 151 sys_set_socket_timeout(fd, 20) 152 let a: *u8 = sys_mmap(16) 153 a[0] = 2 as u8; a[1] = 0 as u8; a[2] = ((port >> 8) & 0xff) as u8; a[3] = (port & 0xff) as u8 154 a[4] = 127 as u8; a[5] = 0 as u8; a[6] = 0 as u8; a[7] = 1 as u8 155 var zi: i64 = 8; while zi < 16 { a[zi] = 0 as u8; zi = zi + 1 } 156 if nx_connect_bounded(fd, a, 16, NX_CONN_DEFAULT_MS) != 0 { sys_close(fd); return 0 - 2 } 157 var sent: i64 = 0 158 var sgo: i64 = 1 159 while sgo == 1 { 160 if sent >= plain_n { sgo = 0 } else { 161 let w: i64 = sys_write(fd, ((plain as i64) + sent) as *u8, plain_n - sent) 162 if w <= 0 { sgo = 0 } else { sent = sent + w } 163 } 164 } 165 let buf: *u8 = sys_mmap(RD_RELAYCAP) 166 var tot: i64 = 0; var go: i64 = 1 167 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64) + tot) as *u8, RD_RELAYCAP - tot); if r <= 0 { go = 0 } else { tot = tot + r; if tot >= RD_RELAYCAP { go = 0 } } } 168 sys_close(fd) 169 if tot <= 0 { return 0 - 3 } 170 let on: i64 = nx_tls13_server_session_app_send(s, buf, tot, out_rec, RD_OUTCAP) 171 if on > 0 { sys_write(cfd, out_rec, on) } 172 return tot 173} 174 175func main() -> i64 { 176 // ---- startup: load the 3 data tables + the default cert (fail-fast on the default) ---- 177 let regsz: *i64 = sys_mmap(16) as *i64 178 let reg: *u8 = rd_readfile(RD_REG, regsz); var reg_n: i64 = 0; if (reg as i64) != 0 { reg_n = regsz[0] } 179 let rtsz: *i64 = sys_mmap(16) as *i64 180 let rt: *u8 = rd_readfile(RD_RT, rtsz); var rt_n: i64 = 0; if (rt as i64) != 0 { rt_n = rtsz[0] } 181 let vtsz: *i64 = sys_mmap(16) as *i64 182 let vt: *u8 = rd_readfile(RD_VT, vtsz); var vt_n: i64 = 0; if (vt as i64) != 0 { vt_n = vtsz[0] } 183 let dcsz: *i64 = sys_mmap(16) as *i64 184 let def_chain: *u8 = rd_readfile(RD_DEF_CHAIN, dcsz) 185 if (def_chain as i64) == 0 { sys_write(2, "FATAL: default cert chain\n" as *u8, 26); return 2 } 186 let def_chain_len: i64 = dcsz[0] 187 let dksz: *i64 = sys_mmap(16) as *i64 188 let def_key: *u8 = rd_readfile(RD_DEF_KEY, dksz) 189 if (def_key as i64) == 0 { sys_write(2, "FATAL: default key\n" as *u8, 19); return 2 } 190 191 // ---- listen 0.0.0.0:8443 ---- 192 let addr: *u8 = sys_mmap(16) 193 addr[0] = 2 as u8; addr[1] = 0 as u8; addr[2] = ((RD_PORT >> 8) & 0xff) as u8; addr[3] = (RD_PORT & 0xff) as u8 194 addr[4] = 0 as u8; addr[5] = 0 as u8; addr[6] = 0 as u8; addr[7] = 0 as u8 195 var zj: i64 = 8; while zj < 16 { addr[zj] = 0 as u8; zj = zj + 1 } 196 let lfd: i64 = sys_socket(2, 1, 0) 197 if lfd < 0 { sys_write(2, "SOCKET-FAIL\n" as *u8, 12); return 1 } 198 let optv: *u8 = sys_mmap(4); optv[0] = 1 as u8 199 sys_setsockopt(lfd, 1, 2, optv, 4) 200 if sys_bind(lfd, addr, 16) < 0 { sys_write(2, "BIND-FAIL\n" as *u8, 10); return 1 } 201 if sys_listen(lfd, 64) < 0 { sys_write(2, "LISTEN-FAIL\n" as *u8, 12); return 1 } 202 sys_write(1, "RECONCILED-SITES-UP (data-driven: route+cert+vhost tables, no hardcoding)\n" as *u8, 73) 203 sys_set_socket_timeout(lfd, 5) 204 205 // ---- hoisted per-conn buffers (children get COW copies) ---- 206 let server_random: *u8 = sys_mmap(32) 207 let server_priv: *u8 = sys_mmap(32) 208 let rec_buf: *u8 = sys_mmap(RD_MAGIC_20480) 209 let plain: *u8 = sys_mmap(RD_PLAINCAP) // 64KB: full-request reassembly (headers + up to a ~63KB chunked-upload body), not just one record 210 let out_rec: *u8 = sys_mmap(RD_OUTCAP) 211 let resp: *u8 = sys_mmap(RD_OUTCAP) 212 let sni_peek: *u8 = sys_mmap(RD_PEEK_CAP) 213 let sni_host: *u8 = sys_mmap(256) 214 let dec: *i64 = sys_mmap(64) as *i64 215 let cp: *i64 = sys_mmap(8) as *i64; let cl: *i64 = sys_mmap(8) as *i64 216 let kp: *i64 = sys_mmap(8) as *i64; let kl: *i64 = sys_mmap(8) as *i64 217 let reapst: *i64 = sys_mmap(8) as *i64 218 var served: i64 = 0 219 var live: i64 = 0 220 221 while served < RD_BUDGET { 222 while sys_wait4(0 - 1, reapst, 1) > 0 { live = live - 1 } 223 let cfd: i64 = sys_accept(lfd) 224 if cfd >= 0 { 225 if live >= RD_MAXCHILD { if sys_wait4(0 - 1, reapst, 0) > 0 { live = live - 1 } } 226 let pid: i64 = sys_fork() 227 if pid == 0 { 228 sys_close(lfd) 229 sys_set_socket_timeout(cfd, 10) 230 nx_csprng_fill(server_random, 32) 231 nx_csprng_fill(server_priv, 32) 232 // io: peek the ClientHello (non-consuming) -> SNI host (data: cl_load -> cert; else default) 233 let pk_n: i64 = sys_recvfrom(cfd, sni_peek, RD_PEEK_CAP, RD_MSG_PEEK, 0 as *u8, 0 as *i64) 234 sni_host[0] = 0 as u8 235 if pk_n > 0 { scs_pick_from_clienthello(sni_peek, pk_n, sni_host, 256) } 236 var hn: i64 = 0; while sni_host[hn] != (0 as u8) { hn = hn + 1 } 237 var sel_chain: *u8 = def_chain 238 var sel_chain_len: i64 = def_chain_len 239 var sel_key: *u8 = def_key 240 if hn > 0 { if reg_n > 0 { 241 if cl_load(reg, reg_n, sni_host, hn, cp, cl, kp, kl) == 1 { 242 sel_chain = cp[0] as *u8; sel_chain_len = cl[0]; sel_key = kp[0] as *u8 243 } 244 } } 245 let hs_rc: i64 = nx_tls13_server_session_run(cfd, server_random, server_priv, sel_chain, sel_chain_len, sel_key) 246 if hs_rc > 0 { 247 let s: *Tls13ServerSession = hs_rc as *Tls13ServerSession 248 let plain_n: i64 = rd_recv_request(s, cfd, rec_buf, plain, RD_PLAINCAP) 249 if plain_n > 0 { 250 dec[0] = 0 - 9 251 let on: i64 = sh_handle(plain, plain_n, rt, rt_n, vt, vt_n, resp, dec) 252 if dec[0] == SH_PROXY { 253 rd_relay(s, dec[1], plain, plain_n, out_rec, cfd) 254 } else { 255 let en: i64 = nx_tls13_server_session_app_send(s, resp, on, out_rec, RD_OUTCAP) 256 if en > 0 { sys_write(cfd, out_rec, en) } 257 } 258 } 259 } 260 sys_close(cfd) 261 sys_exit(0) 262 } 263 live = live + 1 264 served = served + 1 265 } 266 } 267 sys_close(lfd) 268 return 0 269}