[ Posted by James Harton
Thu, 13 Aug 2009 22:54:42 GMT ]
Another instalment in my series of IPAddr extensions for Ruby, today I show you how to calculate the EUI-64 address for a given network and MAC address:
class IPAddr
def self.eui_64(network, mac)
if !network.is_a? IPAddr
raise ArgumentError, "Network must be an IPAddr type."
elsif network.ipv4?
raise ArgumentError, "Network must be an IPv6 network."
elsif network.length != 64
raise ArgumentError, "Network must have a 64 bit mask."
end
if mac.is_a? Integer
mac = "%:012x" % mac
end
if mac.is_a? String
mac = mac.split(":").join.downcase
if mac.match(/^[0-9a-f]{12}/).nil?
raise ArgumentError, "Second argument must be a valid MAC address."
end
e64 = (mac[0..5] + "fffe" + mac[6..11]).to_i(16) ^ 0x0200000000000000
IPAddr.from_i(network.first.to_i + e64, Socket::AF_INET6)
end
end
end
Tags class, extend, integer, ipaddr, patch, range, ruby, work | no comments
[ Posted by James Harton
Wed, 12 Aug 2009 23:50:17 GMT ]
WRT yesterday's blog entry, Ruby's IPAddr class is missing a lot of useful methods. Today I'll show you how to add methods to return the network address and the last address (the broadcast address in IPv4 parlance).
class IPAddr
def length
# nasty hack, but works well enough.
@mask_addr.to_s(2).count("1")
end
def first
IPAddr.from_i(@addr & @mask_addr, @family)
end
def last
if @family == Socket::AF_INET
IPAddr.from_i(first.to_i | (@mask_addr ^ IN4MASK), @family)
elsif @family == Socket::AF_INET6
IPAddr.from_i(first.to_i | (@mask_addr ^ IN6MASK), @family)
else
raise "unsupported address family."
end
end
end
I hope you find these useful.
Tags class, extend, integer, ipaddr, patch, range, ruby, work | no comments
[ Posted by James Harton
Wed, 12 Aug 2009 01:00:38 GMT ]
There are a number of really dumb things wrong with Ruby's IPAddr class, but the two most annoying is no way to convert an integer to an IPv4 or IPv6 address and you can't use IPAddr's in ranges.
I've added a from_i() Class method that clones a new IPAddr instance by converting the integer into the string representation of an IP address. You can optionally also pass in an address family (Socket::AF_INET or Socket::AF_INET6) otherwise it will try and work it out from the size of the integer. I was lucky because I was able to take the bulk of the code from Culvert and convert it to rubyisms.
I've also added the succ() and <=>() methods to IPAddr so that you can use it in ranges, eg:
(IPAddr.new("192.0.2.13")..IPAddr.new("192.0.2.21")) === IPAddr.new("192.0.2.1")
=> false
(IPAddr.new("192.0.2.13")..IPAddr.new("192.0.2.21")) === IPAddr.new("192.0.2.17")
=> true
(IPAddr.new("192.0.2.13")..IPAddr.new("192.0.2.21")) === IPAddr.new("192.0.2.43")
=> false
I need this because I'm writing some code for work which abstracts DHCP ranges (which don't always match subnet boundaries).
Here's the code:
require 'ipaddr'
class IPAddr
include Comparable
def self.from_i(i = 0, family = Socket::AF_UNSPEC)
if i < 0
raise ArgumentError, "Cannot convert negative integer to an IP address."
elsif family == Socket::AF_INET && i > IN4MASK
raise ArgumentError, "Cannot convert integer > 0xffffffff to an IPv4 address."
elsif family == Socket::AF_INET6 && i > IN6MASK
raise ArgumentError, "Cannot convert integer > 0xffffffffffffffffffffffffffffffff to an IPv6 address."
elsif i > IN6MASK
raise ArgumentError, "Cannot convert integer > 0xffffffffffffffffffffffffffffffff to IP address."
end
if family == Socket::AF_UNSPEC
if (0..4) === i.size
family = Socket::AF_INET
elsif (5..16) === i.size
family = Socket::AF_INET6
end
end
if family == Socket::AF_INET
r = []
(0..3).each do |byte|
x = (3 - byte) * 8
y = (4 - byte) * 8
r << ((i >> x) - ((i >> y) * 256 )).to_s
end
IPAddr.new(r * ".")
elsif family == Socket::AF_INET6
r = []
(0..7).each do |byte|
x = (7 - byte) * 16
y = (8 - byte) * 16
r << ((i >> x) - ((i >> y) * 65536)).to_s(16)
end
IPAddr.new(r * ":")
end
end
def succ
i = to_i + 1
if ipv4? and (i <= IN4MASK)
IPAddr.from_i(i)
elsif ipv6? and (i <= IN6MASK)
IPAddr.from_i(i)
end
end
def <=>(other)
to_i <=> other.to_i
end
end
I hope you find this code useful.
Tags class, extend, integer, ipaddr, patch, range, ruby, work | no comments