Class: IP
- Inherits:
-
Object
- Object
- IP
- Includes:
- Comparable
- Defined in:
- lib/ip/base.rb,
lib/ip/cpal.rb,
lib/ip/socket.rb,
lib/ip/version.rb
Overview
Copyright © 2009-2010 Brian Candler <www.deploy2.net/> Licensed under the same terms as ruby. See LICENCE.txt and COPYING.txt
Defined Under Namespace
Constant Summary collapse
- PROTO_TO_CLASS =
{}
- VERSION =
'0.10.0'
Instance Attribute Summary collapse
-
#ctx ⇒ Object
Routing Context indicates the scope of this address (e.g. virtual router).
-
#pfxlen ⇒ Object
Length of prefix (network portion) of address.
Class Method Summary collapse
-
.from_cpal(cpal) ⇒ Object
Create an instance from an alternative array format: [context, protocol, address, prefix_length].
-
.new(src) ⇒ Object
Examples: IP.new(“1.2.3.4”) IP.new(“1.2.3.4/28”) IP.new(“1.2.3.4/28@routing_context”).
-
.new_ntoh(addr) ⇒ Object
Creates a new ip containing the given network byte ordered string form of an IP address.
-
.ntop(addr) ⇒ Object
Convert a network byte ordered string form of an IP address into human readable form.
- .orig_new ⇒ Object
-
.parse(str) ⇒ Object
Parse a string as an IP address - return a V4/V6 object or nil.
Instance Method Summary collapse
- #&(other) ⇒ Object
- #+(other) ⇒ Object
- #-(other) ⇒ Object
- #<=>(other) ⇒ Object
- #^(other) ⇒ Object
-
#af ⇒ Object
Return the address family, Socket::AF_INET or Socket::AF_INET6.
-
#broadcast(offset = 0) ⇒ Object
Return a new IP object at the top of the subnet, with an optional offset applied.
-
#deaggregate(other) ⇒ Object
deaggregate address range IP.new(‘1.2.0.0’).deaggregate(IP.new(‘1.3.255.255’)) => [#<IP::V4 1.2.0.0/15>] IP.new(‘1.2.0.0’).deaggregate(IP.new(‘1.4.255.255’)) => [#<IP::V4 1.2.0.0/15>, #<IP::V4 1.4.0.0/16>] IP.new(‘2001:db8:85a3:8d3::’).deaggregate(IP.new(‘2001:0db8:85a3:08d3:ffff:ffff:ffff:ffff’)) => [#<IP::V6 2001:db8:85a3:8d3::/64>] IP.new(‘2001:db8:85a3:8d3::’).deaggregate(IP.new(‘2001:db8:85a3:8d3:1::’)) => [#<IP::V6 2001:db8:85a3:8d3::/80>, #<IP::V6 2001:db8:85a3:8d3:1::>].
-
#divide_by_hosts(number_hosts) ⇒ Object
subdivide a larger subnet into smaller subnets by number of hosts.
-
#divide_by_subnets(number_subnets) ⇒ Object
subdivide a larger subnet into smaller subnets by number of subnets of equal size, stop when subnets reach their smallest possible size (i.e. 31 for IP4).
- #eql?(other) ⇒ Boolean
- #freeze ⇒ Object
- #hash ⇒ Object
-
#initialize(addr, pfxlen = nil, ctx = nil) ⇒ IP
constructor
Examples: IP::V4.new(0x01020304) IP::V4.new(“01020304”) IP::V4.new(0x01020304, 28) IP::V4.new(0x01020304, 28, “routing_context”).
- #inspect ⇒ Object
- #ipv4_compat? ⇒ Boolean
- #ipv4_mapped? ⇒ Boolean
-
#is_in?(subnet) ⇒ Boolean
test if the address is in the provided subnet.
-
#mask ⇒ Object
Return the mask for this pfxlen as an integer.
-
#mask! ⇒ Object
Masks the address such that it is the base of the subnet IP.new(“1.2.3.4/24”).mask! => #<IP::V4 1.2.3.0/24>.
- #native ⇒ Object
-
#netmask ⇒ Object
Return a new IP object representing the netmask IP.new(“1.2.3.4/24”).netmask => #<IP::V4 255.255.255.0>.
-
#network(offset = 0) ⇒ Object
Return a new IP object at the base of the subnet, with an optional offset applied.
-
#offset ⇒ Object
Returns offset from base of subnet to this address IP.new(“1.2.3.4/24”).offset => 4.
-
#offset? ⇒ Boolean
Returns true if this is not the base address of the subnet implied from the prefix length (e.g. 1.2.3.4/24 is offset, because the base is 1.2.3.0/24).
-
#proto ⇒ Object
Return the protocol in string form, “v4” or “v6”.
-
#reset_pfxlen! ⇒ Object
If the address is not on the base, turn it into a single IP.
-
#size ⇒ Object
The number of IP addresses in subnet IP.new(“1.2.3.4/24”).size => 256.
-
#split ⇒ Object
this function sub-divides a subnet into two subnets of equal size.
- #succ ⇒ Object
- #succ! ⇒ Object
-
#to_a ⇒ Object
Return an array representation of the address, with 3 or 4 elements depending on whether there is a routing context set.
-
#to_addrlen ⇒ Object
Return the string representation of the IP address and prefix, or just the IP address if it’s a single address.
-
#to_ah ⇒ Object
Return an array representation of the address, with 3 or 4 elements depending on whether there is a routing context set, using hexadecimal.
-
#to_b ⇒ Object
returns the address in Binary.
-
#to_cpal ⇒ Object
Return an alternative 4-element array format with the routing context as the first element.
-
#to_cphl ⇒ Object
As cpal but with a hex string for the address part.
-
#to_hex ⇒ Object
Return the address as a hexadecimal string (8 or 32 digits).
-
#to_i ⇒ Object
Return the address as an Integer.
- #to_irange ⇒ Object
-
#to_range ⇒ Object
QUERY: IPAddr (1.9) turns 1.2.3.0/24 into 1.2.3.0/24..1.2.3.255/24 Here I turn it into 1.2.3.0..1.2.3.255.
-
#to_s ⇒ Object
Return the string representation of the address, x.x.x.x[@ctx].
-
#to_sockaddr(port = 0) ⇒ Object
Convert to a packed sockaddr structure.
-
#wildmask ⇒ Object
Return a new IP object representing the wildmask (inverse netmask) IP.new(“1.2.3.4/24”).netmask => #<IP::V4 0.0.0.255>.
- #|(other) ⇒ Object
- #~ ⇒ Object
Constructor Details
#initialize(addr, pfxlen = nil, ctx = nil) ⇒ IP
56 57 58 59 60 61 62 |
# File 'lib/ip/base.rb', line 56 def initialize(addr, pfxlen = nil, ctx = nil) @addr = addr.is_a?(String) ? addr.to_i(16) : addr.to_i raise ArgumentError, 'Invalid address value' if @addr < 0 || @addr > self.class::MASK self.pfxlen = pfxlen self.ctx = ctx end |
Instance Attribute Details
#ctx ⇒ Object
Routing Context indicates the scope of this address (e.g. virtual router)
49 50 51 |
# File 'lib/ip/base.rb', line 49 def ctx @ctx end |
#pfxlen ⇒ Object
Length of prefix (network portion) of address
46 47 48 |
# File 'lib/ip/base.rb', line 46 def pfxlen @pfxlen end |
Class Method Details
.from_cpal(cpal) ⇒ Object
Create an instance from an alternative array format:
[context, protocol, address, prefix_length]
9 10 11 |
# File 'lib/ip/cpal.rb', line 9 def self.from_cpal(cpal) new([cpal[1], cpal[2], cpal[3], cpal[0]]) end |
.new(src) ⇒ Object
Examples:
IP.new("1.2.3.4")
IP.new("1.2.3.4/28")
IP.new("1.2.3.4/28@routing_context")
Array form (inverse of to_a and to_ah):
IP.new(["v4", 0x01020304])
IP.new(["v4", 0x01020304, 28])
IP.new(["v4", 0x01020304, 28, "routing_context"])
IP.new(["v4", "01020304", 28, "routing_context"])
Note that this returns an instance of IP::V4 or IP::V6. IP is the base class of both of those, but cannot be instantiated itself.
25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/ip/base.rb', line 25 def new(src) case src when String parse(src) || (raise ArgumentError, 'invalid address') when Array (PROTO_TO_CLASS[src[0]] || (raise ArgumentError, 'invalid protocol')).new(*src[1..-1]) when IP src.dup else raise ArgumentError, 'invalid address' end end |
.new_ntoh(addr) ⇒ Object
Creates a new ip containing the given network byte ordered string form of an IP address.
71 72 73 |
# File 'lib/ip/base.rb', line 71 def self.new_ntoh(addr) IP.new(IP.ntop(addr)) end |
.ntop(addr) ⇒ Object
Convert a network byte ordered string form of an IP address into human readable form.
77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/ip/base.rb', line 77 def self.ntop(addr) case addr.size when 4 s = addr.unpack('C4').join('.') when 16 s = (['%.4x'] * 8).join(':') % addr.unpack('n8') else raise ArgumentError, 'Invalid address value' end s end |
.orig_new ⇒ Object
11 |
# File 'lib/ip/base.rb', line 11 alias orig_new new |
Instance Method Details
#&(other) ⇒ Object
324 325 326 |
# File 'lib/ip/base.rb', line 324 def &(other) self.class.new(@addr & other.to_i, @pfxlen, @ctx) end |
#+(other) ⇒ Object
316 317 318 |
# File 'lib/ip/base.rb', line 316 def +(other) self.class.new(@addr + other.to_i, @pfxlen, @ctx) end |
#-(other) ⇒ Object
320 321 322 |
# File 'lib/ip/base.rb', line 320 def -(other) self.class.new(@addr - other.to_i, @pfxlen, @ctx) end |
#<=>(other) ⇒ Object
378 379 380 |
# File 'lib/ip/base.rb', line 378 def <=>(other) to_a <=> other.to_a end |
#^(other) ⇒ Object
332 333 334 |
# File 'lib/ip/base.rb', line 332 def ^(other) self.class.new(@addr ^ other.to_i, @pfxlen, @ctx) end |
#af ⇒ Object
Return the address family, Socket::AF_INET or Socket::AF_INET6
10 11 12 |
# File 'lib/ip/socket.rb', line 10 def af self.class::AF end |
#broadcast(offset = 0) ⇒ Object
Return a new IP object at the top of the subnet, with an optional offset applied.
IP.new("1.2.3.4/24").broadcast => #<IP::V4 1.2.3.255/24>
IP.new("1.2.3.4/24").broadcast(-1) => #<IP::V4 1.2.3.254/24>
171 172 173 |
# File 'lib/ip/base.rb', line 171 def broadcast(offset = 0) self.class.new((@addr | mask) + offset, @pfxlen, @ctx) end |
#deaggregate(other) ⇒ Object
deaggregate address range
IP.new('1.2.0.0').deaggregate(IP.new('1.3.255.255'))
=> [#<IP::V4 1.2.0.0/15>]
IP.new('1.2.0.0').deaggregate(IP.new('1.4.255.255'))
=> [#<IP::V4 1.2.0.0/15>, #<IP::V4 1.4.0.0/16>]
IP.new('2001:db8:85a3:8d3::').deaggregate(IP.new('2001:0db8:85a3:08d3:ffff:ffff:ffff:ffff'))
=> [#<IP::V6 2001:db8:85a3:8d3::/64>]
IP.new('2001:db8:85a3:8d3::').deaggregate(IP.new('2001:db8:85a3:8d3:1::'))
=> [#<IP::V6 2001:db8:85a3:8d3::/80>, #<IP::V6 2001:db8:85a3:8d3:1::>]
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/ip/base.rb', line 294 def deaggregate(other) nets = [] base = to_i while base <= other.to_i step = 0 while (base | (1 << step)) != base break if (base | (((~0) & self.class::ADDR_MAX) >> (self.class::ADDR_BITS - 1 - step))) > other.to_i step += 1 end nets << self.class.new(base, self.class::ADDR_BITS - step, @ctx) base += 1 << step end nets end |
#divide_by_hosts(number_hosts) ⇒ Object
subdivide a larger subnet into smaller subnets by number of hosts
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/ip/base.rb', line 269 def divide_by_hosts(number_hosts) nets = [] return nets if split.empty? nets << self while number_hosts <= (nets[0].split[0].size - 2) && nets[0].pfxlen <= (self.class::ADDR_BITS - 1) new_nets = [] nets.each do |net| new_nets |= net.split end nets = new_nets end nets end |
#divide_by_subnets(number_subnets) ⇒ Object
subdivide a larger subnet into smaller subnets by number of subnets of equal size, stop when subnets reach their smallest possible size (i.e. 31 for IP4)
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/ip/base.rb', line 251 def divide_by_subnets(number_subnets) nets = [] return nets if split.empty? nets << self loop do new_nets = [] nets.each do |net| new_nets |= net.split end nets = new_nets break if number_subnets <= nets.length && nets[0].pfxlen <= (self.class::ADDR_BITS - 1) end nets end |
#eql?(other) ⇒ Boolean
374 375 376 |
# File 'lib/ip/base.rb', line 374 def eql?(other) to_a.eql?(other.to_a) end |
#freeze ⇒ Object
369 370 371 372 |
# File 'lib/ip/base.rb', line 369 def freeze mask super end |
#hash ⇒ Object
365 366 367 |
# File 'lib/ip/base.rb', line 365 def hash to_a.hash end |
#inspect ⇒ Object
349 350 351 |
# File 'lib/ip/base.rb', line 349 def inspect "#<#{self.class} #{self}>" end |
#ipv4_compat? ⇒ Boolean
357 358 359 |
# File 'lib/ip/base.rb', line 357 def ipv4_compat? false end |
#ipv4_mapped? ⇒ Boolean
353 354 355 |
# File 'lib/ip/base.rb', line 353 def ipv4_mapped? false end |
#is_in?(subnet) ⇒ Boolean
test if the address is in the provided subnet
228 229 230 231 |
# File 'lib/ip/base.rb', line 228 def is_in?(subnet) subnet.network.to_i <= network.to_i && subnet.broadcast.to_i >= broadcast.to_i end |
#mask ⇒ Object
Return the mask for this pfxlen as an integer. For example, a V4 /24 address has a mask of 255 (0x000000ff)
155 156 157 |
# File 'lib/ip/base.rb', line 155 def mask @mask ||= (1 << (self.class::ADDR_BITS - @pfxlen)) - 1 end |
#mask! ⇒ Object
Masks the address such that it is the base of the subnet
IP.new("1.2.3.4/24").mask! => #<IP::V4 1.2.3.0/24>
189 190 191 192 |
# File 'lib/ip/base.rb', line 189 def mask! @addr &= ~mask self end |
#native ⇒ Object
361 362 363 |
# File 'lib/ip/base.rb', line 361 def native self end |
#netmask ⇒ Object
Return a new IP object representing the netmask
IP.new("1.2.3.4/24").netmask => #<IP::V4 255.255.255.0>
177 178 179 |
# File 'lib/ip/base.rb', line 177 def netmask self.class.new(self.class::MASK & ~mask) end |
#network(offset = 0) ⇒ Object
Return a new IP object at the base of the subnet, with an optional offset applied.
IP.new("1.2.3.4/24").network => #<IP::V4 1.2.3.0/24>
IP.new("1.2.3.4/24").network(7) => #<IP::V4 1.2.3.7/24>
163 164 165 |
# File 'lib/ip/base.rb', line 163 def network(offset = 0) self.class.new((@addr & ~mask) + offset, @pfxlen, @ctx) end |
#offset ⇒ Object
203 204 205 |
# File 'lib/ip/base.rb', line 203 def offset @addr - (@addr & ~mask) end |
#offset? ⇒ Boolean
Returns true if this is not the base address of the subnet implied from the prefix length (e.g. 1.2.3.4/24 is offset, because the base is 1.2.3.0/24)
197 198 199 |
# File 'lib/ip/base.rb', line 197 def offset? @addr != (@addr & ~mask) end |
#proto ⇒ Object
Return the protocol in string form, “v4” or “v6”
65 66 67 |
# File 'lib/ip/base.rb', line 65 def proto self.class::PROTO end |
#reset_pfxlen! ⇒ Object
If the address is not on the base, turn it into a single IP.
IP.new("1.2.3.4/24").reset_pfxlen! => <IP::V4 1.2.3.4>
IP.new("1.2.3.0/24").reset_pfxlen! => <IP::V4 1.2.3.0/24>
210 211 212 213 |
# File 'lib/ip/base.rb', line 210 def reset_pfxlen! self.pfxlen = nil if offset? self end |
#size ⇒ Object
312 313 314 |
# File 'lib/ip/base.rb', line 312 def size mask + 1 end |
#split ⇒ Object
this function sub-divides a subnet into two subnets of equal size
234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/ip/base.rb', line 234 def split nets = [] if pfxlen < self.class::ADDR_BITS if self.class::ADDR_BITS == 32 new_base = IP::V4.new(network.to_i, (pfxlen + 1)) nets = [new_base, IP::V4.new((new_base.broadcast + 1).to_i, (pfxlen + 1))] end if self.class::ADDR_BITS == 128 new_base = IP::V6.new(network.to_i, (pfxlen + 1)) nets = [new_base, IP::V6.new((new_base.broadcast + 1).to_i, (pfxlen + 1))] end end nets end |
#succ ⇒ Object
340 341 342 |
# File 'lib/ip/base.rb', line 340 def succ self.class.new(@addr + size, @pfxlen, @ctx) end |
#succ! ⇒ Object
344 345 346 347 |
# File 'lib/ip/base.rb', line 344 def succ! @addr += size self end |
#to_a ⇒ Object
Return an array representation of the address, with 3 or 4 elements depending on whether there is a routing context set.
["v4", 16909060, 28]
["v4", 16909060, 28, "context"]
(Removing the last element makes them Comparable, as nil.<=> doesn’t exist)
120 121 122 123 124 125 126 |
# File 'lib/ip/base.rb', line 120 def to_a if @ctx [self.class::PROTO, @addr, @pfxlen, @ctx] else [self.class::PROTO, @addr, @pfxlen] end end |
#to_addrlen ⇒ Object
Return the string representation of the IP address and prefix, or just the IP address if it’s a single address
96 97 98 |
# File 'lib/ip/base.rb', line 96 def to_addrlen pfxlen == self.class::ADDR_BITS ? to_addr : "#{to_addr}/#{pfxlen}" end |
#to_ah ⇒ Object
Return an array representation of the address, with 3 or 4 elements depending on whether there is a routing context set, using hexadecimal.
["v4", "01020304", 28]
["v4", "01020304", 28, "context"]
132 133 134 135 136 137 138 |
# File 'lib/ip/base.rb', line 132 def to_ah if @ctx [self.class::PROTO, to_hex, @pfxlen, @ctx] else [self.class::PROTO, to_hex, @pfxlen] end end |
#to_b ⇒ Object
returns the address in Binary
106 107 108 |
# File 'lib/ip/base.rb', line 106 def to_b @addr.to_s(2).to_i end |
#to_cpal ⇒ Object
Return an alternative 4-element array format with the routing context as the first element. Useful for grouping by context.
cpal = [context, proto, address, prefix_length]
16 17 18 |
# File 'lib/ip/cpal.rb', line 16 def to_cpal [@ctx, self.class::PROTO, @addr, @pfxlen] end |
#to_cphl ⇒ Object
As cpal but with a hex string for the address part
21 22 23 |
# File 'lib/ip/cpal.rb', line 21 def to_cphl [@ctx, self.class::PROTO, to_hex, @pfxlen] end |
#to_hex ⇒ Object
Return the address as a hexadecimal string (8 or 32 digits)
111 112 113 |
# File 'lib/ip/base.rb', line 111 def to_hex @addr.to_s(16).rjust(self.class::ADDR_BITS >> 2, '0') end |
#to_i ⇒ Object
Return the address as an Integer
101 102 103 |
# File 'lib/ip/base.rb', line 101 def to_i @addr end |
#to_irange ⇒ Object
215 216 217 218 219 |
# File 'lib/ip/base.rb', line 215 def to_irange a1 = @addr & ~mask a2 = a1 | mask (a1..a2) end |
#to_range ⇒ Object
QUERY: IPAddr (1.9) turns 1.2.3.0/24 into 1.2.3.0/24..1.2.3.255/24 Here I turn it into 1.2.3.0..1.2.3.255. Which is better?
223 224 225 |
# File 'lib/ip/base.rb', line 223 def to_range self.class.new(@addr & ~mask, self.class::ADDR_BITS, @ctx)..self.class.new(@addr | mask, self.class::ADDR_BITS, @ctx) end |
#to_s ⇒ Object
Return the string representation of the address, x.x.x.x[@ctx]
90 91 92 |
# File 'lib/ip/base.rb', line 90 def to_s ctx ? "#{to_addrlen}@#{ctx}" : to_addrlen end |
#to_sockaddr(port = 0) ⇒ Object
Convert to a packed sockaddr structure
15 16 17 |
# File 'lib/ip/socket.rb', line 15 def to_sockaddr(port = 0) Socket.pack_sockaddr_in(port, to_addr) end |
#wildmask ⇒ Object
Return a new IP object representing the wildmask (inverse netmask)
IP.new("1.2.3.4/24").netmask => #<IP::V4 0.0.0.255>
183 184 185 |
# File 'lib/ip/base.rb', line 183 def wildmask self.class.new(mask) end |
#|(other) ⇒ Object
328 329 330 |
# File 'lib/ip/base.rb', line 328 def |(other) self.class.new(@addr | other.to_i, @pfxlen, @ctx) end |
#~ ⇒ Object
336 337 338 |
# File 'lib/ip/base.rb', line 336 def ~ self.class.new(~@addr & self.class::MASK, @pfxlen, @ctx) end |