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}