Skip to content

Append the zone ID after compressing the address in IPAddr#to_s - #127

Merged
taketo1113 merged 1 commit into
ruby:masterfrom
afurm:fix-to-s-zone-id
Oct 10, 2026
Merged

taketo1113 merged 1 commit into
ruby:masterfrom
afurm:fix-to-s-zone-id

Conversation

@afurm

@afurm afurm commented Oct 9, 2026

Copy link
Copy Markdown
Member

IPAddr#to_s runs compression on the string with the zone already appended, so IPAddr.new("::%eth0").to_s gives "::0%eth0", an IPv4-mapped address with a zone loses its dotted form, and zone ids like %0ab become %ab (a different interface). The fix compresses the bare address, then appends the zone. Test added.

IPAddr#to_s ran its zero-compression and IPv4-tail regexps on the
output of #to_string, which already ends with the zone ID. That had
two effects for IPv6 addresses with a zone ID:

* Anchored patterns no longer matched, so "::%eth0" was printed as
  "::0%eth0", and "::ffff:192.168.1.2%eth0" as
  "::ffff:c0a8:102%eth0" instead of using the dotted IPv4 tail.
* The leading-zero stripping also applied to the zone ID, so
  "fe80::1%0ab" was printed as "fe80::1%ab", naming a different zone.

Build the compressed form from the bare address and append the zone ID
at the end.
@afurm
afurm requested a review from knu as a code owner October 9, 2026 17:11
@taketo1113

Copy link
Copy Markdown
Collaborator

Thanks.
I confirmed the following behavior changes.

Zone IDs like %0ab

# Before fix
IPAddr.new("fe80::1%0ab").to_s
#=> "fe80::1%ab"

IPAddr.new("fe80::1%0ab").to_string
#=> "fe80:0000:0000:0000:0000:0000:0000:0001%0ab"

# After fix
IPAddr.new("fe80::1%0ab").to_s
#=> "fe80::1%0ab"

IPAddr.new("fe80::1%0ab").to_string
#=> "fe80:0000:0000:0000:0000:0000:0000:0001%0ab"

"::0%eth0" and IPv4-mapped addresses with a zone ID

# Before fix
IPAddr.new("::0%eth0").to_s
#=> "::0%eth0"

IPAddr.new("::ffff:192.168.1.2%eth0").to_s
#=> "::ffff:c0a8:102%eth0"

IPAddr.new("::ffff:192.168.1.2%eth0").to_string
#=> "0000:0000:0000:0000:0000:ffff:c0a8:0102%eth0"

# After fix
IPAddr.new("::0%eth0").to_s
#=> "::%eth0"

IPAddr.new("::ffff:192.168.1.2%eth0").to_s
#=> "::ffff:192.168.1.2%eth0"

IPAddr.new("::ffff:192.168.1.2%eth0").to_string
#=> "0000:0000:0000:0000:0000:ffff:c0a8:0102%eth0"

The change to the to_s representation of IPv4-mapped IPv6 addresses is also consistent with RFC 5952, which specifies their recommended text representation:

The text representation method noted in Section 4 should be applied
for the leading hexadecimal part (i.e., ::ffff:192.0.2.1 instead of
0:0:0:0:0:ffff:192.0.2.1).

@taketo1113
taketo1113 merged commit c0d36f6 into ruby:master Oct 10, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants