Bug #13769


IPAddr#ipv4_compat incorrect behavior

Added by arkadiyt (Arkadiy Tetelman) almost 5 years ago. Updated over 4 years ago.

Target version:
ruby -v:
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-darwin14]


To ease transition from IPv4 to IPv6, there exist "ipv4-compatible" and "ipv4-mapped" addresses, which are ipv6 addresses that embed an ipv4 address inside them.

Ruby's IPAddr defines several helper functions related to this:
IPAddr#ipv4_mapped? -> return true if the ipaddr is an ipv4-mapped ipv6 address
IPAddr#ipv4_compat? -> return true if the ipaddr is an ipv4-compatible ipv6 address

These 2 formats are defined in RFC4291 section 2.5.5, here:

Notably for ipv4-compatible addresses, it says the following:

The "IPv4-Compatible IPv6 address" was defined to assist in the IPv6
   transition.  The format of the "IPv4-Compatible IPv6 address" is as

   |                80 bits               | 16 |      32 bits        |
   |0000..............................0000|0000|    IPv4 address     |

   Note: The IPv4 address used in the "IPv4-Compatible IPv6 address"
   must be a globally-unique IPv4 unicast address.

But this is not the behavior of IPAddr#ipv4_compat?, defined here:

Given an ipv6 address it checks that the top 96 bits are 0, but then also that the last 32 bits are not equal to 0 or 1, so we have:

2.2.1 :002 >'::').ipv4_compat?
 => false
2.2.1 :003 >'::').ipv4_compat?
 => false

It seems like those should return true.


Perhaps this is related to the last sentence of the RFC: "The IPv4 address used in the "IPv4-Compatible IPv6 address must be a globally-unique IPv4 unicast address.". Since and are not globally-unique unicast addresses, that might justify the false return value. Under this reasoning the function is still wrong in that it only returns false for those 2 IPv4 addresses, when there are many other non-globally-unique unicast addresses - see here for some:

It's not clear why and are given this special treatment. The commit was made in 2002 and predates Ruby 1.9.3:

Updated by Glass_saga (Masaki Matsushita) over 4 years ago

  • Target version set to 2.5

RFC4291 says: '"IPv4-Compatible IPv6 address" is now deprecated.'
We can remove #ipv4_compat? or mark it as deprecated.


The "IPv4-Compatible IPv6 address" is now deprecated because the
current IPv6 transition mechanisms no longer use these addresses.
New or updated implementations are not required to support this
address type.

Updated by arkadiyt (Arkadiy Tetelman) over 4 years ago

I'd vote for marking it deprecated & fixing the bug in the original ticket. Despite the fact that the addresses are now deprecated, it may be useful for ruby code to interact with or check for legacy situations - that's how I found the bug

Updated by Glass_saga (Masaki Matsushita) over 4 years ago

  • Assignee set to knu (Akinori MUSHA)
  • Status changed from Open to Assigned

Updated by knu (Akinori MUSHA) over 4 years ago

Agreed with deprecating it. Other libraries like the ipaddress gem do not seem to have this, so I'll remove it by 2.5.

Updated by knu (Akinori MUSHA) over 4 years ago

I guess :: and ::1 are the only exceptions listed because they are the only IPv6 addresses with the 80+16 bit zero prefix that already have special, conflicting meanings as IPv6 address, so I consider it was practically reasonable enough not to bother with all the other possible non-public IPv4 addresses.

Updated by knu (Akinori MUSHA) over 4 years ago

While I do understand the need for dealing with legacy situations, changing the current behavior can cause a subtle bug with rarely maintained code without being noticed immediately.

I'd rather just remove it so that breakage is noticeable because one would soon get a NoMethodError.

Updated by knu (Akinori MUSHA) over 4 years ago

I'll mark IPAddr#ipv4_compat and #ipv4_compat? as deprecated in Ruby 2.5 / ipaddr 1.x and remove them in Ruby 2.6 / ipaddr 2.x.

Updated by knu (Akinori MUSHA) over 4 years ago

Depreation warning added in r60270. Thanks!

Actions #9

Updated by knu (Akinori MUSHA) over 4 years ago

  • Status changed from Assigned to Closed

Applied in changeset trunk|r60272.

Fix the issue reference to [Bug #13769], handled in r60270


Also available in: Atom PDF