Skip to content

Commit

Permalink
Add IPAddr#prefix
Browse files Browse the repository at this point in the history
This (kind of) addresses [Feature #11210](https://bugs.ruby-lang.org/issues/11210).
  • Loading branch information
knu committed Sep 19, 2017
1 parent 2300793 commit 293ad5a
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 3 deletions.
32 changes: 31 additions & 1 deletion lib/ipaddr.rb
Expand Up @@ -371,6 +371,35 @@ def to_range
return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
end

# Returns the prefix length in bits for the ipaddr.
def prefix
case @family
when Socket::AF_INET
n = IN4MASK ^ @mask_addr
i = 32
when Socket::AF_INET6
n = IN6MASK ^ @mask_addr
i = 128
else
raise AddressFamilyError, "unsupported address family"
end
while n.positive?
n >>= 1
i -= 1
end
i
end

# Sets the prefix length in bits
def prefix=(prefix)
case prefix
when Integer
mask!(prefix)
else
raise InvalidPrefixError, "prefix must be an integer"
end
end

# Returns a string containing a human-readable representation of the
# ipaddr. ("#<IPAddr: family:address/mask>")
def inspect
Expand Down Expand Up @@ -413,7 +442,8 @@ def set(addr, *family)

# Set current netmask to given mask.
def mask!(mask)
if mask.kind_of?(String)
case mask
when String
if mask =~ /\A\d+\z/
prefixlen = mask.to_i
else
Expand Down
40 changes: 38 additions & 2 deletions test/test_ipaddr.rb
Expand Up @@ -21,11 +21,13 @@ def test_s_new
assert_equal("::", a.to_s)
assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(128, a.prefix)

a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
assert_equal(Socket::AF_INET6, a.family)
assert_equal(128, a.prefix)

a = IPAddr.new("3ffe:505:2::/48")
assert_equal("3ffe:505:2::", a.to_s)
Expand All @@ -34,34 +36,47 @@ def test_s_new
assert_equal(false, a.ipv4?)
assert_equal(true, a.ipv6?)
assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect)
assert_equal(48, a.prefix)

a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
assert_equal("3ffe:505:2::", a.to_s)
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)

a = IPAddr.new("0.0.0.0")
assert_equal("0.0.0.0", a.to_s)
assert_equal("0.0.0.0", a.to_string)
assert_equal(Socket::AF_INET, a.family)
assert_equal(32, a.prefix)

a = IPAddr.new("192.168.1.2")
assert_equal("192.168.1.2", a.to_s)
assert_equal("192.168.1.2", a.to_string)
assert_equal(Socket::AF_INET, a.family)
assert_equal(true, a.ipv4?)
assert_equal(false, a.ipv6?)
assert_equal(32, a.prefix)

a = IPAddr.new("192.168.1.2/24")
a = IPAddr.new("192.168.1.2/26")
assert_equal("192.168.1.0", a.to_s)
assert_equal("192.168.1.0", a.to_string)
assert_equal(Socket::AF_INET, a.family)
assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.0>", a.inspect)
assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.192>", a.inspect)
assert_equal(26, a.prefix)

a = IPAddr.new("192.168.1.2/255.255.255.0")
assert_equal("192.168.1.0", a.to_s)
assert_equal("192.168.1.0", a.to_string)
assert_equal(Socket::AF_INET, a.family)
assert_equal(24, a.prefix)

(0..32).each do |prefix|
assert_equal(prefix, IPAddr.new("10.20.30.40/#{prefix}").prefix)
end
(0..128).each do |prefix|
assert_equal(prefix, IPAddr.new("1:2:3:4:5:6:7:8/#{prefix}").prefix)
end

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)
Expand Down Expand Up @@ -153,6 +168,27 @@ def test_ip6_int
}
end

def test_prefix_writer
a = IPAddr.new("192.168.1.2")
["1", "255.255.255.0", "ffff:ffff:ffff:ffff::", nil, 1.0, -1, 33].each { |x|
assert_raise(IPAddr::InvalidPrefixError) { a.prefix = x }
}
a = IPAddr.new("1:2:3:4:5:6:7:8")
["1", "255.255.255.0", "ffff:ffff:ffff:ffff::", nil, 1.0, -1, 129].each { |x|
assert_raise(IPAddr::InvalidPrefixError) { a.prefix = x }
}

a = IPAddr.new("192.168.1.2")
a.prefix = 26
assert_equal(26, a.prefix)
assert_equal("192.168.1.0", a.to_s)

a = IPAddr.new("1:2:3:4:5:6:7:8")
a.prefix = 52
assert_equal(52, a.prefix)
assert_equal("1:2:3::", a.to_s)
end

def test_to_s
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string)
assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s)
Expand Down

0 comments on commit 293ad5a

Please sign in to comment.