From d56acecb806760776b38077cb69d2ff689adfde6 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Sat, 16 Dec 2023 13:58:58 +0100 Subject: [PATCH] Consider IPv4-mapped IPv6 addresses link local/loopback if IPV4 address is private Same as #57 --- lib/ipaddr.rb | 19 ++++++++++++++----- test/test_ipaddr.rb | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb index 03e1c18..0ec6143 100644 --- a/lib/ipaddr.rb +++ b/lib/ipaddr.rb @@ -247,12 +247,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 @@ -282,15 +287,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 diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb index 90a7fc3..9b5d5a5 100644 --- a/test/test_ipaddr.rb +++ b/test/test_ipaddr.rb @@ -396,6 +396,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? @@ -463,6 +469,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