* Parse IPv6 address to buffer * @param {string} address - IPv6 address string * @returns {Buffer} 16-byte buffer
(address)
| 45 | * @returns {Buffer} 16-byte buffer |
| 46 | */ |
| 47 | function parseIPv6 (address) { |
| 48 | 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 | } |
| 63 | |
| 64 | // Handle compressed notation (::) |
| 65 | const doubleColonIndex = normalizedAddress.indexOf('::') |
| 66 | if (doubleColonIndex !== -1) { |
| 67 | const before = normalizedAddress.slice(0, doubleColonIndex) |
| 68 | const after = normalizedAddress.slice(doubleColonIndex + 2) |
| 69 | const beforeParts = before === '' ? [] : before.split(':') |
| 70 | const afterParts = after === '' ? [] : after.split(':') |
| 71 | |
| 72 | let bufferIndex = 0 |
| 73 | for (const part of beforeParts) { |
| 74 | buffer.writeUInt16BE(parseInt(part, 16), bufferIndex) |
| 75 | bufferIndex += 2 |
| 76 | } |
| 77 | bufferIndex = 16 - afterParts.length * 2 |
| 78 | for (const part of afterParts) { |
| 79 | buffer.writeUInt16BE(parseInt(part, 16), bufferIndex) |
| 80 | bufferIndex += 2 |
| 81 | } |
| 82 | } else { |
| 83 | const parts = normalizedAddress.split(':') |
| 84 | for (let i = 0; i < parts.length; i++) { |
| 85 | buffer.writeUInt16BE(parseInt(parts[i], 16), i * 2) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | return buffer |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Build a SOCKS5 address buffer |
no test coverage detected
searching dependent graphs…