code wiki / (root) / nx_udp_rv.nx

nx_udp_rv.nx source

↩ module page · 66 lines · 2584 B

1// nx_udp_rv.nx -- native-lane UDP socket primitives. 2// 3// Twin of nx_udp.nx, but imports nx_syscalls.nx (RV64-numbered, @ifdef 4// TARGET_X86_64) instead of nx_syscalls_x86_64.nx (raw x86_64 numbers). 5// 6// WHY THIS EXISTS: the native compiler (_offc/nx_compile_x86_native.elf) 7// translates RV64 syscall numbers -> x86_64 at codegen time 8// (nx_x86_64_ctx.nx: 198->41 socket, 200->49 bind, 206->44 sendto, 9// 207->45 recvfrom, 73->7 poll, ...). Code that feeds it raw x86_64 10// numbers (nx_udp.nx -> nx_syscalls_x86_64.nx) hits a collision: 11// x86_64 socket=41 == RV64 unshare=41, so socket() silently became 12// unshare() and every UDP daemon died with -EINVAL before its banner. 13// This is the same syscall-duality class as the documented 14// fork()->openat() leak. Using nx_syscalls.nx (which yields RV64 15// numbers when TARGET_X86_64 is undefined, i.e. the native lane) makes 16// the translation correct. This is the recipe the gated nx_netscope 17// UDP code already uses successfully on the native lane. 18// 19// Use nx_udp_rv.* for daemons built via the native lane; use nx_udp.* 20// for the nxc2.exe --target x86_64 (non-translating) lane. 21 22import "nx_syscalls.nx" 23 24// Open a UDP socket. Returns fd or -errno. 25func nx_udpr_open() -> i64 { 26 return sys_socket(AF_INET, SOCK_DGRAM, 0) 27} 28 29// Fill a 16-byte sockaddr_in for INADDR_ANY:port. 30func nx_udpr_sa_any(out: *u8, port: i64) -> i64 { 31 out[0] = 2; out[1] = 0 32 out[2] = (port >> 8) & 0xff 33 out[3] = port & 0xff 34 var i: i64 = 4 35 while i < 16 { out[i] = 0; i = i + 1 } 36 return 16 37} 38 39// Bind a UDP socket to (INADDR_ANY, port). Returns 0 / -errno. 40func nx_udpr_bind_any(fd: i64, port: i64) -> i64 { 41 let a: *u8 = sys_mmap(16) 42 nx_udpr_sa_any(a, port) 43 return sys_bind(fd, a, 16) 44} 45 46// Fill a 16-byte sockaddr_in for an IPv4 dest a.b.c.d:port. 47func nx_udpr_sa_dest(out: *u8, a: i64, b: i64, c: i64, d: i64, port: i64) -> i64 { 48 out[0] = 2; out[1] = 0 49 out[2] = (port >> 8) & 0xff 50 out[3] = port & 0xff 51 out[4] = a; out[5] = b; out[6] = c; out[7] = d 52 var i: i64 = 8 53 while i < 16 { out[i] = 0; i = i + 1 } 54 return 16 55} 56 57// Send a UDP datagram (flags=0). Returns bytes sent or -errno. 58func nx_udpr_send(fd: i64, buf: *u8, n: i64, addr16: *u8) -> i64 { 59 return sys_sendto(fd, buf, n, 0, addr16, 16) 60} 61 62// Receive a UDP datagram (flags=0). `from` gets the 16-byte source 63// sockaddr_in; `fromlen` is in/out (caller sets 16). Bytes or -errno. 64func nx_udpr_recv(fd: i64, buf: *u8, n: i64, from: *u8, fromlen: *i64) -> i64 { 65 return sys_recvfrom(fd, buf, n, 0, from, fromlen) 66}