Class: IPAddr

Inherits:
Object
  • Object
show all
Defined in:
lib/ipaddr.rb

Overview

IPAddr provides a set of methods to manipulate an IP address. Both IPv4 and IPv6 are supported.

Example

require 'ipaddr'

ipaddr1 = IPAddr.new "3ffe:505:2::1"

p ipaddr1			#=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>

p ipaddr1.to_s		#=> "3ffe:505:2::1"

ipaddr2 = ipaddr1.mask(48)	#=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>

p ipaddr2.to_s		#=> "3ffe:505:2::"

ipaddr3 = IPAddr.new "192.168.2.0/24"

p ipaddr3			#=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>

Constant Summary collapse

IN4MASK =
0xffffffff
IN6MASK =
0xffffffffffffffffffffffffffffffff
IN6FORMAT =
(["%.4x"] * 8).join(':')

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#familyObject (readonly)

Returns the address family of this IP address.



86
87
88
# File 'lib/ipaddr.rb', line 86

def family
  @family
end

Class Method Details

.new_ntoh(addr) ⇒ Object

Creates a new ipaddr containing the given network byte ordered string form of an IP address.



90
91
92
# File 'lib/ipaddr.rb', line 90

def IPAddr::new_ntoh(addr)
  return IPAddr.new(IPAddr::ntop(addr))
end

.ntop(addr) ⇒ Object

Convert a network byte ordered string form of an IP address into human readable form.



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ipaddr.rb', line 96

def IPAddr::ntop(addr)
  case addr.size
  when 4
    s = addr.unpack('C4').join('.')
  when 16
    s = IN6FORMAT % addr.unpack('n8')
  else
    raise ArgumentError, "unsupported address family"
  end
  return s
end

Instance Method Details

#&(other) ⇒ Object

Returns a new ipaddr built by bitwise AND.



109
110
111
# File 'lib/ipaddr.rb', line 109

def &(other)
  return self.clone.set(@addr & other.to_i)
end

#<<(num) ⇒ Object

Returns a new ipaddr built by bitwise left shift.



124
125
126
# File 'lib/ipaddr.rb', line 124

def <<(num)
  return self.clone.set(addr_mask(@addr << num))
end

#==(other) ⇒ Object

Returns true if two ipaddr are equal.



134
135
136
137
138
139
# File 'lib/ipaddr.rb', line 134

def ==(other)
  if other.kind_of?(IPAddr) && @family != other.family
    return false
  end
  return (@addr == other.to_i)
end

#>>(num) ⇒ Object

Returns a new ipaddr built by bitwise right-shift.



119
120
121
# File 'lib/ipaddr.rb', line 119

def >>(num)
  return self.clone.set(@addr >> num)
end

#htonObject

Returns a network byte ordered string form of the IP address.



225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/ipaddr.rb', line 225

def hton
  case @family
  when Socket::AF_INET
    return [@addr].pack('N')
  when Socket::AF_INET6
    return (0..7).map { |i|
	(@addr >> (112 - 16 * i)) & 0xffff
    }.pack('n8')
  else
    raise "unsupported address family"
  end
end

#include?(other) ⇒ Boolean Also known as: ===

Returns true if the given ipaddr is in the range.

e.g.:

require 'ipaddr'
net1 = IPAddr.new("192.168.2.0/24")
p net1.include?(IPAddr.new("192.168.2.0"))	#=> true
p net1.include?(IPAddr.new("192.168.2.255"))	#=> true
p net1.include?(IPAddr.new("192.168.3.0"))	#=> false

Returns:

  • (Boolean)


155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/ipaddr.rb', line 155

def include?(other)
  if ipv4_mapped?
    if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
	return false
    end
    mask_addr = (@mask_addr & IN4MASK)
    addr = (@addr & IN4MASK)
    family = Socket::AF_INET
  else
    mask_addr = @mask_addr
    addr = @addr
    family = @family
  end
  if other.kind_of?(IPAddr)
    if other.ipv4_mapped?
	other_addr = (other.to_i & IN4MASK)
	other_family = Socket::AF_INET
    else
	other_addr = other.to_i
	other_family = other.family
    end
  else # Not IPAddr - assume integer in same family as us
    other_addr   = other.to_i
    other_family = family
  end

  if family != other_family
    return false
  end
  return ((addr & mask_addr) == (other_addr & mask_addr))
end

#inspectObject

Returns a string containing a human-readable representation of the ipaddr. ("#<IPAddr: family:address/mask>")



321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/ipaddr.rb', line 321

def inspect
  case @family
  when Socket::AF_INET
    af = "IPv4"
  when Socket::AF_INET6
    af = "IPv6"
  else
    raise "unsupported address family"
  end
  return sprintf("#<%s: %s:%s/%s>", self.class.name,
   af, _to_string(@addr), _to_string(@mask_addr))
end

#ip6_arpaObject

Returns a string for DNS reverse lookup compatible with RFC3172.



304
305
306
307
308
309
# File 'lib/ipaddr.rb', line 304

def ip6_arpa
  if !ipv6?
    raise ArgumentError, "not an IPv6 address"
  end
  return _reverse + ".ip6.arpa"
end

#ip6_intObject

Returns a string for DNS reverse lookup compatible with RFC1886.



312
313
314
315
316
317
# File 'lib/ipaddr.rb', line 312

def ip6_int
  if !ipv6?
    raise ArgumentError, "not an IPv6 address"
  end
  return _reverse + ".ip6.int"
end

#ipv4?Boolean

Returns true if the ipaddr is an IPv4 address.

Returns:

  • (Boolean)


239
240
241
# File 'lib/ipaddr.rb', line 239

def ipv4?
  return @family == Socket::AF_INET
end

#ipv4_compatObject

Returns a new ipaddr built by converting the native IPv4 address into an IPv4-compatible IPv6 address.



273
274
275
276
277
278
# File 'lib/ipaddr.rb', line 273

def ipv4_compat
  if !ipv4?
    raise ArgumentError, "not an IPv4 address"
  end
  return self.clone.set(@addr, Socket::AF_INET6)
end

#ipv4_compat?Boolean

Returns true if the ipaddr is an IPv4-compatible IPv6 address.

Returns:

  • (Boolean)


254
255
256
257
258
259
260
# File 'lib/ipaddr.rb', line 254

def ipv4_compat?
  if !ipv6? || (@addr >> 32) != 0
    return false
  end
  a = (@addr & IN4MASK)
  return a != 0 && a != 1
end

#ipv4_mappedObject

Returns a new ipaddr built by converting the native IPv4 address into an IPv4-mapped IPv6 address.



264
265
266
267
268
269
# File 'lib/ipaddr.rb', line 264

def ipv4_mapped
  if !ipv4?
    raise ArgumentError, "not an IPv4 address"
  end
  return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
end

#ipv4_mapped?Boolean

Returns true if the ipaddr is an IPv4-mapped IPv6 address.

Returns:

  • (Boolean)


249
250
251
# File 'lib/ipaddr.rb', line 249

def ipv4_mapped?
  return ipv6? && (@addr >> 32) == 0xffff
end

#ipv6?Boolean

Returns true if the ipaddr is an IPv6 address.

Returns:

  • (Boolean)


244
245
246
# File 'lib/ipaddr.rb', line 244

def ipv6?
  return @family == Socket::AF_INET6
end

#mask(prefixlen) ⇒ Object

Returns a new ipaddr built by masking IP address with the given prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)



143
144
145
# File 'lib/ipaddr.rb', line 143

def mask(prefixlen)
  return self.clone.mask!(prefixlen)
end

#nativeObject

Returns a new ipaddr built by converting the IPv6 address into a native IPv4 address. If the IP address is not an IPv4-mapped or IPv4-compatible IPv6 address, returns self.



283
284
285
286
287
288
# File 'lib/ipaddr.rb', line 283

def native
  if !ipv4_mapped? && !ipv4_compat?
    return self
  end
  return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
end

#reverseObject

Returns a string for DNS reverse lookup. It returns a string in RFC3172 form for an IPv6 address.



292
293
294
295
296
297
298
299
300
301
# File 'lib/ipaddr.rb', line 292

def reverse
  case @family
  when Socket::AF_INET
    return _reverse + ".in-addr.arpa"
  when Socket::AF_INET6
    return ip6_arpa
  else
    raise "unsupported address family"
  end
end

#to_iObject

Returns the integer representation of the ipaddr.



189
190
191
# File 'lib/ipaddr.rb', line 189

def to_i
  return @addr
end

#to_sObject

Returns a string containing the IP address representation.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/ipaddr.rb', line 194

def to_s
  str = to_string
  return str if ipv4?

  str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
  loop do
    break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
    break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0\b/, ':')
    break if str.sub!(/\b0:0\b/, ':')
    break
  end
  str.sub!(/:{3,}/, '::')

  if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str
    str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
  end

  str
end

#to_stringObject

Returns a string containing the IP address representation in canonical form.



220
221
222
# File 'lib/ipaddr.rb', line 220

def to_string
  return _to_string(@addr)
end

#|(other) ⇒ Object

Returns a new ipaddr built by bitwise OR.



114
115
116
# File 'lib/ipaddr.rb', line 114

def |(other)
  return self.clone.set(@addr | other.to_i)
end

#~Object

Returns a new ipaddr built by bitwise negation.



129
130
131
# File 'lib/ipaddr.rb', line 129

def ~
  return self.clone.set(addr_mask(~@addr))
end