ruby/ipaddr

#native results in incorrect mask, breaking #prefix

zarqman opened this issue · 2 comments

Calling native leaves the internal @mask_addr as its ipv6 mask instead of converting it to an ipv4 mask. This is most easily seen when calling prefix, but also breaks to_range and possibly other methods.

IPAddr.new('::ffff:1.2.3.4/127')
# => #<IPAddr: IPv6:0000:0000:0000:0000:0000:ffff:0102:0304/ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe> 
IPAddr.new('::ffff:1.2.3.4/127').prefix
# => 127 
IPAddr.new('::ffff:1.2.3.4/127').native
# => #<IPAddr: IPv4:1.2.3.4/255.255.255.254> 
IPAddr.new('::ffff:1.2.3.4/127').native.prefix
# => -96                <-- should be 31
IPAddr.new('1.2.3.4/31').prefix
# => 31 
IPAddr.new('::ffff:1.2.3.4/127').native.instance_variable_get :@mask_addr
# => 340282366920938463463374607431768211454       <-- root issue

Similarly, ipv4_mapped and ipv4_compat also fail to adjust @mask_addr the other direction.

IPAddr.new('1.2.3.4/31').ipv4_mapped
# => #<IPAddr: IPv6:0000:0000:0000:0000:0000:ffff:0102:0304/0000:0000:0000:0000:0000:0000:ffff:fffe> 
IPAddr.new('1.2.3.4/31').ipv4_mapped.prefix
# => 0                  <-- should be 127
IPAddr.new('1.2.3.4/31').ipv4_mapped.instance_variable_get :@mask_addr
# => 4294967294 

IPAddr.new('1.2.3.4/31').ipv4_compat
# => #<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0102:0304/0000:0000:0000:0000:0000:0000:ffff:fffe> 
IPAddr.new('1.2.3.4/31').ipv4_compat.prefix
# => 0 
IPAddr.new('1.2.3.4/31').ipv4_compat.instance_variable_get :@mask_addr
# => 4294967294 

#34 fixed #native.
#31 fixed #ipv4_mapped.

#ipv4_compat still returns an inconsistent mask. As it's been deprecated (in IETF and in this library), I don't think we need to maintain it.
However, this violation in object invariant ("the netmask must be consecutive 1s followed by consecutive 0s") may cause other problems and I'd propose fixing it like #ipv4_mapped if we cannot remove #ipv4_compat now.

#18 also tried to resolve this issue regarding netmask conversion in a consistent way.