Class: IP

Inherits:
Object
  • Object
show all
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

Direct Known Subclasses

V4, V6

Defined Under Namespace

Classes: V4, V6

Constant Summary collapse

PROTO_TO_CLASS =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(addr, pfxlen = nil, ctx = nil) ⇒ IP

Examples:

IP::V4.new(0x01020304)
IP::V4.new("01020304")
IP::V4.new(0x01020304, 28)
IP::V4.new(0x01020304, 28, "routing_context")

Raises:

  • (ArgumentError)


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

#ctxObject

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

#pfxlenObject

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_newObject



8
# File 'lib/ip/base.rb', line 8

alias :orig_new :new

.parse(str) ⇒ Object

Parse a string as an IP address - return a V4/V6 object or nil



36
37
38
# File 'lib/ip/base.rb', line 36

def parse(str)
  V4.parse(str) || V6.parse(str)
end

Instance Method Details

#&(other) ⇒ Object



205
206
207
# File 'lib/ip/base.rb', line 205

def &(other)
  self.class.new(@addr & other.to_int, @pfxlen, @ctx)
end

#+(other) ⇒ Object



197
198
199
# File 'lib/ip/base.rb', line 197

def +(other)
  self.class.new(@addr + other.to_int, @pfxlen, @ctx)
end

#-(other) ⇒ Object



201
202
203
# File 'lib/ip/base.rb', line 201

def -(other)
  self.class.new(@addr - other.to_int, @pfxlen, @ctx)
end

#<=>(other) ⇒ Object



259
260
261
# File 'lib/ip/base.rb', line 259

def <=>(other)
  to_a <=> other.to_a
end

#^(other) ⇒ Object



213
214
215
# File 'lib/ip/base.rb', line 213

def ^(other)
  self.class.new(@addr ^ other.to_int, @pfxlen, @ctx)
end

#afObject

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>


134
135
136
# File 'lib/ip/base.rb', line 134

def broadcast(offset=0)
  self.class.new((@addr | mask) + offset, @pfxlen, @ctx)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


255
256
257
# File 'lib/ip/base.rb', line 255

def eql?(other)
  to_a.eql?(other.to_a)
end

#freezeObject



250
251
252
253
# File 'lib/ip/base.rb', line 250

def freeze
  mask
  super
end

#hashObject



246
247
248
# File 'lib/ip/base.rb', line 246

def hash
  to_a.hash
end

#inspectObject



230
231
232
# File 'lib/ip/base.rb', line 230

def inspect
  res = "#<#{self.class} #{to_s}>"
end

#ipv4_compat?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'lib/ip/base.rb', line 238

def ipv4_compat?
  false
end

#ipv4_mapped?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'lib/ip/base.rb', line 234

def ipv4_mapped?
  false
end

#maskObject

Return the mask for this pfxlen as an integer. For example, a V4 /24 address has a mask of 255 (0x000000ff)



118
119
120
# File 'lib/ip/base.rb', line 118

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>


152
153
154
155
# File 'lib/ip/base.rb', line 152

def mask!
  @addr &= ~mask
  self
end

#nativeObject



242
243
244
# File 'lib/ip/base.rb', line 242

def native
  self
end

#netmaskObject

Return a new IP object representing the netmask

IP.new("1.2.3.4/24").netmask  =>  #<IP::V4 255.255.255.0>


140
141
142
# File 'lib/ip/base.rb', line 140

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>


126
127
128
# File 'lib/ip/base.rb', line 126

def network(offset=0)
  self.class.new((@addr & ~mask) + offset, @pfxlen, @ctx)
end

#offsetObject

Returns offset from base of subnet to this address

IP.new("1.2.3.4/24").offset   => 4


166
167
168
# File 'lib/ip/base.rb', line 166

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)

Returns:

  • (Boolean)


160
161
162
# File 'lib/ip/base.rb', line 160

def offset?
  @addr != (@addr & ~mask)
end

#protoObject

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>


173
174
175
176
# File 'lib/ip/base.rb', line 173

def reset_pfxlen!
  self.pfxlen = nil if offset?
  self
end

#sizeObject

The number of IP addresses in subnet

IP.new("1.2.3.4/24").size   => 256


193
194
195
# File 'lib/ip/base.rb', line 193

def size
  mask + 1
end

#succObject



221
222
223
# File 'lib/ip/base.rb', line 221

def succ
  self.class.new(@addr + size, @pfxlen, @ctx)
end

#succ!Object



225
226
227
228
# File 'lib/ip/base.rb', line 225

def succ!
  @addr += size
  self
end

#to_aObject

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)



90
91
92
93
# File 'lib/ip/base.rb', line 90

def to_a
  @ctx ? [self.class::PROTO, @addr, @pfxlen, @ctx] :
         [self.class::PROTO, @addr, @pfxlen]
end

#to_addrlenObject

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_ahObject

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"]


99
100
101
102
# File 'lib/ip/base.rb', line 99

def to_ah
  @ctx ? [self.class::PROTO, to_hex, @pfxlen, @ctx] :
         [self.class::PROTO, to_hex, @pfxlen]
end

#to_cpalObject

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_cphlObject

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_hexObject

Return the address as a hexadecimal string (8 or 32 digits)



81
82
83
# File 'lib/ip/base.rb', line 81

def to_hex
  @addr.to_s(16).rjust(self.class::ADDR_BITS>>2,"0")
end

#to_iObject

Return the address as an Integer



76
77
78
# File 'lib/ip/base.rb', line 76

def to_i
  @addr
end

#to_irangeObject



178
179
180
181
182
# File 'lib/ip/base.rb', line 178

def to_irange
  a1 = @addr & ~mask
  a2 = a1 | mask
  (a1..a2)
end

#to_rangeObject

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?



186
187
188
189
# File 'lib/ip/base.rb', line 186

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_sObject

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

#wildmaskObject

Return a new IP object representing the wildmask (inverse netmask)

IP.new("1.2.3.4/24").netmask  =>  #<IP::V4 0.0.0.255>


146
147
148
# File 'lib/ip/base.rb', line 146

def wildmask
  self.class.new(mask)
end

#|(other) ⇒ Object



209
210
211
# File 'lib/ip/base.rb', line 209

def |(other)
  self.class.new(@addr | other.to_int, @pfxlen, @ctx)
end

#~Object



217
218
219
# File 'lib/ip/base.rb', line 217

def ~
  self.class.new(~@addr & self.class::MASK, @pfxlen, @ctx)
end