Skip to content

Commit d76f932

Browse files
authored
fix(socks5): encode embedded IPv4 tails in IPv6 literals correctly (#5099)
Assisted-by: openai:gpt-5.4 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
1 parent 754a3d3 commit d76f932

2 files changed

Lines changed: 22 additions & 5 deletions

File tree

lib/core/socks5-utils.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,26 @@ function parseAddress (address) {
4646
*/
4747
function parseIPv6 (address) {
4848
const buffer = Buffer.alloc(16)
49+
let normalizedAddress = address
50+
51+
// Expand an embedded IPv4 tail into the last two IPv6 groups.
52+
if (address.includes('.')) {
53+
const lastColonIndex = address.lastIndexOf(':')
54+
const ipv4Part = address.slice(lastColonIndex + 1)
55+
56+
if (net.isIPv4(ipv4Part)) {
57+
const octets = ipv4Part.split('.').map(Number)
58+
const high = ((octets[0] << 8) | octets[1]).toString(16)
59+
const low = ((octets[2] << 8) | octets[3]).toString(16)
60+
normalizedAddress = `${address.slice(0, lastColonIndex)}:${high}:${low}`
61+
}
62+
}
4963

5064
// Handle compressed notation (::)
51-
const doubleColonIndex = address.indexOf('::')
65+
const doubleColonIndex = normalizedAddress.indexOf('::')
5266
if (doubleColonIndex !== -1) {
53-
const before = address.slice(0, doubleColonIndex)
54-
const after = address.slice(doubleColonIndex + 2)
67+
const before = normalizedAddress.slice(0, doubleColonIndex)
68+
const after = normalizedAddress.slice(doubleColonIndex + 2)
5569
const beforeParts = before === '' ? [] : before.split(':')
5670
const afterParts = after === '' ? [] : after.split(':')
5771

@@ -66,7 +80,7 @@ function parseIPv6 (address) {
6680
bufferIndex += 2
6781
}
6882
} else {
69-
const parts = address.split(':')
83+
const parts = normalizedAddress.split(':')
7084
for (let i = 0; i < parts.length; i++) {
7185
buffer.writeUInt16BE(parseInt(parts[i], 16), i * 2)
7286
}

test/socks5-utils.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ test('parseAddress - Domain', async (t) => {
4848
})
4949

5050
test('parseIPv6', async (t) => {
51-
const p = tspl(t, { plan: 9 })
51+
const p = tspl(t, { plan: 10 })
5252

5353
// Test full IPv6
5454
const buffer1 = parseIPv6('2001:0db8:0000:0042:0000:8a2e:0370:7334')
@@ -74,6 +74,9 @@ test('parseIPv6', async (t) => {
7474
// Test trailing ::
7575
p.equal(parseIPv6('fe80::').toString('hex'), 'fe800000000000000000000000000000', 'should expand fe80:: correctly')
7676

77+
// Test IPv4-mapped IPv6
78+
p.equal(parseIPv6('::ffff:192.0.2.128').toString('hex'), '00000000000000000000ffffc0000280', 'should encode embedded IPv4 tail correctly')
79+
7780
await p.completed
7881
})
7982

0 commit comments

Comments
 (0)