Skip to content

Commit

Permalink
[ruby/ipaddr] Consider IPv4-mapped IPv6 addresses link local/loopback…
Browse files Browse the repository at this point in the history
… if IPV4 address is private

Same as #57

ruby/ipaddr@d56acecb80
  • Loading branch information
Earlopain authored and hsbt committed Dec 25, 2023
1 parent da77c79 commit 86fa418
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
19 changes: 14 additions & 5 deletions lib/ipaddr.rb
Expand Up @@ -252,12 +252,17 @@ def ipv6?
end

# Returns true if the ipaddr is a loopback address.
# Loopback IPv4 addresses in the IPv4-mapped IPv6
# address range are also considered as loopback addresses.
def loopback?
case @family
when Socket::AF_INET
@addr & 0xff000000 == 0x7f000000
@addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
when Socket::AF_INET6
@addr == 1
@addr == 1 || # ::1
(@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
@addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
))
else
raise AddressFamilyError, "unsupported address family"
end
Expand Down Expand Up @@ -287,15 +292,19 @@ def private?
end

# Returns true if the ipaddr is a link-local address. IPv4
# addresses in 169.254.0.0/16 reserved by RFC 3927 and Link-Local
# addresses in 169.254.0.0/16 reserved by RFC 3927 and link-local
# IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are
# considered link-local.
# considered link-local. Link-local IPv4 addresses in the
# IPv4-mapped IPv6 address range are also considered link-local.
def link_local?
case @family
when Socket::AF_INET
@addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
when Socket::AF_INET6
@addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
@addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
(@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
@addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
))
else
raise AddressFamilyError, "unsupported address family"
end
Expand Down
15 changes: 15 additions & 0 deletions test/test_ipaddr.rb
Expand Up @@ -415,6 +415,12 @@ def test_loopback?
assert_equal(true, IPAddr.new('::1').loopback?)
assert_equal(false, IPAddr.new('::').loopback?)
assert_equal(false, IPAddr.new('3ffe:505:2::1').loopback?)

assert_equal(true, IPAddr.new('::ffff:127.0.0.1').loopback?)
assert_equal(true, IPAddr.new('::ffff:127.127.1.1').loopback?)
assert_equal(false, IPAddr.new('::ffff:0.0.0.0').loopback?)
assert_equal(false, IPAddr.new('::ffff:192.168.2.0').loopback?)
assert_equal(false, IPAddr.new('::ffff:255.0.0.0').loopback?)
end

def test_private?
Expand Down Expand Up @@ -482,6 +488,15 @@ def test_link_local?
assert_equal(false, IPAddr.new('fb84:8bf7:e905::1').link_local?)

assert_equal(true, IPAddr.new('fe80::dead:beef:cafe:1234').link_local?)

assert_equal(false, IPAddr.new('::ffff:0.0.0.0').link_local?)
assert_equal(false, IPAddr.new('::ffff:127.0.0.1').link_local?)
assert_equal(false, IPAddr.new('::ffff:10.0.0.0').link_local?)
assert_equal(false, IPAddr.new('::ffff:172.16.0.0').link_local?)
assert_equal(false, IPAddr.new('::ffff:192.168.0.0').link_local?)

assert_equal(true, IPAddr.new('::ffff:169.254.1.1').link_local?)
assert_equal(true, IPAddr.new('::ffff:169.254.254.255').link_local?)
end

def test_hash
Expand Down

0 comments on commit 86fa418

Please sign in to comment.