netaddr 2.0.3 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 89ce300b6a351757d48c569e132c3e1346f7b09a
4
- data.tar.gz: 5f11179793ee8a0d5a42758524b7aa49f71392cc
2
+ SHA256:
3
+ metadata.gz: 13e871a188dbf2b94f5c57fe638c5dac249792134a8eece5386fbc36d1ea88d6
4
+ data.tar.gz: 14e02af771158f3003e49181ed49fe7e2fa8d201991215bda51fc2a48b15a96a
5
5
  SHA512:
6
- metadata.gz: 36acfbba061405495f4e4d08c271f6be19c9810de6c5a44f78a2ebf407cf24637dac6b50277c82cc6048e36d00785e143aa37170e0101d40638b36f77e575c5a
7
- data.tar.gz: c9baee3f002fb16def0f60f8e9304b44015739f0a5f844b1413f8b20d2d80c9bc73678654f81906ef14255f9928b64a3153eba120e387f4044bd558e5d6f5df3
6
+ metadata.gz: 2c1baeafeba2d571e007da5ed16276c3fadccb9be542ea47922878ba2e9889e8912145482db9b3c10f2aad3a7a19005ad0499005f71f893bb2db1e7806db1ed2
7
+ data.tar.gz: 3a287b3d7cb1f87cc46e50fefc54952c80e2ff43581492328a27091605db7937cde768d5003d9eeda201ee5e1b353de86e4602bf093bea497bac3403612f6e0f
data/LICENSE CHANGED
File without changes
data/README.md CHANGED
File without changes
data/lib/eui48.rb CHANGED
File without changes
data/lib/eui64.rb CHANGED
File without changes
data/lib/ipv4.rb CHANGED
@@ -19,7 +19,7 @@ module NetAddr
19
19
  # parse will create an IPv4 from its string representation (ie. "192.168.1.1").
20
20
  # Throws ValidationError on error.
21
21
  def IPv4.parse(ip)
22
- ip.strip!
22
+ ip = ip.strip
23
23
  i = Util.parse_IPv4(ip)
24
24
  return IPv4.new(i)
25
25
  end
@@ -77,6 +77,11 @@ module NetAddr
77
77
  Util.int_to_IPv4(@addr)
78
78
  end
79
79
 
80
+ # version returns "4" for IPv4
81
+ def version()
82
+ return 4
83
+ end
84
+
80
85
  end # end class IPv4
81
86
 
82
87
  end # end module
data/lib/ipv4net.rb CHANGED
@@ -23,7 +23,7 @@ module NetAddr
23
23
  # parse will create an IPv4Net from its string representation. Will default to a /32 netmask if not specified.
24
24
  # Throws ValidationError on error.
25
25
  def IPv4Net.parse(net)
26
- net.strip!
26
+ net = net.strip
27
27
  m32 = nil
28
28
  if (net.include?("/")) # cidr format
29
29
  addr,mask = net.split("/")
@@ -220,6 +220,11 @@ module NetAddr
220
220
  return @base.to_s + @m32.to_s
221
221
  end
222
222
 
223
+ # version returns "4" for IPv4
224
+ def version()
225
+ return 4
226
+ end
227
+
223
228
 
224
229
  protected
225
230
 
data/lib/ipv6.rb CHANGED
@@ -19,7 +19,7 @@ module NetAddr
19
19
  # parse will create an IPv6 from its string representation (ie. "1::").
20
20
  # Throws ValidationError on error.
21
21
  def IPv6.parse(ip)
22
- ip.strip!
22
+ ip = ip.strip
23
23
  i = Util.parse_IPv6(ip)
24
24
  return IPv6.new(i)
25
25
  end
@@ -40,6 +40,31 @@ module NetAddr
40
40
  return 0
41
41
  end
42
42
 
43
+ # ipv4 generates an IPv4 from an IPv6 address. The IPv4 address is generated based on the mechanism described by RFC 6052.
44
+ # The argument pl (prefix length) should be one of: 32, 40, 48, 56, 64, or 96. Default is 96 unless one of the supported values is provided.
45
+ def ipv4(pl=96)
46
+ if (pl == 32)
47
+ i = (@addr >> 64) # get bits 32-63 into position
48
+ return IPv4.new(i & NetAddr::F32)
49
+ elsif (pl == 40)
50
+ i = (@addr >> 48) & 0xff # get the last 8 bits into position
51
+ i2 = (@addr & 0xffffff0000000000000000) >> 56 # get first 24 bits into position
52
+ return IPv4.new(i | i2)
53
+ elsif (pl == 48)
54
+ i = (@addr >> 40) & 0xffff # get the last 16 bits into position
55
+ i2 = (@addr & 0xffff0000000000000000) >> 48 # get first 16 bits into position
56
+ return IPv4.new(i | i2)
57
+ elsif (pl == 56)
58
+ i = (@addr >> 32) & 0xffffff # get the last 24 bits into position
59
+ i2 = (@addr & 0xff0000000000000000) >> 40 # get first 8 bits into position
60
+ return IPv4.new(i | i2)
61
+ elsif (pl == 64)
62
+ i = (@addr >> 24) # get the 32 bits into position
63
+ return IPv4.new(i & NetAddr::F32)
64
+ end
65
+ return IPv4.new(@addr & NetAddr::F32)
66
+ end
67
+
43
68
  # long returns the IPv6 as a string in long (uncompressed) format
44
69
  def long()
45
70
  words = []
@@ -100,8 +125,9 @@ module NetAddr
100
125
  end
101
126
  end
102
127
 
103
- # compress if we've found a series of 0 words in a row
104
- if (finalStart != -1)
128
+ # compress if we've found a series of zero fields in a row.
129
+ # per https://tools.ietf.org/html/rfc5952#section-4.2.2 we must not compress just a single 16-bit zero field.
130
+ if (finalLen > 1)
105
131
  head = hexStr[0,finalStart].join(":")
106
132
  tailStart = finalStart + finalLen
107
133
  tail = hexStr[tailStart..7].join(":")
@@ -110,6 +136,11 @@ module NetAddr
110
136
  return hexStr.join(":")
111
137
  end
112
138
 
139
+ # version returns "6" for IPv6
140
+ def version()
141
+ return 6
142
+ end
143
+
113
144
  end # end class IPv6
114
145
 
115
146
  end # end module
data/lib/ipv6net.rb CHANGED
@@ -28,7 +28,7 @@ module NetAddr
28
28
  # Throws ValidationError on error.
29
29
  def IPv6Net.parse(net)
30
30
  m128 = nil
31
- net.strip!
31
+ net = net.strip
32
32
  if (net.include?("/")) # cidr format
33
33
  addr,mask = net.split("/")
34
34
  m128 = Mask128.parse(mask)
@@ -224,6 +224,11 @@ module NetAddr
224
224
  return @base.to_s + @m128.to_s
225
225
  end
226
226
 
227
+ # version returns "6" for IPv6
228
+ def version()
229
+ return 6
230
+ end
231
+
227
232
 
228
233
  protected
229
234
 
data/lib/mask128.rb CHANGED
@@ -26,11 +26,13 @@ module NetAddr
26
26
  #
27
27
  # Throws ValidationError on error.
28
28
  def Mask128.parse(mask)
29
- mask.strip!
29
+ mask = mask.strip
30
30
  if (mask.start_with?("/")) # cidr format
31
31
  mask = mask[1..-1] # remove "/"
32
32
  end
33
- return Mask128.new(mask.to_i)
33
+ return Mask128.new(Integer(mask))
34
+ rescue ArgumentError
35
+ raise ValidationError, "#{mask} is not valid integer."
34
36
  end
35
37
 
36
38
  #cmp compares equality with another Mask128. Return:
data/lib/mask32.rb CHANGED
@@ -26,11 +26,17 @@ module NetAddr
26
26
  #
27
27
  # Throws ValidationError on error.
28
28
  def Mask32.parse(mask)
29
- mask.strip!
29
+ mask = mask.strip
30
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)
31
+ mask = mask[1..-1] # remove "/"
32
+ end
33
+
34
+ if (!mask.include?("."))
35
+ begin
36
+ return Mask32.new(Integer(mask))
37
+ rescue ArgumentError
38
+ raise ValidationError, "#{mask} is not valid integer."
39
+ end
34
40
  end
35
41
 
36
42
  # for extended netmask
@@ -62,7 +68,7 @@ module NetAddr
62
68
 
63
69
  # extended returns the Mask32 in extended format (eg. x.x.x.x)
64
70
  def extended()
65
- Util.intToMask32(@mask)
71
+ Util.int_to_IPv4(@mask)
66
72
  end
67
73
 
68
74
  #cmp compares equality with another Mask32. Return:
data/lib/netaddr.rb CHANGED
@@ -37,6 +37,24 @@ module NetAddr
37
37
  end
38
38
  module_function :ipv4_prefix_len
39
39
 
40
+ ## parse_ip parses a string into an IPv4 or IPv6
41
+ def parse_ip(ip)
42
+ if (ip.include?(":"))
43
+ return IPv6.parse(ip)
44
+ end
45
+ return IPv4.parse(ip)
46
+ end
47
+ module_function :parse_ip
48
+
49
+ ## parse_net parses a string into an IPv4Net or IPv6Net
50
+ def parse_net(net)
51
+ if (net.include?(":"))
52
+ return IPv6Net.parse(net)
53
+ end
54
+ return IPv4Net.parse(net)
55
+ end
56
+ module_function :parse_net
57
+
40
58
  # sort_IPv4 sorts a list of IPv4 objects in ascending order.
41
59
  # It will return a new list with any non IPv4 objects removed.
42
60
  def sort_IPv4(list)
data/lib/util.rb CHANGED
@@ -23,35 +23,33 @@ module NetAddr
23
23
 
24
24
  # discard_subnets returns a copy of the IPv4NetList with any entries which are subnets of other entries removed.
25
25
  def Util.discard_subnets(list)
26
- unrelated = []
27
- supernets = []
26
+ keepers = []
28
27
  last = list[list.length-1]
28
+ keep_last = true
29
29
  list.each do |net|
30
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)
31
+ if (!rel) # keep unrelated nets
32
+ keepers.push(net)
33
+ elsif (rel == -1) # keep supernets, but do not keep last
34
+ keepers.push(net)
35
+ keep_last = false
35
36
  end
36
37
  end
37
38
 
38
- cleaned = []
39
- if (supernets.length > 0)
40
- cleaned = discard_subnets(supernets)
41
- else
42
- cleaned.push(last)
39
+ # recursively clean up keepers
40
+ if (keepers.length > 0)
41
+ keepers = discard_subnets(keepers)
43
42
  end
44
-
45
- if (unrelated.length > 0)
46
- cleaned.concat( discard_subnets(unrelated) )
43
+ if keep_last
44
+ keepers.unshift(last)
47
45
  end
48
- return cleaned
46
+ return keepers
49
47
  end
50
48
 
51
49
  # fill returns a copy of the given Array, stripped of any networks which are not subnets of ipnet
52
50
  # and with any missing gaps filled in.
53
51
  def Util.fill(ipnet,list)
54
- # sort & git rid of non subnets
52
+ # sort & get rid of non subnets
55
53
  subs = []
56
54
  discard_subnets(list).each do |sub|
57
55
  r = ipnet.rel(sub)
@@ -69,21 +67,14 @@ module NetAddr
69
67
  filled = backfill(subs[0],base)
70
68
  end
71
69
 
72
- # fill gaps
73
- sib = ipnet.next_sib()
74
- ceil = NetAddr::F32
75
- if (sib != nil)
76
- ceil = sib.network.addr
77
- end
78
-
70
+ # fill gaps between subnets
79
71
  0.upto(subs.length-1) do |i|
80
72
  sub = subs[i]
81
- filled.push(sub)
82
- limit = ceil
83
73
  if (i+1 < subs.length)
84
- limit = subs[i+1].network.addr
74
+ filled.concat( fwdfill(sub,ipnet,subs[i+1]) )
75
+ else
76
+ filled.concat( fwdfill(sub,ipnet,nil) )
85
77
  end
86
- filled.concat( fwdfill(sub,limit) )
87
78
  end
88
79
  end
89
80
  return filled
@@ -133,18 +124,80 @@ module NetAddr
133
124
  return filtered
134
125
  end
135
126
 
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 = []
127
+ # fwdfill returns subnets between given IPv4Net/IPv6Nett and the limit address. limit should be > ipnet.
128
+ def Util.fwdfill(ipnet,supernet,limit)
129
+ nets = [ipnet]
140
130
  cur = ipnet
141
- while true do
142
- net = cur.next
143
- if (net == nil || net.network.addr >= limit)
144
- break
131
+ if (limit != nil) # if limit, then fill gaps between net and limit
132
+ while true do
133
+ nextSub = cur.next()
134
+ # ensure we've not exceed the total address space
135
+ if (nextSub == nil)
136
+ break
137
+ end
138
+ # ensure we've not exceeded the address space of supernet
139
+ if (supernet.rel(nextSub) == nil)
140
+ break
141
+ end
142
+ # ensure we've not hit limit
143
+ if (nextSub.network.addr == limit.network.addr)
144
+ break
145
+ end
146
+
147
+ # check relationship to limit
148
+ if (nextSub.rel(limit) != nil) # if related, then nextSub must be a supernet of limit. we need to shrink it.
149
+ prefixLen = nextSub.netmask.prefix_len
150
+ while true do
151
+ prefixLen += 1
152
+ if (nextSub.kind_of?(IPv4Net))
153
+ nextSub = IPv4Net.new(nextSub.network, Mask32.new(prefixLen))
154
+ else
155
+ nextSub = IPv6Net.new(nextSub.network, Mask128.new(prefixLen))
156
+ end
157
+ if (nextSub.rel(limit) == nil) # stop when we no longer overlap with limit
158
+ break
159
+ end
160
+ end
161
+ else # otherwise, if unrelated then grow until we hit the limit
162
+ prefixLen = nextSub.netmask.prefix_len
163
+ mask = nextSub.netmask.mask
164
+ while true do
165
+ prefixLen -= 1
166
+ if (prefixLen == supernet.netmask.prefix_len) # break if we've hit the supernet boundary
167
+ break
168
+ end
169
+ mask = mask << 1
170
+ if (nextSub.network.addr|mask != mask) # break when bit boundary crossed (there are '1' bits in the host portion)
171
+ break
172
+ end
173
+ if (nextSub.kind_of?(IPv4Net))
174
+ grown = IPv4Net.new(nextSub.network, Mask32.new(prefixLen))
175
+ else
176
+ grown = IPv6Net.new(nextSub.network, Mask128.new(prefixLen))
177
+ end
178
+ if (grown.rel(limit) != nil) # if we've overlapped with limit in any way, then break
179
+ break
180
+ end
181
+ nextSub = grown
182
+ end
183
+ end
184
+ nets.push(nextSub)
185
+ cur = nextSub
186
+ end
187
+ else # if no limit, then get next largest sibs until we've exceeded supernet
188
+ while true do
189
+ nextSub = cur.next()
190
+ # ensure we've not exceed the total address space
191
+ if (nextSub == nil)
192
+ break
193
+ end
194
+ # ensure we've not exceeded the address space of supernet
195
+ if (supernet.rel(nextSub) == nil)
196
+ break
197
+ end
198
+ nets.push(nextSub)
199
+ cur = nextSub
145
200
  end
146
- nets.push(net)
147
- cur = net
148
201
  end
149
202
  return nets
150
203
  end
@@ -166,8 +219,7 @@ module NetAddr
166
219
  raise ValidationError, "#{ip} contains invalid characters."
167
220
  end
168
221
 
169
- ip.strip!
170
- octets = ip.split('.')
222
+ octets = ip.strip.split('.')
171
223
  if (octets.length != 4)
172
224
  raise ValidationError, "IPv4 requires (4) octets."
173
225
  end
@@ -188,14 +240,24 @@ module NetAddr
188
240
  # parse_IPv6 parses an IPv6 address String into an Integer
189
241
  def Util.parse_IPv6(ip)
190
242
  # check that only valid characters are present
191
- if (ip =~ /[^0-9a-fA-F\:]/)
243
+ if (ip =~ /[^0-9a-fA-F\:.]/)
192
244
  raise ValidationError, "#{ip} contains invalid characters."
193
245
  end
194
246
 
195
- ip.strip!
247
+ ip = ip.strip
196
248
  if (ip == "::")
197
249
  return 0 # zero address
198
250
  end
251
+ ipv4Int = nil
252
+ if (ip.include?(".")) # check for ipv4 embedded addresses
253
+ words = ip.split(":")
254
+ begin
255
+ ipv4Int = Util.parse_IPv4(words.last)
256
+ rescue
257
+ raise ValidationError, "IPv4-embedded IPv6 address is invalid."
258
+ end
259
+ ip = ip.sub(words.last,"0:0") # temporarily remove the ipv4 portion
260
+ end
199
261
  words = []
200
262
  if (ip.include?("::")) # short format
201
263
  if (ip =~ /:{3,}/) # make sure only i dont have ":::"
@@ -231,7 +293,6 @@ module NetAddr
231
293
  raise ValidationError, "#{ip} is too short."
232
294
  end
233
295
  end
234
-
235
296
  ipInt = 0
236
297
  i = 8
237
298
  words.each do |word|
@@ -239,7 +300,9 @@ module NetAddr
239
300
  word = word.to_i(16) << (16*i)
240
301
  ipInt = ipInt | word
241
302
  end
242
-
303
+ if ipv4Int # re-add ipv4 portion if present
304
+ ipInt = ipInt | ipv4Int
305
+ end
243
306
  return ipInt
244
307
  end
245
308
 
data/test/eui48_test.rb CHANGED
File without changes
data/test/eui64_test.rb CHANGED
File without changes
data/test/examples.rb CHANGED
File without changes
data/test/ipv4_test.rb CHANGED
File without changes
data/test/ipv4net_test.rb CHANGED
@@ -52,6 +52,7 @@ class TestIPv4Net < Test::Unit::TestCase
52
52
  end
53
53
 
54
54
  def test_fill
55
+ # filter supernet. remove subnets of subnets. basic fwd fill.
55
56
  parent = NetAddr::IPv4Net.parse("10.0.0.0/24")
56
57
  nets = []
57
58
  ["10.0.0.0/24", "10.0.0.0/8", "10.0.0.8/30", "10.0.0.16/30", "10.0.0.16/28"].each do |net|
@@ -64,6 +65,7 @@ class TestIPv4Net < Test::Unit::TestCase
64
65
  i += 1
65
66
  end
66
67
 
68
+ # basic backfill
67
69
  parent = NetAddr::IPv4Net.parse("128.0.0.0/1")
68
70
  nets = []
69
71
  ["192.0.0.0/2"].each do |net|
@@ -76,6 +78,7 @@ class TestIPv4Net < Test::Unit::TestCase
76
78
  i += 1
77
79
  end
78
80
 
81
+ # basic fwd fill with non-contiguous subnets
79
82
  parent = NetAddr::IPv4Net.parse("1.0.0.0/25")
80
83
  nets = []
81
84
  ["1.0.0.0/30", "1.0.0.64/26"].each do |net|
@@ -87,6 +90,32 @@ class TestIPv4Net < Test::Unit::TestCase
87
90
  assert_equal(expect[i],net.to_s)
88
91
  i += 1
89
92
  end
93
+
94
+ # basic backfill. complex fwd fill that uses 'shrink' of the proposed 1.0.16.0/21 subnet
95
+ parent = NetAddr::IPv4Net.parse("1.0.0.0/19")
96
+ nets = []
97
+ ["1.0.8.0/21", "1.0.20.0/24"].each do |net|
98
+ nets.push(NetAddr::IPv4Net.parse(net))
99
+ end
100
+ expect = ["1.0.0.0/21","1.0.8.0/21","1.0.16.0/22","1.0.20.0/24","1.0.21.0/24","1.0.22.0/23","1.0.24.0/21"]
101
+ i = 0
102
+ parent.fill(nets).each do |net|
103
+ assert_equal(expect[i],net.to_s)
104
+ i += 1
105
+ end
106
+
107
+ # list contains the supernet
108
+ parent = NetAddr::IPv4Net.parse("1.0.0.0/19")
109
+ nets = []
110
+ ["1.0.0.0/19"].each do |net|
111
+ nets.push(NetAddr::IPv4Net.parse(net))
112
+ end
113
+ expect = []
114
+ i = 0
115
+ parent.fill(nets).each do |net|
116
+ assert_equal(expect[i],net.to_s)
117
+ i += 1
118
+ end
90
119
  end
91
120
 
92
121
  def test_len
data/test/ipv6_test.rb CHANGED
@@ -39,6 +39,18 @@ class TestIPv6 < Test::Unit::TestCase
39
39
  assert_equal(0x00000001000200030004000500060007, NetAddr::IPv6.parse("::1:2:3:4:5:6:7").addr)
40
40
  assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("fec0") }
41
41
  assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("fec0:::1") }
42
+
43
+ assert_equal(0x0064ff9b0000000000000000c0000221, NetAddr::IPv6.parse("64:ff9b::192.0.2.33").addr)
44
+ assert_equal(0x0064ff9b0000000000000000c0000221, NetAddr::IPv6.parse("64:ff9b::0:192.0.2.33").addr)
45
+ assert_equal(0x0064ff9b0000000000000000c0000221, NetAddr::IPv6.parse("64:ff9b::0:0:192.0.2.33").addr)
46
+ assert_equal(0x0064ff9b0000000000000000c0000221, NetAddr::IPv6.parse("64:ff9b::0:0:0:192.0.2.33").addr)
47
+ assert_equal(0x0064ff9b0000000000000000c0000221, NetAddr::IPv6.parse("64:ff9b::0:0:0:0:192.0.2.33").addr)
48
+ assert_equal(0x0064ff9b0000000000000000c0000221, NetAddr::IPv6.parse("64:ff9b:0:0:0:0:192.0.2.33").addr)
49
+ assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("64:ff9b::192.0.2") }
50
+ assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("64:ff9b::192.0.2.33.0") }
51
+ assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("64:ff9b::192.0.256.33") }
52
+ assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("64:ff9b:0:0:0:0:0:192.0.2.33") }
53
+ assert_raise(NetAddr::ValidationError){ NetAddr::IPv6.parse("64:ff9b::0:0:0:0:0:192.0.2.33") }
42
54
  end
43
55
 
44
56
  def test_cmp
@@ -51,6 +63,32 @@ class TestIPv6 < Test::Unit::TestCase
51
63
  assert_equal(0, ip.cmp(ip4))
52
64
  end
53
65
 
66
+ def test_ipv4
67
+ ipv6 = NetAddr::IPv6.parse("64:ff9b::192.0.2.33")
68
+ ipv4 = ipv6.ipv4()
69
+ assert_equal("192.0.2.33", ipv4.to_s)
70
+
71
+ ipv6 = NetAddr::IPv6.parse("2001:db8:c000:221::")
72
+ ipv4 = ipv6.ipv4(32)
73
+ assert_equal("192.0.2.33", ipv4.to_s)
74
+
75
+ ipv6 = NetAddr::IPv6.parse("2001:db8:1c0:2:21::")
76
+ ipv4 = ipv6.ipv4(40)
77
+ assert_equal("192.0.2.33", ipv4.to_s)
78
+
79
+ ipv6 = NetAddr::IPv6.parse("2001:db8:122:c000:2:2100::")
80
+ ipv4 = ipv6.ipv4(48)
81
+ assert_equal("192.0.2.33", ipv4.to_s)
82
+
83
+ ipv6 = NetAddr::IPv6.parse("2001:db8:122:3c0:0:221::")
84
+ ipv4 = ipv6.ipv4(56)
85
+ assert_equal("192.0.2.33", ipv4.to_s)
86
+
87
+ ipv6 = NetAddr::IPv6.parse("2001:db8:122:344:c0:2:2100::")
88
+ ipv4 = ipv6.ipv4(64)
89
+ assert_equal("192.0.2.33", ipv4.to_s)
90
+ end
91
+
54
92
  def test_long
55
93
  assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", NetAddr::IPv6.parse("::").long)
56
94
  assert_equal("fe80:0000:0000:0000:0000:0000:0000:0001", NetAddr::IPv6.parse("fe80::1").long)
@@ -83,6 +121,7 @@ class TestIPv6 < Test::Unit::TestCase
83
121
  assert_equal("::1:0:0", NetAddr::IPv6.parse("0:0:0:0:0:1:0:0").to_s)
84
122
  assert_equal("::1:0", NetAddr::IPv6.parse(":0:0:0:0:0:1:0").to_s)
85
123
  assert_equal("::1", NetAddr::IPv6.parse("0:0:0:0:0:0:0:1").to_s)
124
+ assert_equal("1:0:1:1:1:1:1:1", NetAddr::IPv6.parse("1:0:1:1:1:1:1:1").to_s) # see RFC 5952 section 4.2.2
86
125
 
87
126
  assert_equal("1::1", NetAddr::IPv6.parse("1:0:0:0:0:0:0:1").to_s)
88
127
  assert_equal("1:1::1", NetAddr::IPv6.parse("1:1:0:0:0:0:0:1").to_s)
data/test/ipv6net_test.rb CHANGED
@@ -48,18 +48,33 @@ class TestIPv6Net < Test::Unit::TestCase
48
48
  end
49
49
 
50
50
  def test_fill
51
+ # filter supernet. remove subnets of subnets. basic fwd fill.
51
52
  parent = NetAddr::IPv6Net.parse("ff00::/8")
52
53
  nets = []
53
- ["ff08::/14", "fe00::/7", "ff20::/11", "ff20::/12"].each do |net|
54
+ ["ff00::/8", "ff00::/9", "ff08::/14", "fe00::/7", "ff20::/11", "ff20::/12"].each do |net|
54
55
  nets.push(NetAddr::IPv6Net.parse(net))
55
56
  end
56
- expect = ["ff00::/13", "ff08::/14", "ff0c::/14", "ff10::/12", "ff20::/11", "ff40::/10", "ff80::/9"]
57
+ expect = ["ff00::/9", "ff80::/9"]
57
58
  i = 0
58
59
  parent.fill(nets).each do |net|
59
60
  assert_equal(expect[i],net.to_s)
60
61
  i += 1
61
62
  end
62
63
 
64
+ # basic backfill
65
+ parent = NetAddr::IPv6Net.parse("8000::/1")
66
+ nets = []
67
+ ["c000::/2"].each do |net|
68
+ nets.push(NetAddr::IPv6Net.parse(net))
69
+ end
70
+ expect = ["8000::/2","c000::/2"]
71
+ i = 0
72
+ parent.fill(nets).each do |net|
73
+ assert_equal(expect[i],net.to_s)
74
+ i += 1
75
+ end
76
+
77
+ # basic fwd fill with non-contiguous subnets
63
78
  parent = NetAddr::IPv6Net.parse("ff00::/121")
64
79
  nets = []
65
80
  ["ff00::/126", "ff00::/120"].each do |net|
@@ -71,6 +86,33 @@ class TestIPv6Net < Test::Unit::TestCase
71
86
  assert_equal(expect[i],net.to_s)
72
87
  i += 1
73
88
  end
89
+
90
+ # basic backfill. complex fwd fill that uses 'shrink' of the proposed ffff:ffff:ffff:fff8::/62 subnet. designed to cross the /64 bit boundary.
91
+ parent = NetAddr::IPv6Net.parse("fff:ffff:ffff:fff0::/60")
92
+ nets = []
93
+ ["ffff:ffff:ffff:fff4::/62", "ffff:ffff:ffff:fffb::/65"].each do |net|
94
+ nets.push(NetAddr::IPv6Net.parse(net))
95
+ end
96
+ expect = ["ffff:ffff:ffff:fff0::/62", "ffff:ffff:ffff:fff4::/62", "ffff:ffff:ffff:fff8::/63", "ffff:ffff:ffff:fffa::/64", "ffff:ffff:ffff:fffb::/65",
97
+ "ffff:ffff:ffff:fffb:8000::/65", "ffff:ffff:ffff:fffc::/62"]
98
+ i = 0
99
+ parent.fill(nets).each do |net|
100
+ assert_equal(expect[i],net.to_s)
101
+ i += 1
102
+ end
103
+
104
+ # list contains the supernet
105
+ parent = NetAddr::IPv6Net.parse("ffff::/16")
106
+ nets = []
107
+ ["ffff::/16"].each do |net|
108
+ nets.push(NetAddr::IPv6Net.parse(net))
109
+ end
110
+ expect = []
111
+ i = 0
112
+ parent.fill(nets).each do |net|
113
+ assert_equal(expect[i],net.to_s)
114
+ i += 1
115
+ end
74
116
  end
75
117
 
76
118
  def test_next
data/test/mask128_test.rb CHANGED
File without changes
data/test/mask32_test.rb CHANGED
@@ -34,6 +34,11 @@ class TestMask32 < Test::Unit::TestCase
34
34
  assert_equal(0, m.cmp(m4))
35
35
  end
36
36
 
37
+ def test_extended
38
+ m32 = NetAddr::Mask32.new(24)
39
+ assert_equal("255.255.255.0", m32.extended)
40
+ end
41
+
37
42
  def test_len
38
43
  m = NetAddr::Mask32.new(24)
39
44
  assert_equal(256, m.len())
data/test/netaddr_test.rb CHANGED
@@ -5,6 +5,17 @@ require 'test/unit'
5
5
 
6
6
  class TestNetAddr < Test::Unit::TestCase
7
7
 
8
+ def test_parse_ip
9
+ assert_equal("128.0.0.1", NetAddr.parse_ip("128.0.0.1").to_s)
10
+ assert_equal("1::1", NetAddr.parse_ip("1::1").to_s)
11
+ end
12
+
13
+ def test_parse_net
14
+ assert_equal("128.0.0.1/32", NetAddr.parse_net("128.0.0.1/32").to_s)
15
+ assert_equal("1::/24", NetAddr.parse_net("1::1/24").to_s)
16
+ assert_equal("::ffff:aabb:ccdd/128", NetAddr.parse_net("::ffff:170.187.204.221/128").to_s)
17
+ end
18
+
8
19
  def test_ipv4_prefix_len
9
20
  assert_equal(32,NetAddr.ipv4_prefix_len(1))
10
21
  assert_equal(27,NetAddr.ipv4_prefix_len(30))
@@ -67,6 +78,17 @@ class TestNetAddr < Test::Unit::TestCase
67
78
  assert_equal(expect[i],net.to_s)
68
79
  i += 1
69
80
  end
81
+
82
+ nets = []
83
+ ["10.0.0.0/26","10.0.0.64/26","10.0.0.0/24","10.0.0.192/26","10.0.0.128/26"].each do |net| # test out of order
84
+ nets.push(NetAddr::IPv4Net.parse(net))
85
+ end
86
+ expect = ["10.0.0.0/24"]
87
+ i = 0
88
+ NetAddr.summ_IPv4Net(nets).each do |net|
89
+ assert_equal(expect[i],net.to_s)
90
+ i += 1
91
+ end
70
92
  end
71
93
 
72
94
  def test_sort_IPv6
data/test/run_all.rb CHANGED
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: netaddr
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dustin Spinhirne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-23 00:00:00.000000000 Z
11
+ date: 2022-07-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -60,8 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  requirements: []
63
- rubyforge_project:
64
- rubygems_version: 2.5.2.1
63
+ rubygems_version: 3.3.5
65
64
  signing_key:
66
65
  specification_version: 4
67
66
  summary: A Ruby library for performing calculations on IPv4 and IPv6 subnets.