summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ipaddr.rb46
-rw-r--r--test/test_ipaddr.rb26
2 files changed, 67 insertions, 5 deletions
diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb
index c21c0cbf12..48141198ef 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -231,7 +231,13 @@ class IPAddr
# Returns a string containing the IP address representation in
# canonical form.
def to_string
- return _to_string(@addr)
+ str = _to_string(@addr)
+
+ if @family == Socket::AF_INET6
+ str << zone_id.to_s
+ end
+
+ return str
end
# Returns a network byte ordered string form of the IP address.
@@ -403,7 +409,7 @@ class IPAddr
# Returns a hash value used by Hash, Set, and Array classes
def hash
- return ([@addr, @mask_addr].hash << 1) | (ipv4? ? 0 : 1)
+ return ([@addr, @mask_addr, @zone_id].hash << 1) | (ipv4? ? 0 : 1)
end
# Creates a Range object for the network address.
@@ -459,11 +465,12 @@ class IPAddr
af = "IPv4"
when Socket::AF_INET6
af = "IPv6"
+ zone_id = @zone_id.to_s
else
raise AddressFamilyError, "unsupported address family"
end
- return sprintf("#<%s: %s:%s/%s>", self.class.name,
- af, _to_string(@addr), _to_string(@mask_addr))
+ return sprintf("#<%s: %s:%s%s/%s>", self.class.name,
+ af, _to_string(@addr), zone_id, _to_string(@mask_addr))
end
# Returns the netmask in string format e.g. 255.255.0.0
@@ -471,6 +478,31 @@ class IPAddr
_to_string(@mask_addr)
end
+ # Returns the IPv6 zone identifier, if present.
+ # Raises InvalidAddressError if not an IPv6 address.
+ def zone_id
+ if @family == Socket::AF_INET6
+ @zone_id
+ else
+ raise InvalidAddressError, "not an IPv6 address"
+ end
+ end
+
+ # Returns the IPv6 zone identifier, if present.
+ # Raises InvalidAddressError if not an IPv6 address.
+ def zone_id=(zid)
+ if @family == Socket::AF_INET6
+ case zid
+ when nil, /\A%(\w+)\z/
+ @zone_id = zid
+ else
+ raise InvalidAddressError, "invalid zone identifier for address"
+ end
+ else
+ raise InvalidAddressError, "not an IPv6 address"
+ end
+ end
+
protected
# Set +@addr+, the internal stored ip address, to given +addr+. The
@@ -579,6 +611,11 @@ class IPAddr
prefix = $1
family = Socket::AF_INET6
end
+ if prefix =~ /\A(.*)(%\w+)\z/
+ prefix = $1
+ zone_id = $2
+ family = Socket::AF_INET6
+ end
# It seems AI_NUMERICHOST doesn't do the job.
#Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
# Socket::AI_NUMERICHOST)
@@ -593,6 +630,7 @@ class IPAddr
@addr = in6_addr(prefix)
@family = Socket::AF_INET6
end
+ @zone_id = zone_id
if family != Socket::AF_UNSPEC && @family != family
raise AddressFamilyError, "address family mismatch"
end
diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb
index c055f4b2c4..029ad06642 100644
--- a/test/test_ipaddr.rb
+++ b/test/test_ipaddr.rb
@@ -43,6 +43,17 @@ class TC_IPAddr < Test::Unit::TestCase
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(48, a.prefix)
+ assert_nil(a.zone_id)
+
+ a = IPAddr.new("fe80::1%ab0")
+ assert_equal("fe80::1%ab0", a.to_s)
+ assert_equal("fe80:0000:0000:0000:0000:0000:0000:0001%ab0", a.to_string)
+ assert_equal(Socket::AF_INET6, a.family)
+ assert_equal(false, a.ipv4?)
+ assert_equal(true, a.ipv6?)
+ assert_equal("#<IPAddr: IPv6:fe80:0000:0000:0000:0000:0000:0000:0001%ab0/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>", a.inspect)
+ assert_equal(128, a.prefix)
+ assert_equal('%ab0', a.zone_id)
a = IPAddr.new("0.0.0.0")
assert_equal("0.0.0.0", a.to_s)
@@ -87,7 +98,8 @@ class TC_IPAddr < Test::Unit::TestCase
assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.256") }
assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.011") }
- assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%fxp0") }
+ assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%") }
+ assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%]") }
assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("[192.168.1.2]/120") }
assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("[2001:200:300::]\nINVALID") }
assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.1/32\nINVALID") }
@@ -231,6 +243,18 @@ class TC_IPAddr < Test::Unit::TestCase
a = IPAddr.new("192.168.1.2/24")
assert_equal(a.netmask, "255.255.255.0")
end
+
+ def test_zone_id
+ a = IPAddr.new("192.168.1.2")
+ assert_raise(IPAddr::InvalidAddressError) { a.zone_id = '%ab0' }
+ assert_raise(IPAddr::InvalidAddressError) { a.zone_id }
+
+ a = IPAddr.new("1:2:3:4:5:6:7:8")
+ a.zone_id = '%ab0'
+ assert_equal('%ab0', a.zone_id)
+ assert_equal("1:2:3:4:5:6:7:8%ab0", a.to_s)
+ assert_raise(IPAddr::InvalidAddressError) { a.zone_id = '%' }
+ end
end
class TC_Operator < Test::Unit::TestCase