How can I convert a mac address like 00:16:3e:15:d3:a9
into an IPv6 link local address (as modified EUI-64, like fe80::216:3eff:fe15:d3a9
) in Ruby?
So far, I have the following steps:
mac = "00:16:3e:15:d3:a9"
mac.delete!(':') # Delete colons
mac.insert(6, 'fffe') # Insert ff:ee in the middle
mac = mac.scan(/.{4}/) # Split into octets of 4
The next step would be to flip the sixth bit of the first octet, which I'm having trouble with.
Here is your main problem: Ruby is an object-oriented language. You create programs by manipulating rich, structured objects, more precisely by telling rich, structured objects to manipulate themselves.
You, however, are manipulating String
s. Now, of course, String
s are also objects in Ruby, but they are objects which represent text, they are not objects which represent IP addresses or EUIs.
You should at least treat IP addresses or EUIs as numbers, not as text, but really, you should treat them as rich, structured IP address objects or EUI objects.
Ruby actually comes with a library for manipulating IP addresses as part of its standard library.
Here's an example of what it would look like to treat those addresses as numbers and/or objects:
require 'ipaddr'
eui48 = '00-16-3E-15-D3-A9'
# eliminate all delimiters, note that only ':' is not enough; the standard is '-', but '.' is also sometimes used
eui48 = eui48.gsub(/[^0-9a-zA-Z]/, '')
# parse the EUI-48 as a number
eui48 = eui48.to_i(16)
# split the EUI-48 into the OUI and the manufacturer-assigned parts
oui, assigned = eui48.divmod(1 << 24)
# append 16 zero bits to the OUI
left = oui << 16
# add the standard bit sequence
left += 0xfffe
# append 24 zero bits
left <<= 24
# now we have an EUI-64
eui64 = left + assigned
# flip bit index 57 to create a modified EUI-64
modified_eui64 = eui64 ^ 1 << 57
# the prefix for link-local IPv6 addresses is fe80::/10, link-local addresses are in the fe80::/64 network
prefix = IPAddr.new('fe80::/64')
# the suffix is based on our modified EUI-64
suffix = IPAddr.new(modified_eui64, Socket::AF_INET6)
# the final result is the bitwise logical OR of the prefix and suffix
link_local_ipv6 = prefix | suffix
# the IP address library knows how to correctly format an address according to RFC 5952 Section 4
link_local_ipv6.to_s
#=> 'fe80::216:3eff:fe15:d3a9'