code wiki / _hdl_build / nx_hr_visitor_log_gate.nx
nx_hr_visitor_log_gate.nx source
↩ module page · 72 lines · 5631 B
1// nx_hr_visitor_log_gate.nx -- referee for HR rung C (behavior sweep from real logs). Synthetic access log:
2// a FLOODER (11 reqs/1s window -> abusive), a NORMAL visitor, and a BOT (python-requests UA). PROVES the sweep
3// classifies each, writes verdicts, AUTO-BLOCKLISTS the flooder + bot, and that the auto-block then ENFORCES
4// (a later classify of the flooder -> BLOCK even at low rate). GREEN iff every row matches.
5// Prints verdict=GREEN to STDOUT + returns the exit code. Durable -> knowledge/status/hr_visitor_log_gate.log.
6// license_tier: ORIGINAL
7import "nx_hr_visitor_log.nx"
8import "nx_g_puts_lib.nx"
9import "nx_syscalls.nx"
10
11func g_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
12func g_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
13func g_wn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
14func rput(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ dst[off+i]=s[i]; i=i+1 } return off+i }
15func gwrite(path: *u8, s: *u8, n: i64) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd<0 { return 0 } if n>0 { sys_write(fd, s, n) } sys_close(fd); return 0 }
16func g_read(path: *u8, buf: *u8, cap: i64) -> i64 { let fd: i64=sys_openat_rd(path); if fd<0 {return 0} var o: i64=0; var go: i64=1; while go==1 { let r: i64=sys_read(fd,buf+o,cap-o); if r<=0 {go=0} else {o=o+r} } sys_close(fd); return o }
17func has(path: *u8, needle: *u8) -> i64 {
18 let buf: *u8 = sys_mmap(262144); let n: i64 = g_read(path, buf, 262144)
19 var nl: i64=0; while needle[nl]!=(0 as u8){nl=nl+1}; if nl<=0 { return 0 }
20 var i: i64=0; while i+nl<=n { var j: i64=0; var m: i64=1; while j<nl { if buf[i+j]!=needle[j] {m=0;j=nl} else {j=j+1} } if m==1 { return 1 } i=i+1 } return 0
21}
22func logline(buf: *u8, o: i64, ip: *u8, path: *u8, ua: *u8) -> i64 { var p: i64=rput(buf,o,ip); buf[p]=9 as u8;p=p+1; p=rput(buf,p,path); buf[p]=9 as u8;p=p+1; p=rput(buf,p,ua); buf[p]=10 as u8;p=p+1; return p }
23func chk(got: i64, want: i64, label: *u8) -> i64 {
24 g_puts(" "); g_puts(label); g_puts(" got="); g_num(got); g_puts(" want="); g_num(want)
25 if got == want { g_puts(" PASS\n"); return 1 }
26 g_puts(" FAIL\n"); return 0
27}
28
29func main() -> i64 {
30 g_puts("=== NISHI HR VISITOR-LOG GATE (behavior sweep from real logs -> classify + auto-blocklist) ===\n" as *u8)
31 var pass: i64=0
32 var rows: i64=0
33 let log:*u8 = "/tmp/nx_hvl_log" as *u8
34 let block:*u8 = "/tmp/nx_hvl_block" as *u8
35 let welc:*u8 = "/tmp/nx_hvl_welcome" as *u8
36 let rep:*u8 = "/tmp/nx_hvl_report" as *u8
37 gwrite(block, "" as *u8, 0); gwrite(welc, "" as *u8, 0) // fresh lists
38
39 // build the access log: 1.1.1.1 floods 11x; 2.2.2.2 normal x2; 3.3.3.3 bot x2
40 let lb: *u8 = sys_mmap(8192); var lo: i64 = 0
41 var k: i64 = 0; while k < 11 { lo = logline(lb, lo, "1.1.1.1" as *u8, "/x" as *u8, "Mozilla/5.0" as *u8); k = k + 1 }
42 lo = logline(lb, lo, "2.2.2.2" as *u8, "/y" as *u8, "Mozilla/5.0" as *u8)
43 lo = logline(lb, lo, "2.2.2.2" as *u8, "/y2" as *u8, "Mozilla/5.0" as *u8)
44 lo = logline(lb, lo, "3.3.3.3" as *u8, "/z" as *u8, "python-requests/2.31" as *u8)
45 lo = logline(lb, lo, "3.3.3.3" as *u8, "/z2" as *u8, "python-requests/2.31" as *u8)
46 gwrite(log, lb, lo)
47
48 let rbuf: *u8 = sys_mmap(16384); let rn: i64 = g_read(log, rbuf, 16384)
49 rows=rows+1; pass=pass+chk(hvl_count_ip(rbuf, rn, "1.1.1.1" as *u8, 7), 11, "count 1.1.1.1 requests = 11" as *u8)
50
51 // window=1s -> rate_abusive when count*60 > 600 -> count>10. flooder(11)=abusive; normal(2)/bot(2) not by rate.
52 rows=rows+1; pass=pass+chk(hvl_sweep(log, 1, block, welc, rep), 2, "sweep auto-blocks 2 (flooder + bot)" as *u8)
53 rows=rows+1; pass=pass+chk(has(rep, "1.1.1.1\tBLOCK" as *u8), 1, "report: 1.1.1.1 BLOCK (abusive rate)" as *u8)
54 rows=rows+1; pass=pass+chk(has(rep, "2.2.2.2\tNEUTRAL" as *u8), 1, "report: 2.2.2.2 NEUTRAL (served)" as *u8)
55 rows=rows+1; pass=pass+chk(has(rep, "3.3.3.3\tBLOCK" as *u8), 1, "report: 3.3.3.3 BLOCK (bot UA)" as *u8)
56 rows=rows+1; pass=pass+chk(has(block, "1.1.1.1" as *u8), 1, "auto-blocklist now contains the flooder" as *u8)
57 rows=rows+1; pass=pass+chk(has(block, "3.3.3.3" as *u8), 1, "auto-blocklist now contains the bot" as *u8)
58
59 // ENFORCEMENT: after auto-block, the flooder is BLOCKED even at LOW rate (the block persists + enforces).
60 rows=rows+1; pass=pass+chk(hv_classify("1.1.1.1" as *u8, 7, 1, 60, "Mozilla/5.0" as *u8, block, welc), HV_BLOCK, "auto-block ENFORCES: 1.1.1.1 low-rate -> BLOCK" as *u8)
61
62 g_puts("----\nNISHI-HR-VLOG-GATE rows=" as *u8); g_num(rows); g_puts(" pass=" as *u8); g_num(pass)
63 if pass==rows { g_puts(" verdict=GREEN\n" as *u8) } else { g_puts(" verdict=RED\n" as *u8) }
64 let lg: i64=sys_openat_append("knowledge/status/hr_visitor_log_gate.log" as *u8, 0x1a4)
65 if lg>=0 {
66 g_w(lg, "NISHI-HR-VLOG-GATE rows=" as *u8); g_wn(lg, rows); g_w(lg, " pass=" as *u8); g_wn(lg, pass)
67 if pass==rows { g_w(lg, " verdict=GREEN\n" as *u8) } else { g_w(lg, " verdict=RED\n" as *u8) }
68 sys_close(lg)
69 }
70 if pass==rows { sys_exit(0); return 0 }
71 sys_exit(1); return 1
72}