Class: IP
- Inherits:
-
Object
- Object
- IP
- Includes:
- Comparable
- Defined in:
- lib/ip/base.rb,
lib/ip/cpal.rb,
lib/ip/socket.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 =
{}
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”).
- .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.
-
#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
52 53 54 55 56 57 |
# File 'lib/ip/base.rb', line 52 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)
45 46 47 |
# File 'lib/ip/base.rb', line 45 def ctx @ctx end |
#pfxlen ⇒ Object
Length of prefix (network portion) of address
42 43 44 |
# File 'lib/ip/base.rb', line 42 def pfxlen @pfxlen end |
Class Method Details
.from_cpal(cpal) ⇒ Object
Create an instance from an alternative array format:
[context, protocol, address, prefix_length]
7 8 9 |
# File 'lib/ip/cpal.rb', line 7 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.
22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/ip/base.rb', line 22 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 |
.orig_new ⇒ Object
8 |
# File 'lib/ip/base.rb', line 8 alias :orig_new :new |
Instance Method Details
#&(other) ⇒ Object
257 258 259 |
# File 'lib/ip/base.rb', line 257 def &(other) self.class.new(@addr & other.to_i, @pfxlen, @ctx) end |
#+(other) ⇒ Object
249 250 251 |
# File 'lib/ip/base.rb', line 249 def +(other) self.class.new(@addr + other.to_i, @pfxlen, @ctx) end |
#-(other) ⇒ Object
253 254 255 |
# File 'lib/ip/base.rb', line 253 def -(other) self.class.new(@addr - other.to_i, @pfxlen, @ctx) end |
#<=>(other) ⇒ Object
311 312 313 |
# File 'lib/ip/base.rb', line 311 def <=>(other) to_a <=> other.to_a end |
#^(other) ⇒ Object
265 266 267 |
# File 'lib/ip/base.rb', line 265 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
8 9 10 |
# File 'lib/ip/socket.rb', line 8 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>
137 138 139 |
# File 'lib/ip/base.rb', line 137 def broadcast(offset=0) self.class.new((@addr | mask) + offset, @pfxlen, @ctx) end |
#divide_by_hosts(number_hosts) ⇒ Object
subdivide a larger subnet into smaller subnets by number of hosts
230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/ip/base.rb', line 230 def divide_by_hosts(number_hosts) nets = Array.new nets << self while number_hosts <= (nets[0].split[0].size - 2) && nets[0].pfxlen <= (self.class::ADDR_BITS - 1) new_nets = Array.new nets.each do |net| new_nets = new_nets | net.split end nets = new_nets end return 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)
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/ip/base.rb', line 216 def divide_by_subnets(number_subnets) nets = Array.new nets << self begin new_nets = Array.new nets.each do |net| new_nets = new_nets | net.split end nets = new_nets end until number_subnets <= nets.length && nets[0].pfxlen <= (self.class::ADDR_BITS - 1) return nets end |
#eql?(other) ⇒ Boolean
307 308 309 |
# File 'lib/ip/base.rb', line 307 def eql?(other) to_a.eql?(other.to_a) end |
#freeze ⇒ Object
302 303 304 305 |
# File 'lib/ip/base.rb', line 302 def freeze mask super end |
#hash ⇒ Object
298 299 300 |
# File 'lib/ip/base.rb', line 298 def hash to_a.hash end |
#inspect ⇒ Object
282 283 284 |
# File 'lib/ip/base.rb', line 282 def inspect res = "#<#{self.class} #{to_s}>" end |
#ipv4_compat? ⇒ Boolean
290 291 292 |
# File 'lib/ip/base.rb', line 290 def ipv4_compat? false end |
#ipv4_mapped? ⇒ Boolean
286 287 288 |
# File 'lib/ip/base.rb', line 286 def ipv4_mapped? false end |
#is_in?(subnet) ⇒ Boolean
test if the address is in the provided subnet
194 195 196 197 |
# File 'lib/ip/base.rb', line 194 def is_in?(subnet) return subnet.network.to_i <= self.network.to_i && subnet.broadcast.to_i >= self.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)
121 122 123 |
# File 'lib/ip/base.rb', line 121 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>
155 156 157 158 |
# File 'lib/ip/base.rb', line 155 def mask! @addr &= ~mask self end |
#native ⇒ Object
294 295 296 |
# File 'lib/ip/base.rb', line 294 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>
143 144 145 |
# File 'lib/ip/base.rb', line 143 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>
129 130 131 |
# File 'lib/ip/base.rb', line 129 def network(offset=0) self.class.new((@addr & ~mask) + offset, @pfxlen, @ctx) end |
#offset ⇒ Object
169 170 171 |
# File 'lib/ip/base.rb', line 169 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)
163 164 165 |
# File 'lib/ip/base.rb', line 163 def offset? @addr != (@addr & ~mask) end |
#proto ⇒ Object
Return the protocol in string form, “v4” or “v6”
60 61 62 |
# File 'lib/ip/base.rb', line 60 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>
176 177 178 179 |
# File 'lib/ip/base.rb', line 176 def reset_pfxlen! self.pfxlen = nil if offset? self end |
#size ⇒ Object
245 246 247 |
# File 'lib/ip/base.rb', line 245 def size mask + 1 end |
#split ⇒ Object
this function sub-divides a subnet into two subnets of equal size
199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/ip/base.rb', line 199 def split nets = Array.new if self.pfxlen < self.class::ADDR_BITS if self.class::ADDR_BITS == 32 new_base = IP::V4.new(self.network.to_i, (self.pfxlen + 1)) nets = [new_base, IP::V4.new((new_base.broadcast + 1).to_i, (self.pfxlen + 1))] end if self.class::ADDR_BITS == 128 new_base = IP::V6.new(self.network.to_i, (self.pfxlen + 1)) nets = [new_base, IP::V6.new((new_base.broadcast + 1).to_i, (self.pfxlen + 1))] end end return nets end |
#succ ⇒ Object
273 274 275 |
# File 'lib/ip/base.rb', line 273 def succ self.class.new(@addr + size, @pfxlen, @ctx) end |
#succ! ⇒ Object
277 278 279 280 |
# File 'lib/ip/base.rb', line 277 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)
93 94 95 96 |
# File 'lib/ip/base.rb', line 93 def to_a @ctx ? [self.class::PROTO, @addr, @pfxlen, @ctx] : [self.class::PROTO, @addr, @pfxlen] 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
71 72 73 |
# File 'lib/ip/base.rb', line 71 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"]
102 103 104 105 |
# File 'lib/ip/base.rb', line 102 def to_ah @ctx ? [self.class::PROTO, to_hex, @pfxlen, @ctx] : [self.class::PROTO, to_hex, @pfxlen] end |
#to_b ⇒ Object
returns the address in Binary
80 81 82 |
# File 'lib/ip/base.rb', line 80 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]
14 15 16 |
# File 'lib/ip/cpal.rb', line 14 def to_cpal [@ctx, self.class::PROTO, @addr, @pfxlen] end |
#to_cphl ⇒ Object
As cpal but with a hex string for the address part
19 20 21 |
# File 'lib/ip/cpal.rb', line 19 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)
84 85 86 |
# File 'lib/ip/base.rb', line 84 def to_hex @addr.to_s(16).rjust(self.class::ADDR_BITS>>2,"0") end |
#to_i ⇒ Object
Return the address as an Integer
76 77 78 |
# File 'lib/ip/base.rb', line 76 def to_i @addr end |
#to_irange ⇒ Object
181 182 183 184 185 |
# File 'lib/ip/base.rb', line 181 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?
189 190 191 192 |
# File 'lib/ip/base.rb', line 189 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]
65 66 67 |
# File 'lib/ip/base.rb', line 65 def to_s ctx ? "#{to_addrlen}@#{ctx}" : to_addrlen end |
#to_sockaddr(port = 0) ⇒ Object
Convert to a packed sockaddr structure
13 14 15 |
# File 'lib/ip/socket.rb', line 13 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>
149 150 151 |
# File 'lib/ip/base.rb', line 149 def wildmask self.class.new(mask) end |
#|(other) ⇒ Object
261 262 263 |
# File 'lib/ip/base.rb', line 261 def |(other) self.class.new(@addr | other.to_i, @pfxlen, @ctx) end |
#~ ⇒ Object
269 270 271 |
# File 'lib/ip/base.rb', line 269 def ~ self.class.new(~@addr & self.class::MASK, @pfxlen, @ctx) end |