diff --git a/lib/ipaddr.js b/lib/ipaddr.js index cf04ac3..3a9536f 100644 --- a/lib/ipaddr.js +++ b/lib/ipaddr.js @@ -773,7 +773,15 @@ // in line with RFC 5952 (see https://tools.ietf.org/html/rfc5952#section-4) IPv6.prototype.toRFC5952String = function () { const regex = /((^|:)(0(:|$)){2,})/g; - const string = this.toNormalizedString(); + // The zone identifier (RFC 4007) is not part of the address; match + // against the address alone so a trailing zero run right before the + // "%" suffix still gets compressed (RFC 5952, 4.2.2). + let suffix = ''; + if (this.zoneId) { + suffix = `%${this.zoneId}`; + } + const normalized = this.toNormalizedString(); + const string = normalized.slice(0, normalized.length - suffix.length); let bestMatchIndex = 0; let bestMatchLength = -1; let bestMatchGroups = -1; @@ -793,10 +801,10 @@ } if (bestMatchLength < 0) { - return string; + return string + suffix; } - return `${string.substring(0, bestMatchIndex)}::${string.substring(bestMatchIndex + bestMatchLength)}`; + return `${string.substring(0, bestMatchIndex)}::${string.substring(bestMatchIndex + bestMatchLength)}${suffix}`; }; // Returns the address in compact, human-readable format like diff --git a/test/ipaddr.test.js b/test/ipaddr.test.js index ab0d322..6d32082 100644 --- a/test/ipaddr.test.js +++ b/test/ipaddr.test.js @@ -275,6 +275,15 @@ describe('ipaddr', () => { ); }) + it('compresses a trailing zero run when a zoneIndex is present', () => { + // The zone identifier (RFC 4007) is not part of the address and must + // not prevent zero-run compression at the end of it (RFC 5952, 4.2.2). + assert.equal(new ipaddr.IPv6([0xfe80, 0, 0, 0, 0, 0, 0, 0], 'eth0').toString(), 'fe80::%eth0'); + assert.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0], 'eth0').toRFC5952String(), '2001:db8::%eth0'); + assert.equal(ipaddr.parse('fe80::%eth0').toString(), 'fe80::%eth0'); + assert.equal(ipaddr.parse('::%eth0').toString(), '::%eth0'); + }) + it('returns IPv6 zoneIndex for IPv4-mapped IPv6 addresses', () => { let addr = ipaddr.parse('::ffff:192.168.1.1%eth0'); assert.equal(addr.toNormalizedString(), '0:0:0:0:0:ffff:c0a8:101%eth0');