Skip to content

Commit

Permalink
Add IPv6.toRFC5952String.
Browse files Browse the repository at this point in the history
Our implementation of .toString and .toNormalizedString sadly
does not correctly implement RFC5952. This commit adds a correct
implementation.
  • Loading branch information
whitequark authored Feb 10, 2019
2 parents b8b1e24 + b091daf commit 16ec0b2
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/ipaddr.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,27 @@ class ipaddr.IPv6

# Returns the address in compact, human-readable format like
# 2001:db8:8:66::1
#
# Deprecated: use toRFC5952String() instead.
toString: ->
# Replace the first sequence of 1 or more '0' parts with '::'
return @toNormalizedString().replace( /((^|:)(0(:|$))+)/, '::' )

# Returns the address in compact, human-readable format like
# 2001:db8:8:66::1
# in line with RFC 5952 (see https://tools.ietf.org/html/rfc5952#section-4)
toRFC5952String: ->
regex = /((^|:)(0(:|$)){2,})/g
string = @toNormalizedString()
bestMatchIndex = 0
bestMatchLength = -1
while (match = regex.exec(string))
if match[0].length > bestMatchLength
bestMatchIndex = match.index
bestMatchLength = match[0].length
return string if bestMatchLength < 0
return string.substring(0, bestMatchIndex) + '::' + string.substring(bestMatchIndex+bestMatchLength)

# Returns an array of byte-sized values in network order (MSB first)
toByteArray: ->
bytes = []
Expand All @@ -231,6 +248,8 @@ class ipaddr.IPv6

# Returns the address in expanded format with all zeroes included, like
# 2001:db8:8:66:0:0:0:1
#
# Deprecated: use toFixedLengthString() instead.
toNormalizedString: ->
addr = (part.toString(16) for part in @parts).join ":"

Expand Down
24 changes: 24 additions & 0 deletions test/ipaddr.test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,30 @@ module.exports =
test.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0xff, 0xabc, 0, 0, 0x456c, 0x78d]).toString(), '2001:db8:ff:abc::456c:78d')
test.done()

'converts IPv6 to RFC 5952 string correctly': (test) ->
# see https://tools.ietf.org/html/rfc5952#section-4
addr = new ipaddr.IPv6([0x2001, 0xdb8, 0xf53a, 0, 0, 0, 0, 1])
test.equal(addr.toRFC5952String(), '2001:db8:f53a::1')
test.equal(new ipaddr.IPv6([0, 0, 0, 0, 0, 0, 0, 0]).toRFC5952String(), '::')
test.equal(new ipaddr.IPv6([0, 0, 0, 0, 0, 0, 0, 1]).toRFC5952String(), '::1')
test.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0, 0, 0, 0, 0, 0]).toRFC5952String(), '2001:db8::')
# longest set of zeroes gets collapsed (section 4.2.3)
test.equal(new ipaddr.IPv6([0, 0xff, 0, 0, 0, 0, 0, 0]).toRFC5952String(), '0:ff::')
test.equal(new ipaddr.IPv6([0, 0, 0, 0, 0, 0, 0xff, 0]).toRFC5952String(), '::ff:0')
test.equal(new ipaddr.IPv6([0, 0, 0xff, 0, 0, 0, 0, 0]).toRFC5952String(), '0:0:ff::')
test.equal(new ipaddr.IPv6([0, 0, 0, 0, 0, 0xff, 0, 0]).toRFC5952String(), '::ff:0:0')

test.equal(new ipaddr.IPv6([0x2001, 0, 0, 0, 0xff, 0, 0, 0]).toRFC5952String(), '2001::ff:0:0:0')
test.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0xff, 0xabc, 0xdef, 0x123b, 0x456c, 0x78d]).toRFC5952String(), '2001:db8:ff:abc:def:123b:456c:78d')

# don't shorten single 0s (section 4.2.2)
test.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0xff, 0xabc, 0, 0x123b, 0x456c, 0x78d]).toRFC5952String(), '2001:db8:ff:abc:0:123b:456c:78d')
test.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0xff, 0xabc, 0x78d, 0x123b, 0x456c, 0]).toRFC5952String(), '2001:db8:ff:abc:78d:123b:456c:0')
test.equal(new ipaddr.IPv6([0, 0xdb8, 0xff, 0xabc, 0x78d, 0x123b, 0x456c, 0x2001]).toRFC5952String(), '0:db8:ff:abc:78d:123b:456c:2001')

test.equal(new ipaddr.IPv6([0x2001, 0xdb8, 0xff, 0xabc, 0, 0, 0x456c, 0x78d]).toRFC5952String(), '2001:db8:ff:abc::456c:78d')
test.done()

'returns IPv6 zoneIndex': (test) ->
addr = new ipaddr.IPv6([0x2001, 0xdb8, 0xf53a, 0, 0, 0, 0, 1], 'utun0')
test.equal(addr.toNormalizedString(), '2001:db8:f53a:0:0:0:0:1%utun0')
Expand Down

0 comments on commit 16ec0b2

Please sign in to comment.