From a540d51a3176374ddfe5f8b678bf28eba3a9fa47 Mon Sep 17 00:00:00 2001 From: Taketo Takashima Date: Fri, 16 Oct 2026 11:05:27 +0900 Subject: [PATCH] Warn on bracketed IPv6 address with a prefix length IPAddr.new("[2001:db8::]/32") is currently accepted and treated the same as IPAddr.new("2001:db8::/32"). However, square brackets are a delimiter for embedding an address in a larger syntax such as host:port (RFC 5952 section 6), and no notation is defined for a prefix length after the closing bracket. Print a warning for this form, saying that it will raise IPAddr::InvalidAddressError in a future version. The result is unchanged for now. "[2001:db8::]" and "2001:db8::/32" are not affected. --- lib/ipaddr.rb | 7 +++++++ test/test_ipaddr.rb | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb index 51c6898..e6a888b 100644 --- a/lib/ipaddr.rb +++ b/lib/ipaddr.rb @@ -717,6 +717,7 @@ def initialize(addr = '::', family = Socket::AF_UNSPEC) if prefix =~ /\A\[(.*)\]\z/i prefix = $1 family = Socket::AF_INET6 + bracketed = true end if prefix =~ /\A(.*)(%\w+)\z/ prefix = $1 @@ -743,6 +744,12 @@ def initialize(addr = '::', family = Socket::AF_UNSPEC) end if prefixlen mask!(prefixlen) + + if bracketed + warn "bracketed IPv6 address with a prefix length is an invalid address " \ + "and will raise IPAddr::InvalidAddressError in a future version: #{addr}", + uplevel: 1 + end else @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK end diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb index 3b73664..9a4e345 100644 --- a/test/test_ipaddr.rb +++ b/test/test_ipaddr.rb @@ -100,7 +100,9 @@ def test_s_new assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s) assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s) - assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s) + assert_warning(/will raise IPAddr::InvalidAddressError/) { + assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s) + } assert_equal("1:2:3:4:5:6:7:0", IPAddr.new("1:2:3:4:5:6:7::").to_s) assert_equal("0:2:3:4:5:6:7:8", IPAddr.new("::2:3:4:5:6:7:8").to_s) @@ -772,4 +774,16 @@ def test_raises_invalid_address_error_with_error_message end assert_equal('invalid address: INVALID', e.message) end + + def test_s_new_bracketed_with_prefix_is_deprecated + assert_warning(/will raise IPAddr::InvalidAddressError/) { + assert_equal("2001:db8::", IPAddr.new("[2001:db8::]/32").to_s) + } + assert_warning(/will raise IPAddr::InvalidAddressError/) { + assert_equal("2001:db8::", IPAddr.new("[2001:db8::]/ffff:ffff::").to_s) + } + + assert_warning("") { assert_equal("2001:db8::", IPAddr.new("[2001:db8::]").to_s) } + assert_warning("") { assert_equal("2001:db8::", IPAddr.new("2001:db8::/32").to_s) } + end end