From c2c1d58dc41d93348707485c7480e72a4dd02a39 Mon Sep 17 00:00:00 2001 From: az-xx <0916617@gmail.com> Date: Fri, 18 Sep 2026 06:44:04 +0200 Subject: [PATCH] Format real IPv6 addresses correctly in connect-hook debug logs getReadableAddress() formatted real (non-IPv4-mapped) IPv6 destinations by mapping each of the 16 address bytes to hex and joining them with ':'. That produces 16 single-byte groups with per-byte leading zeros stripped, so e.g. 2001:db8::1 was logged as '[20:1:d:b8:0:0:0:0:0:0:0:0:0:0:0:1]'. Group the bytes into the 8 standard hextets instead, and collapse the longest run of zero hextets to '::' (RFC 5952), so the same address now logs as '[2001:db8::1]'. IPv4 and IPv4-mapped formatting are unchanged. This only affects DEBUG_MODE output, but readable addresses are the whole point of getReadableAddress when checking which connections are being intercepted or blocked. --- native-connect-hook.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/native-connect-hook.js b/native-connect-hook.js index 0969f8d..6e59702 100644 --- a/native-connect-hook.js +++ b/native-connect-hook.js @@ -242,8 +242,30 @@ } else { - // Real IPv6: - return `[${[...hostBytes].map(x => x.toString(16)).join(':')}]`; + // Real IPv6: pair up the 16 bytes into 8 hextets, then collapse the longest run + // of zero hextets to '::' (per RFC 5952) so the output is actually readable, + // rather than 16 stray single-byte values (e.g. '2001:db8::1' not '20:1:d:b8:...:1'): + const hextets = []; + for (let i = 0; i < 16; i += 2) { + hextets.push(((hostBytes[i] << 8) | hostBytes[i + 1]).toString(16)); + } + + // Find the longest run of consecutive zero hextets (only runs of 2+ are worth + // compressing) preferring the leftmost run on a tie: + let runStart = -1, runLength = 0; + for (let i = 0; i < hextets.length; /* advance below */) { + if (hextets[i] !== '0') { i += 1; continue; } + let end = i; + while (end < hextets.length && hextets[end] === '0') end += 1; + if (end - i > runLength) { runStart = i; runLength = end - i; } + i = end; + } + + const readable = runLength >= 2 + ? `${hextets.slice(0, runStart).join(':')}::${hextets.slice(runStart + runLength).join(':')}` + : hextets.join(':'); + + return `[${readable}]`; } };