code wiki / (root) / nx_inet_pton.nx

nx_inet_pton.nx source

↩ module page · 151 lines · 5096 B

1// nx_inet_pton.nx -- IPv4 / IPv6 address text <-> binary conversions. 2// 3// Companion to nx_socket (which has nx_sock_inet_aton for IPv4 4// parse). This module rounds out the conversions: 5// pton: text -> binary (parse) 6// ntop: binary -> text (format) 7// 8// IPv4 only in this commit; IPv6 lands when we have a real DNS / 9// AAAA-record consumer. 10// 11// Used by: 12// - HTTP server (Host header logging in dotted-quad) 13// - DNS resolver result formatting 14// - Sovereign curl-equivalent CLI 15// - Network debug logs 16 17// nx_safety_envelope: 18// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 19// sil_target: SIL1 20// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 21// verdict: NOT_YET_EVALUATED 22 23import "syscalls.nx" 24 25// Helper: write decimal `v` (0..255) to buf[off..]; return bytes written. 26func nx_inet_dec(buf: *u8, off: i64, v: i64) -> i64 { 27 if v == 0 { 28 buf[off] = 0x30 29 return 1 30 } 31 if v < 10 { 32 buf[off] = 0x30 + v 33 return 1 34 } 35 if v < 100 { 36 let tens: i64 = v / 10 37 buf[off] = 0x30 + tens 38 buf[off + 1] = 0x30 + (v - tens * 10) 39 return 2 40 } 41 let hundreds: i64 = v / 100 42 let rem: i64 = v - hundreds * 100 43 let tens2: i64 = rem / 10 44 buf[off] = 0x30 + hundreds 45 buf[off + 1] = 0x30 + tens2 46 buf[off + 2] = 0x30 + (rem - tens2 * 10) 47 return 3 48} 49 50// Format a packed BE u32 IPv4 address into dotted-quad ASCII text. 51// `buf` must be >= 16 bytes (max "255.255.255.255\0"). Returns 52// length written (excluding NUL). 53// 54// Input convention: `addr_be` is the raw 4-byte address as packed 55// little-endian-storage bytes that represent network-byte-order 56// (byte 0 of the storage = first quad). Matches what 57// nx_sock_inet_aton produces. 58func nx_inet_ntop_v4(addr_be: i64, buf: *u8) -> i64 { 59 let b0: i64 = addr_be & 0xFF 60 let b1: i64 = (addr_be >> 8) & 0xFF 61 let b2: i64 = (addr_be >> 16) & 0xFF 62 let b3: i64 = (addr_be >> 24) & 0xFF 63 64 var k: i64 = 0 65 k = k + nx_inet_dec(buf, k, b0) 66 buf[k] = 0x2E; k = k + 1 67 k = k + nx_inet_dec(buf, k, b1) 68 buf[k] = 0x2E; k = k + 1 69 k = k + nx_inet_dec(buf, k, b2) 70 buf[k] = 0x2E; k = k + 1 71 k = k + nx_inet_dec(buf, k, b3) 72 buf[k] = 0 73 return k 74} 75 76// Parse dotted-quad text to packed BE u32. Returns the packed 77// value or -1 on parse error. Same semantics as nx_sock_inet_aton. 78func nx_inet_pton_v4(s: *u8) -> i64 { 79 var parts: i64 = 0 80 var cur: i64 = 0 81 var packed: i64 = 0 82 var i: i64 = 0 83 var done: i64 = 0 84 while done == 0 { 85 let c: i64 = s[i] 86 if c == 0 { 87 if parts != 3 { return 0 - 1 } 88 packed = packed | (cur << 24) 89 done = 1 90 } else { 91 if c == 0x2E { 92 if parts >= 3 { return 0 - 1 } 93 packed = packed | (cur << (parts * 8)) 94 cur = 0 95 parts = parts + 1 96 i = i + 1 97 } else { 98 if c < 0x30 { return 0 - 1 } 99 if c > 0x39 { return 0 - 1 } 100 cur = cur * 10 + (c - 0x30) 101 if cur > 255 { return 0 - 1 } 102 i = i + 1 103 } 104 } 105 } 106 return packed 107} 108 109// ---- self-test --------------------------------------------------- 110 111func main() -> i64 { 112 let buf: *u8 = sys_mmap(32) 113 114 // 127.0.0.1 round-trip. 115 let v1: i64 = 0x0100007F 116 let n1: i64 = nx_inet_ntop_v4(v1, buf) 117 if n1 != 9 { return __syscall(93, 1, 0, 0, 0, 0, 0) } 118 if buf[0] != 0x31 { return __syscall(93, 2, 0, 0, 0, 0, 0) } // '1' 119 if buf[1] != 0x32 { return __syscall(93, 3, 0, 0, 0, 0, 0) } // '2' 120 if buf[2] != 0x37 { return __syscall(93, 4, 0, 0, 0, 0, 0) } // '7' 121 if buf[3] != 0x2E { return __syscall(93, 5, 0, 0, 0, 0, 0) } // '.' 122 if buf[8] != 0x31 { return __syscall(93, 6, 0, 0, 0, 0, 0) } // '1' 123 if buf[9] != 0 { return __syscall(93, 7, 0, 0, 0, 0, 0) } 124 125 let p1: i64 = nx_inet_pton_v4(buf) 126 if p1 != v1 { return __syscall(93, 8, 0, 0, 0, 0, 0) } 127 128 // 255.255.255.255 (max length). 129 let v2: i64 = 0xFFFFFFFF 130 let n2: i64 = nx_inet_ntop_v4(v2, buf) 131 if n2 != 15 { return __syscall(93, 9, 0, 0, 0, 0, 0) } 132 if buf[0] != 0x32 { return __syscall(93, 10, 0, 0, 0, 0, 0) } // '2' 133 if buf[14] != 0x35 { return __syscall(93, 11, 0, 0, 0, 0, 0) } // '5' 134 135 // 0.0.0.0 (min length). 136 let v3: i64 = 0 137 let n3: i64 = nx_inet_ntop_v4(v3, buf) 138 if n3 != 7 { return __syscall(93, 12, 0, 0, 0, 0, 0) } 139 if buf[0] != 0x30 { return __syscall(93, 13, 0, 0, 0, 0, 0) } 140 if buf[6] != 0x30 { return __syscall(93, 14, 0, 0, 0, 0, 0) } 141 142 // 192.168.42.1 143 let v4: i64 = 0x012AA8C0 144 nx_inet_ntop_v4(v4, buf) 145 if buf[0] != 0x31 { return __syscall(93, 15, 0, 0, 0, 0, 0) } // '1' 146 if buf[1] != 0x39 { return __syscall(93, 16, 0, 0, 0, 0, 0) } // '9' 147 if buf[2] != 0x32 { return __syscall(93, 17, 0, 0, 0, 0, 0) } // '2' 148 if buf[10] != 0x34 { return __syscall(93, 18, 0, 0, 0, 0, 0) } // '4' 149 150 return 0 151}