File: eui64.rb

package info (click to toggle)
ruby-netaddr 2.0.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 296 kB
  • sloc: ruby: 2,022; makefile: 7
file content (77 lines) | stat: -rw-r--r-- 2,387 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
module NetAddr
	
	# EUI64 (Extended Unique Identifier 64-bit, or EUI-64) represents a 64-bit hardware address.
	class EUI64
		
		# addr is the Integer representation of this EUI
		attr_reader :addr
		
		#Create an EUI64 from an Integer. Must be between 0 and 2**64-1.
		#Throws ValidationError on error.
		def initialize(i)
			if (!i.kind_of?(Integer))
				raise ValidationError, "Expected an Integer for 'i' but got a #{i.class}."
			elsif ( (i < 0) || (i > 2**64-1) )
				raise ValidationError, "#{i} is out of bounds for EUI64."
			end
			@addr = i
		end
		
		# Parse an EUI-64 string into an EUI64 type.
		# This will successfully parse most of the typically used formats such as:
		# * aa-bb-cc-dd-ee-ff-00-11
		# * aa:bb:cc:dd:ee:ff:00:11
		# * aabb.ccdd.eeff.0011
		# * aabbccddeeff0011
		# 
		# Although, in truth, its not picky about the exact format as long as
		# it contains exactly 16 hex characters with the optional delimiting characters
		# '-', ':', or '.'.
		def EUI64.parse(addr)
			addr = addr.strip.gsub(/[\-\:\.]/,"")
			if (addr.length != 16)
				raise ValidationError, "Must contain exactly 16 hex characters with optional delimiters."
			elsif (addr =~ /[^0-9a-fA-F\:]/)
				raise ValidationError, "#{addr} contains invalid characters."
			end
			return EUI64.new(addr.to_i(16))
		end
		
		# bytes returns a list containing each byte of the EUI64 as a String.
		def bytes()
			return [
				(@addr >> 56 & 0xff).to_s(16).rjust(2, "0"),
				(@addr >> 48 & 0xff).to_s(16).rjust(2, "0"),
				(@addr >> 40 & 0xff).to_s(16).rjust(2, "0"),
				(@addr >> 32 & 0xff).to_s(16).rjust(2, "0"),
				(@addr >> 24 & 0xff).to_s(16).rjust(2, "0"),
				(@addr >> 16 & 0xff).to_s(16).rjust(2, "0"),
				(@addr >> 8 & 0xff).to_s(16).rjust(2, "0"),
				(@addr & 0xff).to_s(16).rjust(2, "0"),
				]
		end
		
		# to_ipv6 generates an IPv6 address from this EUI64 address and the provided IPv6Net.
		# Nil will be returned if net is not a /64.
		def to_ipv6(net)
			if (!net.kind_of?(IPv6Net))
				raise ArgumentError, "Expected an IPv6Net object for 'net' but got a #{net.class}."
			end
			
			if (net.netmask.prefix_len != 64)
				return nil
			end
			
			# set u/l bit to 0
			hostId = @addr ^ 0x0200000000000000
			ipAddr = net.network.addr | hostId
			return IPv6.new(ipAddr)
		end
		
		def to_s()
			return self.bytes.join("-")
		end
		
	end # end class EUI64
	
end # end module