netaddr 2.0.4 → 2.0.5

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
2
  SHA256:
3
- metadata.gz: de26482bcd44b80695dd256c99f45c9f5ceb4d7bec3cfc57c60a0f59a860188d
4
- data.tar.gz: f86ab761fd9ab76f1de6f1fb26d4f89fa85390ab772c3144de18d07b5202dc0e
3
+ metadata.gz: 9a1415cbc9b4353fc9da565edf3ac8a7a9e0494e9a69d5767c1a46219abc4b24
4
+ data.tar.gz: d6d34f2d5dff1beea5855bfac31d5bbb12a3358f8f12aee2513dc074047037d7
5
5
  SHA512:
6
- metadata.gz: e5afb658aa8805f286b273ada3a86fae37b6fd8c4e6ef441845e78fa70e351c7c9b2df2b84f8e919a5cea032ad801b0f1fe36494e13b8e9b3afcf7ecd2ac869b
7
- data.tar.gz: 339ba4279b2f90223362c40ca5753922b889bf2cc2870c4a7a9ddd774668ad7dd419144a9773bd371a5ca16e6d77b7465756fcf5f46bf2410effbbc3a1dc0e55
6
+ metadata.gz: fb448e9527d5bca2ec9c8f095dcf6b825de2919a429bf6aa50b757b2b71dcc9778b2910a090fbba3af209349f295ab59df29cb95f76057400e16a6b9eb892e93
7
+ data.tar.gz: b2ff3dffd33f4bc1ce5b0e1fc16f3121cb2a7f75d9a0a6321daf7c1cc7adea85224d1bb1d0a4593706d0125341fa0c82c464a5ed8d3d5f34de79721df0dcf5ac
data/lib/ipv6.rb CHANGED
@@ -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(":")
data/lib/netaddr.rb CHANGED
@@ -39,10 +39,10 @@ module NetAddr
39
39
 
40
40
  ## parse_ip parses a string into an IPv4 or IPv6
41
41
  def parse_ip(ip)
42
- if (ip.include?(".")) # ipv4
43
- return IPv4.parse(ip)
42
+ if (ip.include?(":"))
43
+ return IPv6.parse(ip)
44
44
  end
45
- return IPv6.parse(ip)
45
+ return IPv4.parse(ip)
46
46
  end
47
47
  module_function :parse_ip
48
48
 
data/lib/util.rb CHANGED
@@ -49,7 +49,7 @@ module NetAddr
49
49
  # fill returns a copy of the given Array, stripped of any networks which are not subnets of ipnet
50
50
  # and with any missing gaps filled in.
51
51
  def Util.fill(ipnet,list)
52
- # sort & git rid of non subnets
52
+ # sort & get rid of non subnets
53
53
  subs = []
54
54
  discard_subnets(list).each do |sub|
55
55
  r = ipnet.rel(sub)
@@ -67,21 +67,14 @@ module NetAddr
67
67
  filled = backfill(subs[0],base)
68
68
  end
69
69
 
70
- # fill gaps
71
- sib = ipnet.next_sib()
72
- ceil = NetAddr::F32
73
- if (sib != nil)
74
- ceil = sib.network.addr
75
- end
76
-
70
+ # fill gaps between subnets
77
71
  0.upto(subs.length-1) do |i|
78
72
  sub = subs[i]
79
- filled.push(sub)
80
- limit = ceil
81
73
  if (i+1 < subs.length)
82
- limit = subs[i+1].network.addr
74
+ filled.concat( fwdfill(sub,ipnet,subs[i+1]) )
75
+ else
76
+ filled.concat( fwdfill(sub,ipnet,nil) )
83
77
  end
84
- filled.concat( fwdfill(sub,limit) )
85
78
  end
86
79
  end
87
80
  return filled
@@ -131,18 +124,80 @@ module NetAddr
131
124
  return filtered
132
125
  end
133
126
 
134
- # fwdfill returns subnets between given IPv4Net/IPv6Nett and the limit address.
135
- # limit should be > ipnet. will create subnets up to limit.
136
- def Util.fwdfill(ipnet,limit)
137
- 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]
138
130
  cur = ipnet
139
- while true do
140
- net = cur.next
141
- if (net == nil || net.network.addr >= limit)
142
- 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
143
200
  end
144
- nets.push(net)
145
- cur = net
146
201
  end
147
202
  return nets
148
203
  end
@@ -185,7 +240,7 @@ module NetAddr
185
240
  # parse_IPv6 parses an IPv6 address String into an Integer
186
241
  def Util.parse_IPv6(ip)
187
242
  # check that only valid characters are present
188
- if (ip =~ /[^0-9a-fA-F\:]/)
243
+ if (ip =~ /[^0-9a-fA-F\:.]/)
189
244
  raise ValidationError, "#{ip} contains invalid characters."
190
245
  end
191
246
 
@@ -193,6 +248,16 @@ module NetAddr
193
248
  if (ip == "::")
194
249
  return 0 # zero address
195
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
196
261
  words = []
197
262
  if (ip.include?("::")) # short format
198
263
  if (ip =~ /:{3,}/) # make sure only i dont have ":::"
@@ -228,7 +293,6 @@ module NetAddr
228
293
  raise ValidationError, "#{ip} is too short."
229
294
  end
230
295
  end
231
-
232
296
  ipInt = 0
233
297
  i = 8
234
298
  words.each do |word|
@@ -236,7 +300,9 @@ module NetAddr
236
300
  word = word.to_i(16) << (16*i)
237
301
  ipInt = ipInt | word
238
302
  end
239
-
303
+ if ipv4Int # re-add ipv4 portion if present
304
+ ipInt = ipInt | ipv4Int
305
+ end
240
306
  return ipInt
241
307
  end
242
308
 
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
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.4
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dustin Spinhirne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-03 00:00:00.000000000 Z
11
+ date: 2021-10-07 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.7.6.2
63
+ rubygems_version: 3.1.2
65
64
  signing_key:
66
65
  specification_version: 4
67
66
  summary: A Ruby library for performing calculations on IPv4 and IPv6 subnets.