code wiki / _hdl_build / nx_netscope_capture.nx

nx_netscope_capture.nx source

↩ module page · 80 lines · 4199 B

1// nx_netscope_capture.nx -- NX-NETSCOPE L-CAPTURE: the SOVEREIGN raw-wire capture front-end (the 2// "wireshark" tap, in-ecosystem, NO tcpdump). Opens an AF_PACKET raw socket, reads frames, and feeds 3// each to the EXISTING pure dissector nx_packet_dissect (nx_netscope_dissect.nx). Filters inbound TCP 4// SYN (no ACK) to a chosen dest port and prints src-ip -> dst-ip:port -- so we can SEE which NAS 5// interface/IP a public :443 connection actually lands on (answering "where does external ingress go" 6// with a capture, not a guess). Bounded: per-recv timeout + wall-clock deadline, so it NEVER hangs. 7// usage: nx_netscope_capture [dport=443] [seconds=90] [maxrows=200] 8// Needs CAP_NET_RAW (run as root). license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_netscope_dissect.nx" 11const NXC_MAGIC_65536: i64 = 65536 12 13const NXC_AF_PACKET: i64 = 17 14const NXC_SOCK_RAW: i64 = 3 15const NXC_ETH_P_ALL_BE: i64 = 768 // htons(0x0003) = 0x0300 16 17func c_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 18func c_n(v: i64) -> i64 { let b: *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{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 19func c_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 20func c_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v } 21// packed-BE ipv4 -> a.b.c.d 22func c_ip(p: i64) -> i64 { 23 c_n((p>>24)&0xff); c_puts("." as *u8); c_n((p>>16)&0xff); c_puts("." as *u8) 24 c_n((p>>8)&0xff); c_puts("." as *u8); c_n(p&0xff); return 0 25} 26 27func main(argc: i64, argv: *i64) -> i64 { 28 var dport: i64 = 443 29 var secs: i64 = 90 30 var maxrows: i64 = 200 31 if argc > 1 { dport = c_atoi(argv[1] as *u8) } 32 if argc > 2 { secs = c_atoi(argv[2] as *u8) } 33 if argc > 3 { maxrows = c_atoi(argv[3] as *u8) } 34 35 c_puts("=== nx_netscope_capture: sovereign wire tap for inbound TCP SYN -> :" as *u8); c_n(dport) 36 c_puts(" window=" as *u8); c_n(secs); c_puts("s ===\n" as *u8) 37 38 let fd: i64 = sys_socket(NXC_AF_PACKET, NXC_SOCK_RAW, NXC_ETH_P_ALL_BE) 39 if fd < 0 { c_puts("SOCKET-FAIL rc=" as *u8); c_n(fd); c_puts(" (need root / CAP_NET_RAW)\n" as *u8); return 1 } 40 sys_set_socket_timeout(fd, 3) // 3s per-recv, so we loop + honor the wall-clock deadline (never hang) 41 42 let buf: *u8 = sys_mmap(NXC_MAGIC_65536) 43 let d: *Dissection = sys_mmap(NXD_DISSECTION_BYTES) as *Dissection 44 let start: i64 = sys_now_realtime_sec() 45 let deadline: i64 = start + secs 46 var frames: i64 = 0 47 var rows: i64 = 0 48 var run: i64 = 1 49 while run == 1 { 50 if sys_now_realtime_sec() >= deadline { run = 0 } 51 if rows >= maxrows { run = 0 } 52 if run == 1 { 53 let n: i64 = sys_recvfrom(fd, buf, NXC_MAGIC_65536, 0, 0 as *u8, 0 as *i64) 54 if n > 0 { 55 frames = frames + 1 56 nx_packet_dissect(buf, n, d) 57 if d.deepest == NXD_L_TCP { 58 if d.l4_dport == dport { 59 var syn: i64 = 0 60 if (d.tcp_flags & NXD_TCP_SYN) != 0 { syn = 1 } 61 var ack: i64 = 0 62 if (d.tcp_flags & NXD_TCP_ACK) != 0 { ack = 1 } 63 if syn == 1 { if ack == 0 { 64 c_puts(" SYN src " as *u8); c_ip(d.ip_src) 65 c_puts(":" as *u8); c_n(d.l4_sport) 66 c_puts(" -> dst " as *u8); c_ip(d.ip_dst) 67 c_puts(":" as *u8); c_n(d.l4_dport); c_puts("\n" as *u8) 68 rows = rows + 1 69 } } 70 } 71 } 72 } 73 } 74 } 75 sys_close(fd) 76 c_puts("--- capture done: frames_seen=" as *u8); c_n(frames) 77 c_puts(" inbound_syn_to_:" as *u8); c_n(dport); c_puts("=" as *u8); c_n(rows) 78 c_puts(" (the dst IP is the NAS interface the connection landed on)\n" as *u8) 79 return 0 80}