summaryrefslogtreecommitdiff
path: root/lib/ipaddress
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ipaddress')
-rw-r--r--lib/ipaddress/ipv4.rb126
-rw-r--r--lib/ipaddress/ipv6.rb18
-rw-r--r--lib/ipaddress/mongoid.rb75
-rw-r--r--lib/ipaddress/prefix.rb12
-rw-r--r--lib/ipaddress/version.rb3
5 files changed, 214 insertions, 20 deletions
diff --git a/lib/ipaddress/ipv4.rb b/lib/ipaddress/ipv4.rb
index e99aea2..19ab14c 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
@@ -231,6 +232,21 @@ module IPAddress;
alias_method :to_u32, :u32
#
+ # Returns the address portion in
+ # hex
+ #
+ # ip = IPAddress("10.0.0.0")
+ #
+ # ip.to_h
+ # #=> 0a000000
+ #
+ def hex(space=true)
+ "%.4x%.4x" % [to_u32].pack("N").unpack("nn")
+ end
+ alias_method :to_h, :hex
+ alias_method :to_hex, :hex
+
+ #
# Returns the address portion of an IPv4 object
# in a network byte order format.
#
@@ -271,6 +287,21 @@ module IPAddress;
@octets[index]
end
alias_method :octet, :[]
+
+ #
+ # Updated the octet specified at index
+ #
+ # ip = IPAddress("172.16.100.50/24")
+ # ip[2] = 200
+ #
+ # #=> #<IPAddress::IPv4:0x00000000000000 @address="172.16.200.1",
+ # #=> @prefix=32, @octets=[172, 16, 200, 1], @u32=2886780929>
+ #
+ def []=(index, value)
+ @octets[index] = value.to_i
+ initialize("#{@octets.join('.')}/#{prefix}")
+ end
+ alias_method :octet=, :[]=
#
# Returns the address portion of an IP in binary format,
@@ -294,7 +325,14 @@ module IPAddress;
# #=> "172.16.10.255"
#
def broadcast
- self.class.parse_u32(broadcast_u32, @prefix)
+ case
+ when prefix <= 30
+ self.class.parse_u32(broadcast_u32, @prefix)
+ when prefix == 31
+ self.class.parse_u32(-1, @prefix)
+ when prefix == 32
+ return self
+ end
end
#
@@ -311,7 +349,7 @@ module IPAddress;
# #=> true
#
def network?
- @u32 | @prefix.to_u32 == @prefix.to_u32
+ (@prefix < 32) && (@u32 | @prefix.to_u32 == @prefix.to_u32)
end
#
@@ -348,7 +386,14 @@ module IPAddress;
# #=> "192.168.100.1"
#
def first
- self.class.parse_u32(network_u32+1, @prefix)
+ case
+ when prefix <= 30
+ self.class.parse_u32(network_u32+1, @prefix)
+ when prefix == 31
+ self.class.parse_u32(network_u32, @prefix)
+ when prefix == 32
+ return self
+ end
end
#
@@ -373,7 +418,14 @@ module IPAddress;
# #=> "192.168.100.254"
#
def last
- self.class.parse_u32(broadcast_u32-1, @prefix)
+ case
+ when prefix <= 30
+ self.class.parse_u32(broadcast_u32-1, @prefix)
+ when prefix == 31
+ self.class.parse_u32(broadcast_u32, @prefix)
+ when prefix == 32
+ return self
+ end
end
#
@@ -458,6 +510,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
@@ -570,6 +623,34 @@ module IPAddress;
end
#
+ # Checks if an IPv4 address objects belongs
+ # to a multicast network RFC3171
+ #
+ # Example:
+ #
+ # ip = IPAddress "224.0.0.0/4"
+ # ip.multicast?
+ # #=> true
+ #
+ def multicast?
+ [self.class.new("224.0.0.0/4")].any? {|i| i.include? self}
+ end
+
+ #
+ # Checks if an IPv4 address objects belongs
+ # to a loopback network RFC1122
+ #
+ # Example:
+ #
+ # ip = IPAddress "127.0.0.1"
+ # ip.loopback?
+ # #=> true
+ #
+ def loopback?
+ [self.class.new("127.0.0.0/8")].any? {|i| i.include? self}
+ end
+
+ #
# Returns the IP address in in-addr.arpa format
# for DNS lookups
#
@@ -584,6 +665,26 @@ module IPAddress;
alias_method :arpa, :reverse
#
+ # Return a list of IP's between @address
+ # and the supplied IP
+ #
+ # ip = IPAddress("172.16.100.51/32")
+ #
+ # ip.to("172.16.100.100")
+ # #=> ["172.16.100.51",
+ # #=> "172.16.100.52",
+ # #=> ...
+ # #=> "172.16.100.99",
+ # #=> "172.16.100.100"]
+ #
+ def to(e)
+ unless e.is_a? IPAddress::IPv4
+ e = IPv4.new(e)
+ end
+
+ Range.new(@u32, e.to_u32).map{|i| IPAddress.ntoa(i) }
+ end
+ #
# Splits a network into different subnets
#
# If the IP Address is a network, it can be divided into
@@ -598,9 +699,9 @@ module IPAddress;
#
# network / 4 # implies map{|i| i.to_string}
# #=> ["172.16.10.0/26",
- # "172.16.10.64/26",
- # "172.16.10.128/26",
- # "172.16.10.192/26"]
+ # #=> "172.16.10.64/26",
+ # #=> "172.16.10.128/26",
+ # #=> "172.16.10.192/26"]
#
# If +num+ is any other number, the supernet will be
# divided into some networks with a even number of hosts and
@@ -610,8 +711,8 @@ module IPAddress;
#
# network / 3 # implies map{|i| i.to_string}
# #=> ["172.16.10.0/26",
- # "172.16.10.64/26",
- # "172.16.10.128/25"]
+ # #=> "172.16.10.64/26",
+ # #=> "172.16.10.128/25"]
#
# Returns an array of IPv4 objects
#
@@ -969,12 +1070,9 @@ module IPAddress;
#
private
+ # Tweaked to remove the #upto(32)
def newprefix(num)
- num.upto(32) do |i|
- if (a = Math::log2(i).to_i) == Math::log2(i)
- return @prefix + a
- end
- end
+ return @prefix + (Math::log2(num).ceil )
end
def sum_first_found(arr)
diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb
index 33d4d19..3e506ac 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 =~ /:.+\./
@@ -252,6 +253,15 @@ module IPAddress;
end
alias_method :group, :[]
+ #
+ # Updated the octet specified at index
+ #
+ def []=(index, value)
+ @groups[index] = value
+ initialize("#{IN6FORMAT % @groups}/#{prefix}")
+ end
+ alias_method :group=, :[]=
+
#
# Returns a Base16 number representing the IPv6
# address
@@ -388,6 +398,13 @@ module IPAddress;
@compressed
end
+ #
+ # Returns true if the address is a link local address
+ #
+ def link_local?
+ @groups[0] == 0xfe80
+ end
+
#
# Returns true if the address is an unspecified address
#
@@ -478,6 +495,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/mongoid.rb b/lib/ipaddress/mongoid.rb
new file mode 100644
index 0000000..3af880a
--- /dev/null
+++ b/lib/ipaddress/mongoid.rb
@@ -0,0 +1,75 @@
+module IPAddress
+
+ #
+ # Mongoid field serialization
+ #
+ # IPAddress objects are converted to String
+ #
+ # IPAddress.mongoize IPAddress.parse("172.16.10.1")
+ # #=> "172.16.10.1"
+ #
+ # Prefix will be removed from host adresses
+ #
+ # IPAddress.mongoize "172.16.10.1/32"
+ # #=> "172.16.10.1"
+ #
+ # Prefix will be kept for network addresses
+ #
+ # IPAddress.mongoize "172.16.10.1/24"
+ # #=> "172.16.10.1/24"
+ #
+ # IPv6 addresses will be stored uncompressed to ease DB search and sorting
+ #
+ # IPAddress.mongoize "2001:db8::8:800:200c:417a"
+ # #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
+ # IPAddress.mongoize "2001:db8::8:800:200c:417a/64"
+ # #=> "2001:0db8:0000:0000:0008:0800:200c:417a/64"
+ #
+ # Invalid addresses will be serialized as nil
+ #
+ # IPAddress.mongoize "invalid"
+ # #=> nil
+ # IPAddress.mongoize ""
+ # #=> nil
+ # IPAddress.mongoize 1
+ # #=> nil
+ # IPAddress.mongoize nil
+ # #=> nil
+ #
+ def self.mongoize(ipaddress)
+ ipaddress = self.parse(ipaddress) unless ipaddress.is_a?(IPAddress)
+ if ipaddress.bits.length == ipaddress.prefix
+ ipaddress.address
+ elsif ipaddress.is_a?(IPAddress::IPv6)
+ ipaddress.to_string_uncompressed
+ else
+ ipaddress.to_string
+ end
+ rescue ArgumentError
+ nil
+ end
+
+ #
+ # Mongoid field deserialization
+ #
+ def self.demongoize(string)
+ parse(string)
+ rescue ArgumentError
+ nil
+ end
+
+ #
+ # Delegates to IPAddress.mongoize
+ #
+ def self.evolve(ipaddress)
+ mongoize(ipaddress)
+ end
+
+ #
+ # Sends self object to IPAddress#mongoize
+ #
+ def mongoize
+ IPAddress.mongoize(self)
+ end
+
+end \ No newline at end of file
diff --git a/lib/ipaddress/prefix.rb b/lib/ipaddress/prefix.rb
index f3d585d..136f2d3 100644
--- a/lib/ipaddress/prefix.rb
+++ b/lib/ipaddress/prefix.rb
@@ -55,10 +55,10 @@ module IPAddress
#
# Sums two prefixes or a prefix to a
- # number, returns a Fixnum
+ # number, returns a Integer
#
def +(oth)
- if oth.is_a? Fixnum
+ if oth.is_a? Integer
self.prefix + oth
else
self.prefix + oth.prefix
@@ -68,10 +68,10 @@ module IPAddress
#
# Returns the difference between two
# prefixes, or a prefix and a number,
- # as a Fixnum
+ # as a Integer
#
def -(oth)
- if oth.is_a? Fixnum
+ if oth.is_a? Integer
self.prefix - oth
else
(self.prefix - oth.prefix).abs
@@ -214,8 +214,8 @@ module IPAddress
# #=> 64
#
def initialize(num=128)
- unless (1..128).include? num.to_i
- raise ArgumentError, "Prefix must be in range 1..128, got: #{num}"
+ unless (0..128).include? num.to_i
+ raise ArgumentError, "Prefix must be in range 0..128, got: #{num}"
end
super(num.to_i)
end
diff --git a/lib/ipaddress/version.rb b/lib/ipaddress/version.rb
new file mode 100644
index 0000000..f637ef8
--- /dev/null
+++ b/lib/ipaddress/version.rb
@@ -0,0 +1,3 @@
+module Ipaddress
+ VERSION = "0.8.3"
+end