netaddr 1.5.3 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of netaddr might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/LICENSE +201 -0
- data/README.md +28 -8
- data/lib/eui48.rb +65 -0
- data/lib/eui64.rb +77 -0
- data/lib/ipv4.rb +77 -0
- data/lib/ipv4net.rb +245 -0
- data/lib/ipv6.rb +110 -0
- data/lib/ipv6net.rb +246 -0
- data/lib/mask128.rb +68 -0
- data/lib/mask32.rb +99 -0
- data/lib/netaddr.rb +104 -20
- data/lib/util.rb +310 -0
- data/test/eui48_test.rb +30 -0
- data/test/eui64_test.rb +32 -0
- data/test/examples.rb +137 -0
- data/test/ipv4_test.rb +54 -0
- data/test/ipv4net_test.rb +166 -0
- data/test/ipv6_test.rb +90 -0
- data/test/ipv6net_test.rb +146 -0
- data/test/mask128_test.rb +45 -0
- data/test/mask32_test.rb +51 -0
- data/test/netaddr_test.rb +127 -0
- data/test/run_all.rb +10 -0
- metadata +28 -22
- data/Errors +0 -7
- data/changelog +0 -52
- data/lib/cidr.rb +0 -2014
- data/lib/cidr_shortcuts.rb +0 -401
- data/lib/eui.rb +0 -402
- data/lib/ip_math.rb +0 -227
- data/lib/methods.rb +0 -1013
- data/lib/tree.rb +0 -816
- data/lib/validation_shortcuts.rb +0 -201
- data/license +0 -13
- data/test/cidr_test.rb +0 -545
- data/test/eui_test.rb +0 -101
- data/test/methods_test.rb +0 -331
- data/test/tree_test.rb +0 -347
data/lib/mask32.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
module NetAddr
|
2
|
+
|
3
|
+
#Mask32 represents a 32-bit netmask.
|
4
|
+
class Mask32
|
5
|
+
# mask is the Integer representation of this netmask
|
6
|
+
attr_reader :mask
|
7
|
+
|
8
|
+
# prefix_len is the Integer prefix length of this netmask
|
9
|
+
attr_reader :prefix_len
|
10
|
+
|
11
|
+
# Create a Mask32 from an Integer prefix length. Valid values are 0-32.
|
12
|
+
# Throws ValidationError on error.
|
13
|
+
def initialize(prefix_len)
|
14
|
+
if (!prefix_len.kind_of?(Integer))
|
15
|
+
raise ValidationError, "Expected an Integer for 'prefix_len' but got a #{prefix_len.class}."
|
16
|
+
elsif ( (prefix_len < 0) || (prefix_len > 32) )
|
17
|
+
raise ValidationError, "#{prefix_len} must be in the range of 0-32."
|
18
|
+
end
|
19
|
+
@prefix_len = prefix_len
|
20
|
+
@mask = NetAddr::F32 ^ (NetAddr::F32 >> @prefix_len)
|
21
|
+
end
|
22
|
+
|
23
|
+
# parse will create an Mask32 from its string representation.
|
24
|
+
# arguments:
|
25
|
+
# * mask - String representing a netmask (ie. "/24" or "255.255.255.0").
|
26
|
+
#
|
27
|
+
# Throws ValidationError on error.
|
28
|
+
def Mask32.parse(mask)
|
29
|
+
mask.strip!
|
30
|
+
if (mask.start_with?("/")) # cidr format
|
31
|
+
return Mask32.new(mask[1..-1].to_i) # remove "/"
|
32
|
+
elsif (!mask.include?("."))
|
33
|
+
return Mask32.new(mask.to_i)
|
34
|
+
end
|
35
|
+
|
36
|
+
# for extended netmask
|
37
|
+
# determine length of netmask by cycling through bit by bit and looking
|
38
|
+
# for the first '1' bit, tracking the length as we go. we also want to verify
|
39
|
+
# that the mask is valid (ie. not something like 255.254.255.0). we do this
|
40
|
+
# by creating a hostmask which covers the '0' bits of the mask. once we have
|
41
|
+
# separated the net vs host mask we xor them together. the result should be that
|
42
|
+
# all bits are now '1'. if not then we know we have an invalid netmask.
|
43
|
+
maskI = Util.parse_IPv4(mask)
|
44
|
+
prefix = 32
|
45
|
+
hostmask = 1
|
46
|
+
i = maskI
|
47
|
+
32.downto(1) do
|
48
|
+
if (i&1 == 1)
|
49
|
+
hostmask = hostmask >> 1
|
50
|
+
if (maskI ^hostmask != NetAddr::F32)
|
51
|
+
raise ValidationError, "#{mask} is invalid. It contains '1' bits in its host portion."
|
52
|
+
end
|
53
|
+
break
|
54
|
+
end
|
55
|
+
hostmask = (hostmask << 1) | 1
|
56
|
+
i = i>>1
|
57
|
+
prefix -= 1
|
58
|
+
end
|
59
|
+
return Mask32.new(prefix)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
# extended returns the Mask32 in extended format (eg. x.x.x.x)
|
64
|
+
def extended()
|
65
|
+
Util.intToMask32(@mask)
|
66
|
+
end
|
67
|
+
|
68
|
+
#cmp compares equality with another Mask32. Return:
|
69
|
+
#* 1 if this Mask128 is larger in capacity
|
70
|
+
#* 0 if the two are equal
|
71
|
+
#* -1 if this Mask128 is smaller in capacity
|
72
|
+
def cmp(other)
|
73
|
+
if (!other.kind_of?(Mask32))
|
74
|
+
raise ArgumentError, "Expected an Mask32 object for 'other' but got a #{other.class}."
|
75
|
+
end
|
76
|
+
if (self.prefix_len < other.prefix_len)
|
77
|
+
return 1
|
78
|
+
elsif (self.prefix_len > other.prefix_len)
|
79
|
+
return -1
|
80
|
+
end
|
81
|
+
return 0
|
82
|
+
end
|
83
|
+
|
84
|
+
#len returns the number of IP addresses in this network. It will always return 0 for /0 networks.
|
85
|
+
def len()
|
86
|
+
if (self.prefix_len == 0)
|
87
|
+
return 0
|
88
|
+
end
|
89
|
+
return (self.mask ^ NetAddr::F32) + 1 # bit flip the netmask and add 1
|
90
|
+
end
|
91
|
+
|
92
|
+
# to_s returns the Mask32 as a String
|
93
|
+
def to_s()
|
94
|
+
return "/#{@prefix_len}"
|
95
|
+
end
|
96
|
+
|
97
|
+
end # end class Mask32
|
98
|
+
|
99
|
+
end # end module
|
data/lib/netaddr.rb
CHANGED
@@ -1,24 +1,108 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
require_relative "eui48.rb"
|
2
|
+
require_relative "eui64.rb"
|
3
|
+
require_relative "ipv4.rb"
|
4
|
+
require_relative "ipv4net.rb"
|
5
|
+
require_relative "ipv6.rb"
|
6
|
+
require_relative "ipv6net.rb"
|
7
|
+
require_relative "mask32.rb"
|
8
|
+
require_relative "mask128.rb"
|
9
|
+
require_relative "util.rb"
|
10
10
|
|
11
11
|
module NetAddr
|
12
|
+
# Constants
|
13
|
+
|
14
|
+
# 32 bits worth of '1'
|
15
|
+
F32 = 2**32-1
|
16
|
+
|
17
|
+
# 128 bits worth of '1'
|
18
|
+
F128 = 2**128-1
|
19
|
+
|
12
20
|
|
13
|
-
|
21
|
+
# ValidationError is thrown when a method fails a validation test.
|
22
|
+
class ValidationError < StandardError
|
14
23
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
|
25
|
+
# ipv4_prefix_len returns the prefix length needed to hold the number of IP addresses specified by "size".
|
26
|
+
def ipv4_prefix_len(size)
|
27
|
+
prefix_len = 32
|
28
|
+
32.downto(0) do |i|
|
29
|
+
hostbits = 32 - prefix_len
|
30
|
+
max = 1 << hostbits
|
31
|
+
if (size <= max)
|
32
|
+
break
|
33
|
+
end
|
34
|
+
prefix_len -= 1
|
35
|
+
end
|
36
|
+
return prefix_len
|
37
|
+
end
|
38
|
+
module_function :ipv4_prefix_len
|
39
|
+
|
40
|
+
# sort_IPv4 sorts a list of IPv4 objects in ascending order.
|
41
|
+
# It will return a new list with any non IPv4 objects removed.
|
42
|
+
def sort_IPv4(list)
|
43
|
+
if ( !list.kind_of?(Array) )
|
44
|
+
raise ArgumentError, "Expected an Array for 'list' but got a #{list.class}."
|
45
|
+
end
|
46
|
+
filtered = Util.filter_IPv4(list)
|
47
|
+
return Util.quick_sort(filtered)
|
48
|
+
end
|
49
|
+
module_function :sort_IPv4
|
50
|
+
|
51
|
+
# sort_IPv6 sorts a list of IPv6 objects in ascending order.
|
52
|
+
# It will return a new list with any non IPv6 objects removed.
|
53
|
+
def sort_IPv6(list)
|
54
|
+
if ( !list.kind_of?(Array) )
|
55
|
+
raise ArgumentError, "Expected an Array for 'list' but got a #{list.class}."
|
56
|
+
end
|
57
|
+
filtered = Util.filter_IPv6(list)
|
58
|
+
return Util.quick_sort(filtered)
|
59
|
+
end
|
60
|
+
module_function :sort_IPv6
|
61
|
+
|
62
|
+
# sort_IPv4Net sorts a list of IPv4Net objects in ascending order.
|
63
|
+
# It will return a new list with any non IPv4Net objects removed.
|
64
|
+
def sort_IPv4Net(list)
|
65
|
+
if ( !list.kind_of?(Array) )
|
66
|
+
raise ArgumentError, "Expected an Array for 'list' but got a #{list.class}."
|
67
|
+
end
|
68
|
+
filtered = Util.filter_IPv4Net(list)
|
69
|
+
return Util.quick_sort(filtered)
|
70
|
+
end
|
71
|
+
module_function :sort_IPv4Net
|
72
|
+
|
73
|
+
# sort_IPv6Net sorts a list of IPv6Net objects in ascending order.
|
74
|
+
# It will return a new list with any non IPv6Net objects removed.
|
75
|
+
def sort_IPv6Net(list)
|
76
|
+
if ( !list.kind_of?(Array) )
|
77
|
+
raise ArgumentError, "Expected an Array for 'list' but got a #{list.class}."
|
78
|
+
end
|
79
|
+
filtered = Util.filter_IPv6Net(list)
|
80
|
+
return Util.quick_sort(filtered)
|
81
|
+
end
|
82
|
+
module_function :sort_IPv6Net
|
83
|
+
|
84
|
+
# summ_IPv4Net summarizes a list of IPv4Net objects as much as possible.
|
85
|
+
# It will return a new list with any non IPv4Net objects removed.
|
86
|
+
def summ_IPv4Net(list)
|
87
|
+
list = Util.filter_IPv4Net(list)
|
88
|
+
if (list.length>1)
|
89
|
+
list = Util.discard_subnets(list)
|
90
|
+
return Util.summ_peers(list)
|
91
|
+
end
|
92
|
+
return [].concat(list)
|
93
|
+
end
|
94
|
+
module_function :summ_IPv4Net
|
95
|
+
|
96
|
+
# summ_IPv6Net summarizes a list of IPv6Net objects as much as possible.
|
97
|
+
# It will return a new list with any non IPv6Net objects removed.
|
98
|
+
def summ_IPv6Net(list)
|
99
|
+
list = Util.filter_IPv6Net(list)
|
100
|
+
if (list.length>1)
|
101
|
+
list = Util.discard_subnets(list)
|
102
|
+
return Util.summ_peers(list)
|
103
|
+
end
|
104
|
+
return [].concat(list)
|
105
|
+
end
|
106
|
+
module_function :summ_IPv6Net
|
107
|
+
|
108
|
+
end # end module
|
data/lib/util.rb
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
module NetAddr
|
2
|
+
|
3
|
+
# Contains various internal util functions
|
4
|
+
class Util
|
5
|
+
private
|
6
|
+
|
7
|
+
# backfill generates subnets between given IPv4Net/IPv6Net and the limit address.
|
8
|
+
# limit should be < ipnet. will create subnets up to and including limit.
|
9
|
+
def Util.backfill(ipnet,limit)
|
10
|
+
nets = []
|
11
|
+
cur = ipnet
|
12
|
+
while true do
|
13
|
+
net = cur.prev
|
14
|
+
if (net == nil || net.network.addr < limit)
|
15
|
+
break
|
16
|
+
end
|
17
|
+
nets.unshift(net)
|
18
|
+
cur = net
|
19
|
+
end
|
20
|
+
return nets
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# discard_subnets returns a copy of the IPv4NetList with any entries which are subnets of other entries removed.
|
25
|
+
def Util.discard_subnets(list)
|
26
|
+
unrelated = []
|
27
|
+
supernets = []
|
28
|
+
last = list[list.length-1]
|
29
|
+
list.each do |net|
|
30
|
+
rel = last.rel(net)
|
31
|
+
if (!rel)
|
32
|
+
unrelated.push(net)
|
33
|
+
elsif (rel == -1) # last is subnet of net
|
34
|
+
supernets.push(net)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
cleaned = []
|
39
|
+
if (supernets.length > 0)
|
40
|
+
cleaned = discard_subnets(supernets)
|
41
|
+
else
|
42
|
+
cleaned.push(last)
|
43
|
+
end
|
44
|
+
|
45
|
+
if (unrelated.length > 0)
|
46
|
+
cleaned.concat( discard_subnets(unrelated) )
|
47
|
+
end
|
48
|
+
return cleaned
|
49
|
+
end
|
50
|
+
|
51
|
+
# fill returns a copy of the given Array, stripped of any networks which are not subnets of ipnet
|
52
|
+
# and with any missing gaps filled in.
|
53
|
+
def Util.fill(ipnet,list)
|
54
|
+
# sort & git rid of non subnets
|
55
|
+
subs = []
|
56
|
+
discard_subnets(list).each do |sub|
|
57
|
+
r = ipnet.rel(sub)
|
58
|
+
if (r == 1)
|
59
|
+
subs.push(sub)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
subs = quick_sort(subs)
|
63
|
+
|
64
|
+
filled = []
|
65
|
+
if (subs.length > 0)
|
66
|
+
# bottom fill if base missing
|
67
|
+
base = ipnet.network.addr
|
68
|
+
if (subs[0].network.addr != base)
|
69
|
+
filled = backfill(subs[0],base)
|
70
|
+
end
|
71
|
+
|
72
|
+
# fill gaps
|
73
|
+
sib = ipnet.next_sib()
|
74
|
+
ceil = NetAddr::F32
|
75
|
+
if (sib != nil)
|
76
|
+
ceil = sib.network.addr
|
77
|
+
end
|
78
|
+
|
79
|
+
0.upto(subs.length-1) do |i|
|
80
|
+
sub = subs[i]
|
81
|
+
filled.push(sub)
|
82
|
+
limit = ceil
|
83
|
+
if (i+1 < subs.length)
|
84
|
+
limit = subs[i+1].network.addr
|
85
|
+
end
|
86
|
+
filled.concat( fwdfill(sub,limit) )
|
87
|
+
end
|
88
|
+
end
|
89
|
+
return filled
|
90
|
+
end
|
91
|
+
|
92
|
+
# filter_IPv4 returns a copy of list with only IPv4 objects
|
93
|
+
def Util.filter_IPv4(list)
|
94
|
+
filtered = []
|
95
|
+
list.each do |ip|
|
96
|
+
if (ip.kind_of?(IPv4))
|
97
|
+
filtered.push(ip)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
return filtered
|
101
|
+
end
|
102
|
+
|
103
|
+
# filter_IPv4Net returns a copy of list with only IPv4Net objects
|
104
|
+
def Util.filter_IPv4Net(list)
|
105
|
+
filtered = []
|
106
|
+
list.each do |ip|
|
107
|
+
if (ip.kind_of?(IPv4Net))
|
108
|
+
filtered.push(ip)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return filtered
|
112
|
+
end
|
113
|
+
|
114
|
+
# filter_IPv6 returns a copy of list with only IPv6 objects
|
115
|
+
def Util.filter_IPv6(list)
|
116
|
+
filtered = []
|
117
|
+
list.each do |ip|
|
118
|
+
if (ip.kind_of?(IPv6))
|
119
|
+
filtered.push(ip)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
return filtered
|
123
|
+
end
|
124
|
+
|
125
|
+
# filter_IPv6Net returns a copy of list with only IPv4Net objects
|
126
|
+
def Util.filter_IPv6Net(list)
|
127
|
+
filtered = []
|
128
|
+
list.each do |ip|
|
129
|
+
if (ip.kind_of?(IPv6Net))
|
130
|
+
filtered.push(ip)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
return filtered
|
134
|
+
end
|
135
|
+
|
136
|
+
# fwdfill returns subnets between given IPv4Net/IPv6Nett and the limit address.
|
137
|
+
# limit should be > ipnet. will create subnets up to limit.
|
138
|
+
def Util.fwdfill(ipnet,limit)
|
139
|
+
nets = []
|
140
|
+
cur = ipnet
|
141
|
+
while true do
|
142
|
+
net = cur.next
|
143
|
+
if (net == nil || net.network.addr >= limit)
|
144
|
+
break
|
145
|
+
end
|
146
|
+
nets.push(net)
|
147
|
+
cur = net
|
148
|
+
end
|
149
|
+
return nets
|
150
|
+
end
|
151
|
+
|
152
|
+
# int_to_IPv4 converts an Integer into an IPv4 address String
|
153
|
+
def Util.int_to_IPv4(i)
|
154
|
+
octets = []
|
155
|
+
3.downto(0) do |x|
|
156
|
+
octet = (i >> 8*x) & 0xFF
|
157
|
+
octets.push(octet.to_s)
|
158
|
+
end
|
159
|
+
return octets.join('.')
|
160
|
+
end
|
161
|
+
|
162
|
+
# parse_IPv4 parses an IPv4 address String into an Integer
|
163
|
+
def Util.parse_IPv4(ip)
|
164
|
+
# check that only valid characters are present
|
165
|
+
if (ip =~ /[^0-9\.]/)
|
166
|
+
raise ValidationError, "#{ip} contains invalid characters."
|
167
|
+
end
|
168
|
+
|
169
|
+
ip.strip!
|
170
|
+
octets = ip.split('.')
|
171
|
+
if (octets.length != 4)
|
172
|
+
raise ValidationError, "IPv4 requires (4) octets."
|
173
|
+
end
|
174
|
+
|
175
|
+
ipInt = 0
|
176
|
+
i = 4
|
177
|
+
octets.each do |octet|
|
178
|
+
octetI = octet.to_i()
|
179
|
+
if ( (octetI < 0) || (octetI >= 256) )
|
180
|
+
raise ValidationError, "#{ip} is out of bounds for IPv4."
|
181
|
+
end
|
182
|
+
i -= 1
|
183
|
+
ipInt = ipInt | (octetI << 8*i)
|
184
|
+
end
|
185
|
+
return ipInt
|
186
|
+
end
|
187
|
+
|
188
|
+
# parse_IPv6 parses an IPv6 address String into an Integer
|
189
|
+
def Util.parse_IPv6(ip)
|
190
|
+
# check that only valid characters are present
|
191
|
+
if (ip =~ /[^0-9a-fA-F\:]/)
|
192
|
+
raise ValidationError, "#{ip} contains invalid characters."
|
193
|
+
end
|
194
|
+
|
195
|
+
ip.strip!
|
196
|
+
if (ip == "::")
|
197
|
+
return 0 # zero address
|
198
|
+
end
|
199
|
+
words = []
|
200
|
+
if (ip.include?("::")) # short format
|
201
|
+
if (ip =~ /:{3,}/) # make sure only i dont have ":::"
|
202
|
+
raise ValidationError, "#{ip} contains invalid field separator."
|
203
|
+
end
|
204
|
+
if (ip.scan(/::/).length != 1)
|
205
|
+
raise ValidationError, "#{ip} contains multiple '::' sequences."
|
206
|
+
end
|
207
|
+
|
208
|
+
halves = ip.split("::")
|
209
|
+
if (halves[0] == nil) # cases such as ::1
|
210
|
+
halves[0] = "0"
|
211
|
+
end
|
212
|
+
if (halves[1] == nil) # cases such as 1::
|
213
|
+
halves[1] = "0"
|
214
|
+
end
|
215
|
+
upHalf = halves[0].split(":")
|
216
|
+
loHalf = halves[1].split(":")
|
217
|
+
numWords = upHalf.length + loHalf.length
|
218
|
+
if (numWords > 8)
|
219
|
+
raise ValidationError, "#{ip} is too long."
|
220
|
+
end
|
221
|
+
words = upHalf
|
222
|
+
(8-numWords).downto(1) do |i|
|
223
|
+
words.push("0")
|
224
|
+
end
|
225
|
+
words.concat(loHalf)
|
226
|
+
else
|
227
|
+
words = ip.split(":")
|
228
|
+
if (words.length > 8)
|
229
|
+
raise ValidationError, "#{ip} is too long."
|
230
|
+
elsif (words.length < 8)
|
231
|
+
raise ValidationError, "#{ip} is too short."
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
ipInt = 0
|
236
|
+
i = 8
|
237
|
+
words.each do |word|
|
238
|
+
i -= 1
|
239
|
+
word = word.to_i(16) << (16*i)
|
240
|
+
ipInt = ipInt | word
|
241
|
+
end
|
242
|
+
|
243
|
+
return ipInt
|
244
|
+
end
|
245
|
+
|
246
|
+
# quick_sort will return a sorted copy of the provided Array.
|
247
|
+
# The array must contain only objects which implement a cmp method and which are comparable to each other.
|
248
|
+
def Util.quick_sort(list)
|
249
|
+
if (list.length <= 1)
|
250
|
+
return [].concat(list)
|
251
|
+
end
|
252
|
+
|
253
|
+
final_list = []
|
254
|
+
lt_list = []
|
255
|
+
gt_list = []
|
256
|
+
eq_list = []
|
257
|
+
pivot = list[list.length-1]
|
258
|
+
list.each do |ip|
|
259
|
+
cmp = pivot.cmp(ip)
|
260
|
+
if (cmp == 1)
|
261
|
+
lt_list.push(ip)
|
262
|
+
elsif (cmp == -1)
|
263
|
+
gt_list.push(ip)
|
264
|
+
else
|
265
|
+
eq_list.push(ip)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
final_list.concat( quick_sort(lt_list) )
|
269
|
+
final_list.concat(eq_list)
|
270
|
+
final_list.concat( quick_sort(gt_list) )
|
271
|
+
return final_list
|
272
|
+
end
|
273
|
+
|
274
|
+
# summ_peers returns a copy of the list with any merge-able subnets summ'd together.
|
275
|
+
def Util.summ_peers(list)
|
276
|
+
summd = quick_sort(list)
|
277
|
+
while true do
|
278
|
+
list_len = summd.length
|
279
|
+
last = list_len - 1
|
280
|
+
tmp_list = []
|
281
|
+
i = 0
|
282
|
+
while (i < list_len) do
|
283
|
+
net = summd[i]
|
284
|
+
next_net = i+1
|
285
|
+
if (i != last)
|
286
|
+
# if this net and next_net summarize then discard them & keep summary
|
287
|
+
new_net = net.summ(summd[next_net])
|
288
|
+
if (new_net) # can summ. keep summary
|
289
|
+
tmp_list.push(new_net)
|
290
|
+
i += 1 # skip next_net
|
291
|
+
else # cant summ. keep existing
|
292
|
+
tmp_list.push(net)
|
293
|
+
end
|
294
|
+
else
|
295
|
+
tmp_list.push(net) # keep last
|
296
|
+
end
|
297
|
+
i += 1
|
298
|
+
end
|
299
|
+
|
300
|
+
# stop when list stops getting shorter
|
301
|
+
if (tmp_list.length == list_len)
|
302
|
+
break
|
303
|
+
end
|
304
|
+
summd = tmp_list
|
305
|
+
end
|
306
|
+
return summd
|
307
|
+
end
|
308
|
+
|
309
|
+
end # end class
|
310
|
+
end # end module
|
data/test/eui48_test.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require_relative "../lib/netaddr.rb"
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TestEUI48 < Test::Unit::TestCase
|
7
|
+
def test_new
|
8
|
+
eui = NetAddr::EUI48.new(0)
|
9
|
+
assert_equal("00-00-00-00-00-00", eui.to_s)
|
10
|
+
|
11
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI48.new(2**48) }
|
12
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI48.new(-1) }
|
13
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI48.new("00-00-00-00-00-00") } # string
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_parse
|
17
|
+
assert_equal("aa-bb-cc-dd-ee-ff", NetAddr::EUI48.parse("aa-bb-cc-dd-ee-ff").to_s)
|
18
|
+
assert_equal("aa-bb-cc-dd-ee-ff", NetAddr::EUI48.parse("aa:bb:cc:dd:ee:ff").to_s)
|
19
|
+
assert_equal("aa-bb-cc-dd-ee-ff", NetAddr::EUI48.parse("aabb.ccdd.eeff").to_s)
|
20
|
+
assert_equal("aa-bb-cc-dd-ee-ff", NetAddr::EUI48.parse("aabbccddeeff").to_s)
|
21
|
+
|
22
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI48.parse("aa-bb-cc-dd-ee-ff-00-11") }
|
23
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI48.parse("aa-bb-cc-dd-ee-gg") }
|
24
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI48.parse("aa;bb;cc;dd;ee;ff") }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_to_eui64
|
28
|
+
assert_equal("aa-bb-cc-ff-fe-dd-ee-ff", NetAddr::EUI48.parse("aa-bb-cc-dd-ee-ff").to_eui64.to_s)
|
29
|
+
end
|
30
|
+
end
|
data/test/eui64_test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require_relative "../lib/netaddr.rb"
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class TestEUI64 < Test::Unit::TestCase
|
7
|
+
def test_new
|
8
|
+
eui = NetAddr::EUI64.new(0)
|
9
|
+
assert_equal("00-00-00-00-00-00-00-00", eui.to_s)
|
10
|
+
|
11
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI64.new(2**64) }
|
12
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI64.new(-1) }
|
13
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI64.new("00-00-00-00-00-00-00-00") } # string
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_parse
|
17
|
+
assert_equal("aa-bb-cc-dd-ee-ff-00-11", NetAddr::EUI64.parse("aa-bb-cc-dd-ee-ff-00-11").to_s)
|
18
|
+
assert_equal("aa-bb-cc-dd-ee-ff-00-11", NetAddr::EUI64.parse("aa:bb:cc:dd:ee:ff:00:11").to_s)
|
19
|
+
assert_equal("aa-bb-cc-dd-ee-ff-00-11", NetAddr::EUI64.parse("aabb.ccdd.eeff.0011").to_s)
|
20
|
+
assert_equal("aa-bb-cc-dd-ee-ff-00-11", NetAddr::EUI64.parse("aabbccddeeff0011").to_s)
|
21
|
+
|
22
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI64.parse("aa-bb-cc-dd-ee-ff-00-11-22") }
|
23
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI64.parse("aa-bb-cc-dd-ee-ff-gg") }
|
24
|
+
assert_raise(NetAddr::ValidationError){ NetAddr::EUI64.parse("aa;bb;cc;dd;ee;ff;00;11") }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_to_ipv6
|
28
|
+
net = NetAddr::IPv6Net.parse("fe80::/64")
|
29
|
+
eui = NetAddr::EUI64.parse("aa-bb-cc-dd-ee-ff-00-11")
|
30
|
+
assert_equal("fe80::a8bb:ccdd:eeff:11", eui.to_ipv6(net).to_s)
|
31
|
+
end
|
32
|
+
end
|