diff --git a/lib/ipaddr.js b/lib/ipaddr.js index 45eecf0..3b4e00f 100644 --- a/lib/ipaddr.js +++ b/lib/ipaddr.js @@ -61,8 +61,9 @@ colonCount--; } - // The following loop would hang if colonCount > parts - if (colonCount > parts) { + // An address must not contain more separators than available parts, + // and :: must compress at least one part. + if (colonCount >= parts) { return null; } @@ -91,7 +92,7 @@ const results = []; for (let i = 0; i < ref.length; i++) { - results.push(parseInt(ref[i], 16)); + results.push(ref[i].length > 4 ? NaN : parseInt(ref[i], 16)); } return results; diff --git a/test/ipaddr.test.js b/test/ipaddr.test.js index d9508df..a6d0337 100644 --- a/test/ipaddr.test.js +++ b/test/ipaddr.test.js @@ -336,6 +336,25 @@ describe('ipaddr', () => { assert.equal(ipaddr.IPv6.isValid(undefined), false); }) + it('rejects IPv6 parts longer than four hexadecimal digits', () => { + assert.equal(ipaddr.IPv6.isValid('00000::1'), false); + assert.throws(() => ipaddr.IPv6.parse('00000::1')); + assert.equal(ipaddr.IPv6.isValid('00000:0:0:0:0:0:1.2.3.4'), false); + assert.throws(() => ipaddr.IPv6.parse('00000:0:0:0:0:0:1.2.3.4')); + }) + + it('rejects compression of zero IPv6 parts', () => { + assert.equal(ipaddr.IPv6.isValid('1:2:3:4:5:6:7:8::'), false); + assert.throws(() => ipaddr.IPv6.parse('1:2:3:4:5:6:7:8::')); + assert.equal(ipaddr.IPv6.isValid('::1:2:3:4:5:6:7:8'), false); + assert.throws(() => ipaddr.IPv6.parse('::1:2:3:4:5:6:7:8')); + }) + + it('does not reject compression of exactly one IPv6 part', () => { + assert.equal(ipaddr.IPv6.isValid('1:2:3:4:5:6:7::'), true); + assert.equal(ipaddr.IPv6.isValid('::1:2:3:4:5:6:7'), true); + }) + it('validates IPv6 addresses in CIDR notation', () => { assert.equal(ipaddr.IPv6.isValidCIDR('::/0'), true); assert.equal(ipaddr.IPv6.isValidCIDR('2001:db8:F53A::1%z/64'), true);