Skip to content

Commit 86fa418

Browse files
Earlopainhsbt
authored andcommitted
[ruby/ipaddr] Consider IPv4-mapped IPv6 addresses link local/loopback if IPV4 address is private
Same as #57 ruby/ipaddr@d56acecb80
1 parent da77c79 commit 86fa418

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

lib/ipaddr.rb

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,17 @@ def ipv6?
252252
end
253253

254254
# Returns true if the ipaddr is a loopback address.
255+
# Loopback IPv4 addresses in the IPv4-mapped IPv6
256+
# address range are also considered as loopback addresses.
255257
def loopback?
256258
case @family
257259
when Socket::AF_INET
258-
@addr & 0xff000000 == 0x7f000000
260+
@addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
259261
when Socket::AF_INET6
260-
@addr == 1
262+
@addr == 1 || # ::1
263+
(@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
264+
@addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
265+
))
261266
else
262267
raise AddressFamilyError, "unsupported address family"
263268
end
@@ -287,15 +292,19 @@ def private?
287292
end
288293

289294
# Returns true if the ipaddr is a link-local address. IPv4
290-
# addresses in 169.254.0.0/16 reserved by RFC 3927 and Link-Local
295+
# addresses in 169.254.0.0/16 reserved by RFC 3927 and link-local
291296
# IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are
292-
# considered link-local.
297+
# considered link-local. Link-local IPv4 addresses in the
298+
# IPv4-mapped IPv6 address range are also considered link-local.
293299
def link_local?
294300
case @family
295301
when Socket::AF_INET
296302
@addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
297303
when Socket::AF_INET6
298-
@addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
304+
@addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
305+
(@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
306+
@addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
307+
))
299308
else
300309
raise AddressFamilyError, "unsupported address family"
301310
end

test/test_ipaddr.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ def test_loopback?
415415
assert_equal(true, IPAddr.new('::1').loopback?)
416416
assert_equal(false, IPAddr.new('::').loopback?)
417417
assert_equal(false, IPAddr.new('3ffe:505:2::1').loopback?)
418+
419+
assert_equal(true, IPAddr.new('::ffff:127.0.0.1').loopback?)
420+
assert_equal(true, IPAddr.new('::ffff:127.127.1.1').loopback?)
421+
assert_equal(false, IPAddr.new('::ffff:0.0.0.0').loopback?)
422+
assert_equal(false, IPAddr.new('::ffff:192.168.2.0').loopback?)
423+
assert_equal(false, IPAddr.new('::ffff:255.0.0.0').loopback?)
418424
end
419425

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

484490
assert_equal(true, IPAddr.new('fe80::dead:beef:cafe:1234').link_local?)
491+
492+
assert_equal(false, IPAddr.new('::ffff:0.0.0.0').link_local?)
493+
assert_equal(false, IPAddr.new('::ffff:127.0.0.1').link_local?)
494+
assert_equal(false, IPAddr.new('::ffff:10.0.0.0').link_local?)
495+
assert_equal(false, IPAddr.new('::ffff:172.16.0.0').link_local?)
496+
assert_equal(false, IPAddr.new('::ffff:192.168.0.0').link_local?)
497+
498+
assert_equal(true, IPAddr.new('::ffff:169.254.1.1').link_local?)
499+
assert_equal(true, IPAddr.new('::ffff:169.254.254.255').link_local?)
485500
end
486501

487502
def test_hash

0 commit comments

Comments
 (0)