code wiki / _hdl_build / nx_hr_visitor_log.nx

nx_hr_visitor_log.nx source

↩ module page · 66 lines · 3831 B

1// nx_hr_visitor_log.nx -- NISHI HR, rung C: drive the front desk from REAL request logs. Parses a daemon access 2// log (one request per line: `ip <TAB> path <TAB> user-agent`), aggregates per-IP request counts over the window, 3// classifies each distinct visitor via hv_classify (rate + bot-UA + lists), writes a verdict report, and 4// AUTO-BLOCKLISTS the ones it BLOCKs (so the next request is dropped at the door). This turns the visitor policy 5// from a static list into BEHAVIOR-driven enforcement. Composes nx_hr_visitor. (Per-path anomaly + log rotation 6// + dedup of the auto-blocklist = later rungs; this is the core behavior sweep.) license_tier: ORIGINAL 7import "nx_hr_visitor.nx" // hv_classify / HV_BLOCK / HV_WELCOME 8import "nx_hr.nx" // hr_read / hr_line_end / hr_field_end / hr_eqrange 9import "nx_syscalls.nx" 10const K_MAGIC_1048576: i64 = 1048576 11 12// number of request lines whose field0 (ip) == ip. 13func hvl_count_ip(buf: *u8, n: i64, ip: *u8, iplen: i64) -> i64 { 14 var c: i64=0; var i: i64=0 15 while i < n { let le: i64=hr_line_end(buf,i,n); let f0e: i64=hr_field_end(buf,i,le); if hr_eqrange(buf,i,f0e,ip,iplen)==1 { c=c+1 } i=le+1 } 16 return c 17} 18// is the line at `before` the FIRST occurrence of this ip? (so each distinct visitor is classified once) 19func hvl_is_first(buf: *u8, before: i64, ip: *u8, iplen: i64) -> i64 { 20 var i: i64=0 21 while i < before { let le: i64=hr_line_end(buf,i,before); let f0e: i64=hr_field_end(buf,i,le); if hr_eqrange(buf,i,f0e,ip,iplen)==1 { return 0 } i=le+1 } 22 return 1 23} 24// copy field2 (user-agent) of the line buf[ls..le) into out (NUL-term). 25func hvl_ua_of_line(buf: *u8, ls: i64, le: i64, out: *u8, cap: i64) -> i64 { 26 let f0e: i64=hr_field_end(buf,ls,le); let f1e: i64=hr_field_end(buf,f0e+1,le); let f2s: i64=f1e+1 27 var o: i64=0; var i: i64=f2s 28 while i < le { if o < cap-1 { out[o]=buf[i]; o=o+1 } i=i+1 } 29 out[o]=0 as u8; return o 30} 31// append an ip to the blocklist (atomic O_APPEND). 32func hvl_append_block(block_path: *u8, ip: *u8, iplen: i64) -> i64 { 33 let line: *u8 = sys_mmap(128); var k: i64=0; while k < iplen { line[k]=ip[k]; k=k+1 } line[k]=10 as u8; k=k+1 34 let fd: i64 = __syscall(SYS_OPENAT, AT_FDCWD, block_path as i64, O_WRONLY_CA, 0x1a4, 0, 0) 35 if fd < 0 { return 0-1 } 36 sys_write(fd, line, k); sys_close(fd); return 0 37} 38 39// THE BEHAVIOR SWEEP: classify every distinct visitor in the log; write `ip <TAB> verdict` to report; auto-block 40// each BLOCK. Returns the number auto-blocked. 41func hvl_sweep(log_path: *u8, window_sec: i64, block_path: *u8, welcome_path: *u8, report_path: *u8) -> i64 { 42 let buf: *u8 = sys_mmap(K_MAGIC_1048576); let n: i64 = hr_read(log_path, buf, K_MAGIC_1048576) 43 let rfd: i64 = sys_openat_wr(report_path, 0x1a4) 44 var blocked: i64 = 0; var i: i64 = 0 45 while i < n { 46 let le: i64 = hr_line_end(buf, i, n) 47 let f0e: i64 = hr_field_end(buf, i, le) 48 let iplen: i64 = f0e - i 49 if iplen > 0 { 50 let ip: *u8 = ((buf as i64) + i) as *u8 51 if hvl_is_first(buf, i, ip, iplen) == 1 { 52 let count: i64 = hvl_count_ip(buf, n, ip, iplen) 53 let ua: *u8 = sys_mmap(512); hvl_ua_of_line(buf, i, le, ua, 512) 54 let v: i64 = hv_classify(ip, iplen, count, window_sec, ua, block_path, welcome_path) 55 if rfd >= 0 { 56 sys_write(rfd, ip, iplen) 57 if v == HV_BLOCK { sys_write(rfd, "\tBLOCK\n" as *u8, 7) } else { if v == HV_WELCOME { sys_write(rfd, "\tWELCOME\n" as *u8, 9) } else { sys_write(rfd, "\tNEUTRAL\n" as *u8, 9) } } 58 } 59 if v == HV_BLOCK { hvl_append_block(block_path, ip, iplen); blocked = blocked + 1 } 60 } 61 } 62 i = le + 1 63 } 64 if rfd >= 0 { sys_close(rfd) } 65 return blocked 66}