summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--Rakefile1
-rw-r--r--lib/ipaddress.rb90
-rw-r--r--lib/ipaddress/ipv4.rb18
-rw-r--r--lib/ipaddress/ipv6.rb30
-rw-r--r--lib/ipaddress/prefix.rb2
-rw-r--r--test/ipaddress/ipv4_test.rb34
-rw-r--r--test/ipaddress/ipv6_test.rb60
-rw-r--r--test/ipaddress/mongoid_test.rb6
-rw-r--r--test/ipaddress/prefix_test.rb2
-rw-r--r--test/ipaddress_test.rb31
11 files changed, 250 insertions, 25 deletions
diff --git a/.travis.yml b/.travis.yml
index bb08cdb..cd30252 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,6 @@ rvm:
- 2.4
install:
- gem install bundler
-- gem uninstall rake -x
- gem install rake
- bundle install
script:
diff --git a/Rakefile b/Rakefile
index 0948203..220a4da 100644
--- a/Rakefile
+++ b/Rakefile
@@ -9,6 +9,7 @@ Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'test'
test.pattern = 'test/**/*_test.rb'
test.verbose = true
+ test.warning = true
end
begin
diff --git a/lib/ipaddress.rb b/lib/ipaddress.rb
index 19b526f..99591d7 100644
--- a/lib/ipaddress.rb
+++ b/lib/ipaddress.rb
@@ -68,14 +68,14 @@ module IPAddress
#
def self.ntoa(uint)
unless(uint.is_a? Numeric and uint <= 0xffffffff and uint >= 0)
- raise(::ArgumentError, "not a long integer: #{uint.inspect}")
- end
- ret = []
- 4.times do
- ret.unshift(uint & 0xff)
- uint >>= 8
- end
- ret.join('.')
+ raise(::ArgumentError, "not a long integer: #{uint.inspect}")
+ end
+ ret = []
+ 4.times do
+ ret.unshift(uint & 0xff)
+ uint >>= 8
+ end
+ ret.join('.')
end
#
@@ -102,22 +102,88 @@ module IPAddress
self.kind_of? IPAddress::IPv6
end
+
+ #
+ # Checks if the given string is either a valid IP, either a valid IPv4 subnet
+ #
+ # Example:
+ #
+ # IPAddress::valid? "10.0.0.0/24"
+ # #=> true
+ #
+ # IPAddress::valid? "2002::1"
+ # #=> true
+ #
+ # IPAddress::valid? "10.0.0.256"
+ # #=> false
+ #
+ # IPAddress::valid? "10.0.0.0/999"
+ # #=> false
+ #
+ def self.valid?(addr)
+ valid_ip?(addr) || valid_ipv4_subnet?(addr) || valid_ipv6_subnet?(addr)
+ end
+
#
# Checks if the given string is a valid IP address,
# either IPv4 or IPv6
#
# Example:
#
- # IPAddress::valid? "2002::1"
+ # IPAddress::valid_ip? "2002::1"
# #=> true
#
- # IPAddress::valid? "10.0.0.256"
+ # IPAddress::valid_ip? "10.0.0.256"
# #=> false
#
- def self.valid?(addr)
+ def self.valid_ip?(addr)
valid_ipv4?(addr) || valid_ipv6?(addr)
end
-
+
+ #
+ # Checks if the given string is a valid IPv4 subnet
+ #
+ # Example:
+ #
+ # IPAdress::valid_ipv4_subnet? "10.0.0.0/24"
+ # #=> true
+ #
+ # IPAdress::valid_ipv4_subnet? "10.0.0.0/255.255.255.0"
+ # #=> true
+ #
+ # IPAdress::valid_ipv4_subnet? "10.0.0.0/64"
+ # #=> false
+ #
+ def self.valid_ipv4_subnet?(addr)
+ ip, netmask = addr.split("/")
+
+ valid_ipv4?(ip) && (!(netmask =~ /\A([12]?\d|3[0-2])\z/).nil? || valid_ipv4_netmask?(netmask))
+ end
+
+ #
+ # Checks if the given string is a valid IPv6 subnet
+ #
+ # Example:
+ #
+ # IPAdress::valid_ipv6_subnet? "::/0"
+ # #=> true
+ #
+ # IPAdress::valid_ipv6_subnet? "dead:beef:cafe:babe::/64"
+ # #=> true
+ #
+ # IPAdress::valid_ipv6_subnet? "2001::1/129"
+ # #=> false
+ #
+ def self.valid_ipv6_subnet?(addr)
+ ip, netmask = addr.split("/")
+
+ netmask = Integer(netmask, 10)
+
+ valid_ipv6?(ip) && netmask >= 0 && netmask <= 128
+ rescue ArgumentError
+ false
+ end
+
#
# Checks if the given string is a valid IPv4 address
#
diff --git a/lib/ipaddress/ipv4.rb b/lib/ipaddress/ipv4.rb
index 080f3d6..70d1a51 100644
--- a/lib/ipaddress/ipv4.rb
+++ b/lib/ipaddress/ipv4.rb
@@ -61,6 +61,7 @@ module IPAddress;
# IPAddress::IPv4.new "10.0.0.1/255.0.0.0"
#
def initialize(str)
+ raise ArgumentError, "Nil IP" unless str
ip, netmask = str.split("/")
# Check the ip and remove white space
@@ -510,6 +511,7 @@ module IPAddress;
# #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
#
def <=>(oth)
+ return nil unless oth.is_a?(self.class)
return prefix <=> oth.prefix if to_u32 == oth.to_u32
to_u32 <=> oth.to_u32
end
@@ -650,6 +652,20 @@ module IPAddress;
end
#
+ # Checks if an IPv4 address objects belongs
+ # to a link-local network RFC3927
+ #
+ # Example:
+ #
+ # ip = IPAddress "169.254.0.1"
+ # ip.link_local?
+ # #=> true
+ #
+ def link_local?
+ [self.class.new("169.254.0.0/16")].any? {|i| i.include? self}
+ end
+
+ #
# Returns the IP address in in-addr.arpa format
# for DNS lookups
#
@@ -772,7 +788,7 @@ module IPAddress;
#
# we can calculate the subnets with a /26 prefix
#
- # ip.subnets(26).map{&:to_string)
+ # ip.subnet(26).map{&:to_string)
# #=> ["172.16.10.0/26", "172.16.10.64/26",
# "172.16.10.128/26", "172.16.10.192/26"]
#
diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb
index 284308c..f427954 100644
--- a/lib/ipaddress/ipv6.rb
+++ b/lib/ipaddress/ipv6.rb
@@ -87,6 +87,7 @@ module IPAddress;
# ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
#
def initialize(str)
+ raise ArgumentError, "Nil IP" unless str
ip, netmask = str.split("/")
if str =~ /:.+\./
@@ -423,6 +424,34 @@ module IPAddress;
@prefix == 128 and @compressed == "::1"
end
+ #
+ # Checks if an IPv6 address objects belongs
+ # to a link-local network RFC4291
+ #
+ # Example:
+ #
+ # ip = IPAddress "fe80::1"
+ # ip.link_local?
+ # #=> true
+ #
+ def link_local?
+ [self.class.new("fe80::/64")].any? {|i| i.include? self}
+ end
+
+ #
+ # Checks if an IPv6 address objects belongs
+ # to a unique-local network RFC4193
+ #
+ # Example:
+ #
+ # ip = IPAddress "fc00::1"
+ # ip.unique_local?
+ # #=> true
+ #
+ def unique_local?
+ [self.class.new("fc00::/7")].any? {|i| i.include? self}
+ end
+
#
# Returns true if the address is a mapped address
#
@@ -495,6 +524,7 @@ module IPAddress;
# #=> ["2001:db8:1::1/64","2001:db8:1::1/65","2001:db8:2::1/64"]
#
def <=>(oth)
+ return nil unless oth.is_a?(self.class)
return prefix <=> oth.prefix if to_u128 == oth.to_u128
to_u128 <=> oth.to_u128
end
diff --git a/lib/ipaddress/prefix.rb b/lib/ipaddress/prefix.rb
index 136f2d3..e819800 100644
--- a/lib/ipaddress/prefix.rb
+++ b/lib/ipaddress/prefix.rb
@@ -78,7 +78,7 @@ module IPAddress
end
end
- end # class Prefix
+ end # class Prefix
class Prefix32 < Prefix
diff --git a/test/ipaddress/ipv4_test.rb b/test/ipaddress/ipv4_test.rb
index df60bb1..19e0450 100644
--- a/test/ipaddress/ipv4_test.rb
+++ b/test/ipaddress/ipv4_test.rb
@@ -74,6 +74,22 @@ class IPv4Test < Minitest::Test
"10.32.0.1" => ["10.32.0.253", 253],
"192.0.0.0" => ["192.1.255.255", 131072]
}
+
+ @link_local = [
+ "169.254.0.0",
+ "169.254.255.255",
+ "169.254.12.34",
+ "169.254.0.0/16",
+ "169.254.0.0/17"]
+
+ @not_link_local = [
+ "127.0.0.1",
+ "127.0.1.1",
+ "192.168.0.100",
+ "169.255.0.0",
+ "169.254.0.0/15",
+ "0.0.0.0",
+ "255.255.255.255"]
end
@@ -83,7 +99,7 @@ class IPv4Test < Minitest::Test
assert_instance_of @klass, ip
end
assert_instance_of IPAddress::Prefix32, @ip.prefix
- assert_raises (ArgumentError) do
+ assert_raises(ArgumentError) do
@klass.new
end
end
@@ -92,6 +108,7 @@ class IPv4Test < Minitest::Test
@invalid_ipv4.each do |i|
assert_raises(ArgumentError) {@klass.new(i)}
end
+ assert_raises (ArgumentError) {@klass.new(nil)}
assert_raises (ArgumentError) {@klass.new("10.0.0.0/asd")}
end
@@ -309,6 +326,15 @@ class IPv4Test < Minitest::Test
assert_equal false, @klass.new("192.0.0.2/24").private?
end
+ def test_method_link_local?
+ @link_local.each do |addr|
+ assert_equal true, @klass.new(addr).link_local?
+ end
+ @not_link_local.each do |addr|
+ assert_equal false, @klass.new(addr).link_local?
+ end
+ end
+
def test_method_octet
assert_equal 172, @ip[0]
assert_equal 16, @ip[1]
@@ -372,6 +398,12 @@ class IPv4Test < Minitest::Test
ip3 = @klass.new("10.0.0.0/8")
arr = ["10.0.0.0/8","10.0.0.0/16","10.0.0.0/24"]
assert_equal arr, [ip1,ip2,ip3].sort.map{|s| s.to_string}
+ # compare with alien thing
+ ip1 = @klass.new('127.0.0.1')
+ ip2 = IPAddress::IPv6.new('::1')
+ not_ip = String
+ assert_equal nil, ip1 <=> ip2
+ assert_equal nil, ip1 <=> not_ip
end
def test_method_minus
diff --git a/test/ipaddress/ipv6_test.rb b/test/ipaddress/ipv6_test.rb
index 3990129..9d7736d 100644
--- a/test/ipaddress/ipv6_test.rb
+++ b/test/ipaddress/ipv6_test.rb
@@ -26,9 +26,7 @@ class IPv6Test < Minitest::Test
"::1" => 1,
"0:0:0:0:0:0:0:0" => 0,
"0:0:0::0:0:0" => 0,
- "::" => 0,
- "1080:0:0:0:8:800:200C:417A" => 21932261930451111902915077091070067066,
- "1080::8:800:200C:417A" => 21932261930451111902915077091070067066}
+ "::" => 0}
@invalid_ipv6 = [":1:2:3:4:5:6:7",
":1:2:3:4:5:6:7",
@@ -44,6 +42,37 @@ class IPv6Test < Minitest::Test
@network = @klass.new "2001:db8:8:800::/64"
@arr = [8193,3512,0,0,8,2048,8204,16762]
@hex = "20010db80000000000080800200c417a"
+
+ @link_local = [
+ "fe80::",
+ "fe80::1",
+ "fe80::208:74ff:feda:625c",
+ "fe80::/64",
+ "fe80::/65"]
+
+ @not_link_local = [
+ "::",
+ "::1",
+ "ff80:03:02:01::",
+ "2001:db8::8:800:200c:417a",
+ "fe80::/63"]
+
+ @unique_local = [
+ "fc00::/7",
+ "fc00::/8",
+ "fd00::/8",
+ "fd12:3456:789a:1::1",
+ "fd12:3456:789a:1::/64",
+ "fc00::1"]
+
+ @not_unique_local = [
+ "fc00::/6",
+ "::",
+ "::1",
+ "fe80::",
+ "fe80::1",
+ "fe80::/64"]
+
end
def test_attribute_address
@@ -58,6 +87,7 @@ class IPv6Test < Minitest::Test
end
assert_equal 64, @ip.prefix
+ assert_raises(ArgumentError) {@klass.new nil }
assert_raises(ArgumentError) {
@klass.new "::10.1.1.1"
}
@@ -216,6 +246,24 @@ class IPv6Test < Minitest::Test
assert_equal false, @ip.loopback?
end
+ def test_method_link_local?
+ @link_local.each do |addr|
+ assert_equal true, @klass.new(addr).link_local?
+ end
+ @not_link_local.each do |addr|
+ assert_equal false, @klass.new(addr).link_local?
+ end
+ end
+
+ def test_method_unique_local?
+ @unique_local.each do |addr|
+ assert_equal true, @klass.new(addr).unique_local?
+ end
+ @not_unique_local.each do |addr|
+ assert_equal false, @klass.new(addr).unique_local?
+ end
+ end
+
def test_method_network
@networks.each do |addr,net|
ip = @klass.new addr
@@ -284,6 +332,12 @@ class IPv6Test < Minitest::Test
arr = ["2001:db8:1::1/64","2001:db8:1::1/65",
"2001:db8:1::2/64","2001:db8:2::1/64"]
assert_equal arr, [ip1,ip2,ip3,ip4].sort.map{|s| s.to_string}
+ # compare with alien thing
+ ip1 = @klass.new('::1')
+ ip2 = IPAddress::IPv4.new('127.0.0.1')
+ not_ip = String
+ assert_equal nil, ip1 <=> ip2
+ assert_equal nil, ip1 <=> not_ip
end
def test_classmethod_expand
diff --git a/test/ipaddress/mongoid_test.rb b/test/ipaddress/mongoid_test.rb
index b463e84..4f32093 100644
--- a/test/ipaddress/mongoid_test.rb
+++ b/test/ipaddress/mongoid_test.rb
@@ -38,7 +38,7 @@ class MongoidTest < Minitest::Test
@invalid_values.each do |invalid_value|
# Invalid addresses should serialize to nil
- assert_equal nil, IPAddress.mongoize(invalid_value)
+ assert_nil IPAddress.mongoize(invalid_value)
end
end
@@ -57,7 +57,7 @@ class MongoidTest < Minitest::Test
@invalid_values.each do |invalid_value|
# Invalid stored value should be loaded as nil
- assert_equal nil, IPAddress.demongoize(invalid_value)
+ assert_nil IPAddress.demongoize(invalid_value)
end
end
@@ -67,4 +67,4 @@ class MongoidTest < Minitest::Test
assert_equal IPAddress.mongoize(@valid_network4), IPAddress.evolve(@valid_network4)
end
-end \ No newline at end of file
+end
diff --git a/test/ipaddress/prefix_test.rb b/test/ipaddress/prefix_test.rb
index 1a0e277..f0a3d8c 100644
--- a/test/ipaddress/prefix_test.rb
+++ b/test/ipaddress/prefix_test.rb
@@ -132,7 +132,7 @@ class Prefix128Test < Minitest::Test
end
def test_initialize
- assert_raises (ArgumentError) do
+ assert_raises(ArgumentError) do
@klass.new 129
end
assert_instance_of @klass, @klass.new(64)
diff --git a/test/ipaddress_test.rb b/test/ipaddress_test.rb
index 862c889..d5bdf60 100644
--- a/test/ipaddress_test.rb
+++ b/test/ipaddress_test.rb
@@ -59,6 +59,17 @@ class IPAddressTest < Minitest::Test
end
def test_module_method_valid?
+ assert_equal true, IPAddress::valid?("10.0.0.0/24")
+ assert_equal true, IPAddress::valid?("10.0.0.0/255.255.255.0")
+ assert_equal false, IPAddress::valid?("10.0.0.0/64")
+ assert_equal false, IPAddress::valid?("10.0.0.0/255.255.255.256")
+ assert_equal true, IPAddress::valid?("::/0")
+ assert_equal true, IPAddress::valid?("2002::1/128")
+ assert_equal true, IPAddress::valid?("dead:beef:cafe:babe::/64")
+ assert_equal false, IPAddress::valid?("2002::1/129")
+ end
+
+ def test_module_method_valid_ip?
assert_equal true, IPAddress::valid?("10.0.0.1")
assert_equal true, IPAddress::valid?("10.0.0.0")
assert_equal true, IPAddress::valid?("2002::1")
@@ -69,14 +80,30 @@ class IPAddressTest < Minitest::Test
assert_equal false, IPAddress::valid?("10.0")
assert_equal false, IPAddress::valid?("2002:::1")
assert_equal false, IPAddress::valid?("2002:516:2:200")
-
end
- def test_module_method_valid_ipv4_netmark?
+ def test_module_method_valid_ipv4_netmask?
assert_equal true, IPAddress::valid_ipv4_netmask?("255.255.255.0")
assert_equal false, IPAddress::valid_ipv4_netmask?("10.0.0.1")
end
+ def test_module_method_valid_ipv4_subnet?
+ assert_equal true, IPAddress::valid_ipv4_subnet?("10.0.0.0/255.255.255.0")
+ assert_equal true, IPAddress::valid_ipv4_subnet?("10.0.0.0/0")
+ assert_equal true, IPAddress::valid_ipv4_subnet?("10.0.0.0/32")
+ assert_equal false, IPAddress::valid_ipv4_subnet?("10.0.0.0/ABC")
+ assert_equal false, IPAddress::valid_ipv4_subnet?("10.0.0.1")
+ assert_equal false, IPAddress::valid_ipv4_subnet?("10.0.0.0/33")
+ assert_equal false, IPAddress::valid_ipv4_subnet?("10.0.0.256/24")
+ assert_equal false, IPAddress::valid_ipv4_subnet?("10.0.0.0/255.255.255.256")
+ end
+
+ def test_module_method_valid_ipv6_subnet?
+ assert_equal true, IPAddress::valid_ipv6_subnet?("::/0")
+ assert_equal true, IPAddress::valid_ipv6_subnet?("2002::1/128")
+ assert_equal true, IPAddress::valid_ipv6_subnet?("dead:beef:cafe:babe::/64")
+ assert_equal false, IPAddress::valid_ipv6_subnet?("2002::1/129")
+ end
end