diff --git a/lib/resolv.rb b/lib/resolv.rb index bac338c..f8f2b23 100644 --- a/lib/resolv.rb +++ b/lib/resolv.rb @@ -3347,7 +3347,31 @@ def initialize(address) # :nodoc: attr_reader :address def to_s # :nodoc: - sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::') + words = @address.unpack("nnnnnnnn") + + # RFC 5952 Section 4.2.3: compress the longest run of two or more + # zero fields, choosing the first one when runs are equally long. + best_start = best_len = nil + i = 0 + while i < 8 + if words[i] == 0 + j = i + j += 1 while j < 8 && words[j] == 0 + if j - i >= 2 && (best_len.nil? || j - i > best_len) + best_start, best_len = i, j - i + end + i = j + else + i += 1 + end + end + + hex = words.map {|word| sprintf("%x", word) } + return hex.join(":") unless best_start + + head = hex[0, best_start].join(":") + tail = hex[(best_start + best_len)..-1].join(":") + "#{head}::#{tail}" end def inspect # :nodoc: diff --git a/test/resolv/test_dns.rb b/test/resolv/test_dns.rb index b8ecef2..8544a0a 100644 --- a/test/resolv/test_dns.rb +++ b/test/resolv/test_dns.rb @@ -622,8 +622,12 @@ def test_ipv6_to_s ["2001::", "2001::0"], ["2001:db8:0:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"], # RFC 5952 Section 4.2.2. ["2001:db8::1:1:1:1", "2001:db8:0:0:1:1:1:1"], - ["1::1:0:0:0:1", "1:0:0:1:0:0:0:1"], + ["1:0:0:1::1", "1:0:0:1:0:0:0:1"], # RFC 5952 Section 4.2.3. ["1::1:0:0:1", "1:0:0:0:1:0:0:1"], + ["2001:db8::1:0:0:1", "2001:db8:0:0:1:0:0:1"], # RFC 5952 Section 4.2.3. + ["2001:0:0:1::", "2001:0:0:1:0:0:0:0"], + ["::1:0:0:1", "0:0:0:0:1:0:0:1"], + ["1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8"], ] test_cases.each do |expected, ipv6|