netaddr 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
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.