ipaddress 0.7.5 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +13 -0
- data/README.rdoc +106 -80
- data/VERSION +1 -1
- data/ipaddress.gemspec +55 -0
- data/lib/ipaddress.rb +16 -2
- data/lib/ipaddress/ipv4.rb +76 -68
- data/lib/ipaddress/ipv6.rb +132 -22
- data/lib/ipaddress/prefix.rb +14 -1
- data/test/ipaddress/ipv4_test.rb +65 -43
- data/test/ipaddress/ipv6_test.rb +68 -2
- metadata +26 -48
- data/lib/ipaddress/extensions/extensions.rb +0 -22
- data/test/ipaddress/extensions/extensions_test.rb +0 -18
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== ipaddress 0.8.0
|
2
|
+
|
3
|
+
CHANGED:: Removed extension methods and extension directory to facilitate integration with the stdlib
|
4
|
+
CHANGED:: Reworked IPv4#<=>, now intuitively sorts objects based on the prefix
|
5
|
+
CHANGED:: IPv4#supernet now returns "0.0.0.0/0" if supernetting with a prefix less than 1
|
6
|
+
CHANGED:: IPv4#subnet now accept a new prefix instead of number of subnets (as per RFC3531)
|
7
|
+
NEW:: IPv6#network
|
8
|
+
NEW:: Prefix128#host_prefix
|
9
|
+
NEW:: IPv6#broadcast_u128
|
10
|
+
NEW:: IPv6#each
|
11
|
+
NEW:: IPv6#<=>
|
12
|
+
NEW:: IPv4#split
|
13
|
+
|
1
14
|
== ipaddress 0.7.5
|
2
15
|
|
3
16
|
CHANGED:: IPAddress::IPv4#each_host to improve speed
|
data/README.rdoc
CHANGED
@@ -14,44 +14,22 @@ examples of typical usage.
|
|
14
14
|
|
15
15
|
== Requirements
|
16
16
|
|
17
|
-
* Ruby >= 1.8.
|
17
|
+
* Ruby >= 1.8.7 (not tested with previous versions)
|
18
|
+
* Ruby 1.9.2 or later is strongly recommended
|
18
19
|
|
19
|
-
IPAddress
|
20
|
+
IPAddress 0.8.0 has been tested on:
|
20
21
|
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
24
|
-
*
|
25
|
-
*
|
26
|
-
*
|
27
|
-
* Ironruby >= 1.0
|
22
|
+
* ruby-1.8.7-p334 [ i386 ]
|
23
|
+
* ree-1.8.7-2011.03 [ i386 ]
|
24
|
+
* rbx-head [ ]
|
25
|
+
* jruby-1.6.1 [ linux-i386-java ]
|
26
|
+
* ruby-1.9.1-p431 [ i386 ]
|
27
|
+
* ruby-1.9.2-p180 [ i386 ]
|
28
28
|
|
29
|
-
|
29
|
+
If you want to collaborate feel
|
30
30
|
free to send a small report to my email address, or
|
31
31
|
{join the discussion}[http://groups.google.com/group/ruby-ipaddress].
|
32
32
|
|
33
|
-
== Why not using IPAddr?
|
34
|
-
|
35
|
-
IPAddr is the IP addresses library that comes with Ruby standard
|
36
|
-
lib. We found this library, although very well written, not very
|
37
|
-
suitable for all our needs, and not very flexible.
|
38
|
-
|
39
|
-
Some quick examples of things you can't do with IPAddr:
|
40
|
-
|
41
|
-
* store both the address and the prefix information
|
42
|
-
* quickly find the broadcast address of a network
|
43
|
-
* iterate over hosts
|
44
|
-
* perform subnetting or network aggregation
|
45
|
-
|
46
|
-
Many methods and procedures are so old that they have been
|
47
|
-
declared deprecated by the IETF, and some others have bugs in their
|
48
|
-
implementation.
|
49
|
-
|
50
|
-
Moreover, IPAddress is more robust and is already around 50% faster than IPAddr,
|
51
|
-
in addition to provide an organic API with logical separation and OO structure.
|
52
|
-
|
53
|
-
We hope that IPAddress will address all these issues and meet all your
|
54
|
-
needs in network programming.
|
55
33
|
|
56
34
|
== Installation
|
57
35
|
|
@@ -81,7 +59,7 @@ documentation with Rake:
|
|
81
59
|
ipaddress$ rake rdoc
|
82
60
|
|
83
61
|
The latest documentation can be found online at
|
84
|
-
{this address}[http://rubydoc.info/gems/ipaddress/0.
|
62
|
+
{this address}[http://rubydoc.info/gems/ipaddress/0.8.0/frames]
|
85
63
|
|
86
64
|
== IPv4
|
87
65
|
|
@@ -127,9 +105,12 @@ networks. Therefore, the default prefix will be /32, or
|
|
127
105
|
255.255.255.255. For example:
|
128
106
|
|
129
107
|
# let's declare an host address
|
130
|
-
host = IPAddress::IPv4.new "10.1.1.1
|
108
|
+
host = IPAddress::IPv4.new "10.1.1.1"
|
109
|
+
|
110
|
+
puts host.to_string
|
111
|
+
#=> "10.1.1.1/32"
|
131
112
|
|
132
|
-
The new created object
|
113
|
+
The new created object has prefix /32, which is the same
|
133
114
|
as we created the following:
|
134
115
|
|
135
116
|
host = IPAddress::IPv4.new "10.1.1.1/32"
|
@@ -222,7 +203,7 @@ address:
|
|
222
203
|
net.to_string
|
223
204
|
#=> "172.16.10.0/24"
|
224
205
|
|
225
|
-
|
206
|
+
Method IPv4#network creates a new IPv4 object from the network
|
226
207
|
number, calculated after the original object. We want to outline here
|
227
208
|
that the network address is a perfect legitimate IPv4 address, which
|
228
209
|
just happen to have all zeroes in the host portion.
|
@@ -402,63 +383,83 @@ For example, if you have network "172.16.10.0/24", we can subnet it
|
|
402
383
|
into 4 smaller subnets. The new prefix will be /26, because 4 is 2^2
|
403
384
|
and therefore we add 2 bits to the network prefix (24+2=26).
|
404
385
|
|
405
|
-
Subnetting is easy with IPAddress.
|
386
|
+
Subnetting is easy with IPAddress. You actually have two options:
|
406
387
|
|
407
|
-
|
388
|
+
* IPv4#subnet: specify a new prefix
|
389
|
+
* IPv4#split: tell IPAddress how many subnets you want to create.
|
408
390
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
391
|
+
Let's examine IPv4#subnet first. Say you have network "172.16.10.0/24"
|
392
|
+
and you want to subnet it into /26 networks. With IPAddress it's very
|
393
|
+
easy:
|
394
|
+
|
395
|
+
network = IPAddress "172.16.10.0/24"
|
396
|
+
|
397
|
+
subnets = network.subnet(26)
|
414
398
|
|
415
399
|
subnets.map{|i| i.to_string}
|
416
|
-
#=> ["172.16.10.0/26",
|
400
|
+
#=> ["172.16.10.0/26",
|
401
|
+
"172.16.10.64/26",
|
402
|
+
"172.16.10.128/26",
|
417
403
|
"172.16.10.192/26"]
|
418
404
|
|
419
|
-
|
420
|
-
|
421
|
-
calculate a subnet: if the IPv4 object is a host IPv4, the method will
|
422
|
-
calculate the network number for that network and then subnet it. For
|
423
|
-
example:
|
405
|
+
As you can see, an Array has been created, containing 4 new IPv4 objects
|
406
|
+
representing the new subnets.
|
424
407
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
408
|
+
Another way to create subnets is to tell IPAddress how many subnets you'd
|
409
|
+
like to have, and letting the library calculate the new prefix for you.
|
410
|
+
|
411
|
+
Let's see how it works, using IPv4#split method. Say you want 4 new subnets:
|
412
|
+
|
413
|
+
network = IPAddress("172.16.10.0/24")
|
414
|
+
|
415
|
+
subnets = network.split(4)
|
430
416
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
417
|
+
subnets.map{|i| i.to_string}
|
418
|
+
#=> ["172.16.10.0/26",
|
419
|
+
"172.16.10.64/26",
|
420
|
+
"172.16.10.128/26",
|
421
|
+
"172.16.10.192/26"]
|
435
422
|
|
436
|
-
|
423
|
+
Hey, that's the same result as before! This actually makes sense, as the
|
424
|
+
two operations are complementary. When you use IPv4#subnet with the new
|
425
|
+
prefix, IPAddress will always create a number of subnets that is a power
|
426
|
+
of two. This is equivalent to use IPv4#split with a power of 2.
|
437
427
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
428
|
+
Where IPv4#split really shines is with the so called "uneven subnetting".
|
429
|
+
You are not limited to split a network into a power-of-two numbers of
|
430
|
+
subnets: IPAddress lets you create any number of subnets, and it will
|
431
|
+
try to organize the new created network in the best possible way, making
|
432
|
+
an efficent allocation of the space.
|
442
433
|
|
443
|
-
|
434
|
+
An example here is worth a thousand words. Let's use the same network
|
435
|
+
as the previous examples:
|
444
436
|
|
445
437
|
network = IPAddress("172.16.10.0/24")
|
446
438
|
|
447
|
-
|
439
|
+
How do we split this network into 3 subnets? Very easy:
|
440
|
+
|
441
|
+
subnets = network.split(3)
|
442
|
+
|
443
|
+
subnets.map{|i| i.to_string}
|
448
444
|
#=> ["172.16.10.0/26",
|
449
445
|
"172.16.10.64/26",
|
450
446
|
"172.16.10.128/25"]
|
451
447
|
|
452
|
-
|
448
|
+
As you can see, IPAddress tried to perform a good allocation by filling up
|
449
|
+
all the address space from the original network. There is no point in splitting
|
450
|
+
a network into 3 subnets like "172.16.10.0/26", "172.16.10.64/26" and
|
451
|
+
"172.16.10.128/26", as you would end up having "172.16.10.192/26" wasted (plus,
|
452
|
+
I suppose I wouldn't need a Ruby library to perform un-efficient IP
|
453
|
+
allocation, as I do that myself very well ;) ).
|
453
454
|
|
454
|
-
|
455
|
+
We can go even further and split into 11 subnets:
|
455
456
|
|
456
|
-
network.
|
457
|
+
network.split(11)
|
457
458
|
#=> ["172.16.10.0/28", "172.16.10.16/28", "172.16.10.32/28",
|
458
459
|
"172.16.10.48/28", "172.16.10.64/28", "172.16.10.80/28",
|
459
460
|
"172.16.10.96/28", "172.16.10.112/28", "172.16.10.128/27",
|
460
461
|
"172.16.10.160/27", "172.16.10.192/26"]
|
461
|
-
|
462
|
+
|
462
463
|
As you can see, most of the networks are /28, with a few /27 and one
|
463
464
|
/26 to fill up the remaining space.
|
464
465
|
|
@@ -572,7 +573,7 @@ eight groups of four hexadecimal digits, each group representing 16
|
|
572
573
|
bits or two octet. For example, the following is a valid IPv6
|
573
574
|
address:
|
574
575
|
|
575
|
-
|
576
|
+
2001:0db8:0000:0000:0008:0800:200c:417a
|
576
577
|
|
577
578
|
Letters in an IPv6 address are usually written downcase, as per
|
578
579
|
RFC. You can create a new IPv6 object using uppercase letters, but
|
@@ -592,7 +593,7 @@ simplifications and compressions that you can use to shorten them.
|
|
592
593
|
Using compression, the IPv6 address written above can be shorten into
|
593
594
|
the following, equivalent, address
|
594
595
|
|
595
|
-
|
596
|
+
2001:db8::8:800:200c:417a
|
596
597
|
|
597
598
|
This short version is often used in human representation.
|
598
599
|
|
@@ -601,7 +602,7 @@ This short version is often used in human representation.
|
|
601
602
|
As we used to do with IPv4 addresses, an IPv6 address can be written
|
602
603
|
using the prefix notation to specify the subnet mask:
|
603
604
|
|
604
|
-
|
605
|
+
2001:db8::8:800:200c:417a/64
|
605
606
|
|
606
607
|
The /64 part means that the first 64 bits of the address are
|
607
608
|
representing the network portion, and the last 64 bits are the host
|
@@ -612,11 +613,11 @@ portion.
|
|
612
613
|
All the IPv6 representations we've just seen are perfectly fine when
|
613
614
|
you want to create a new IPv6 address:
|
614
615
|
|
615
|
-
ip6 = IPAddress "
|
616
|
+
ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200C:417A"
|
616
617
|
|
617
|
-
ip6 = IPAddress "
|
618
|
+
ip6 = IPAddress "2001:db8:0:0:8:800:200C:417A"
|
618
619
|
|
619
|
-
ip6 = IPAddress "
|
620
|
+
ip6 = IPAddress "2001:db8:8:800:200C:417A"
|
620
621
|
|
621
622
|
All three are giving out the same IPv6 object. The default subnet mask
|
622
623
|
for an IPv6 is 128, as IPv6 addresses don't have classes like IPv4
|
@@ -744,13 +745,13 @@ like in the following example:
|
|
744
745
|
A new IPv6 address can also be created from an unsigned 128 bits
|
745
746
|
integer:
|
746
747
|
|
747
|
-
u128 =
|
748
|
+
u128 = 42540766411282592856906245548098208122
|
748
749
|
|
749
750
|
ip6 = IPAddress::IPv6::parse_u128 u128
|
750
751
|
ip6.prefix = 64
|
751
752
|
|
752
753
|
ip6.to_string
|
753
|
-
#=>
|
754
|
+
#=>"2001:db8::8:800:200c:417a/64"
|
754
755
|
|
755
756
|
Finally, a new IPv6 address can be created from an hex string:
|
756
757
|
|
@@ -909,6 +910,30 @@ group will be automatically added at the beginning
|
|
909
910
|
|
910
911
|
making it a mapped IPv6 compatible address.
|
911
912
|
|
913
|
+
== Why not using IPAddr?
|
914
|
+
|
915
|
+
IPAddr is the IP addresses library that comes with Ruby standard
|
916
|
+
lib. We found this library, although very well written, not very
|
917
|
+
suitable for all our needs, and not very flexible.
|
918
|
+
|
919
|
+
Some quick examples of things you can't do with IPAddr:
|
920
|
+
|
921
|
+
* store both the address and the prefix information
|
922
|
+
* quickly find the broadcast address of a network
|
923
|
+
* iterate over hosts
|
924
|
+
* perform subnetting or network aggregation
|
925
|
+
|
926
|
+
Many methods and procedures are so old that they have been
|
927
|
+
declared deprecated by the IETF, and some others have bugs in their
|
928
|
+
implementation.
|
929
|
+
|
930
|
+
Moreover, IPAddress is more robust and is already around 50% faster than IPAddr,
|
931
|
+
in addition to provide an organic API with logical separation and OO structure.
|
932
|
+
|
933
|
+
We hope that IPAddress will address all these issues and meet all your
|
934
|
+
needs in network programming.
|
935
|
+
|
936
|
+
|
912
937
|
== Community
|
913
938
|
|
914
939
|
Want to join the community?
|
@@ -924,12 +949,13 @@ Feel free to join us and tell us what you think!
|
|
924
949
|
Thanks to Luca Russo (vargolo) and Simone Carletti
|
925
950
|
(weppos) for all the support and technical review. Thanks to Marco Beri,
|
926
951
|
Bryan T. Richardson, Nicolas Fevrier, jdpace, Daniele Alessandri, jrdioko,
|
927
|
-
Ghislain Charrier, Pawel Krzesniak, Mark Sullivan,
|
928
|
-
Steve Rawlinson for their support,
|
952
|
+
Ghislain Charrier, Pawel Krzesniak, Mark Sullivan, Leif Gensert,
|
953
|
+
Erik Ahlström, Peter Vandenberk and Steve Rawlinson for their support,
|
954
|
+
feedback and bug reports.
|
929
955
|
|
930
956
|
== Copyright
|
931
957
|
|
932
958
|
Copyright (c) 2009-2011 Marco Ceresa. See LICENSE for details.
|
933
959
|
|
934
960
|
|
935
|
-
|
961
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/ipaddress.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ipaddress}
|
8
|
+
s.version = "0.8.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Marco Ceresa"]
|
12
|
+
s.date = %q{2011-05-17}
|
13
|
+
s.description = %q{ IPAddress is a Ruby library designed to make manipulation
|
14
|
+
of IPv4 and IPv6 addresses both powerful and simple. It mantains
|
15
|
+
a layer of compatibility with Ruby's own IPAddr, while
|
16
|
+
addressing many of its issues.
|
17
|
+
}
|
18
|
+
s.email = %q{ceresa@gmail.com}
|
19
|
+
s.extra_rdoc_files = [
|
20
|
+
"LICENSE",
|
21
|
+
"README.rdoc"
|
22
|
+
]
|
23
|
+
s.files = [
|
24
|
+
".document",
|
25
|
+
"CHANGELOG.rdoc",
|
26
|
+
"LICENSE",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"ipaddress.gemspec",
|
31
|
+
"lib/ipaddress.rb",
|
32
|
+
"lib/ipaddress/ipv4.rb",
|
33
|
+
"lib/ipaddress/ipv6.rb",
|
34
|
+
"lib/ipaddress/prefix.rb",
|
35
|
+
"test/ipaddress/ipv4_test.rb",
|
36
|
+
"test/ipaddress/ipv6_test.rb",
|
37
|
+
"test/ipaddress/prefix_test.rb",
|
38
|
+
"test/ipaddress_test.rb",
|
39
|
+
"test/test_helper.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/bluemonk/ipaddress}
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.6.2}
|
44
|
+
s.summary = %q{IPv4/IPv6 addresses manipulation library}
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
+
else
|
51
|
+
end
|
52
|
+
else
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/lib/ipaddress.rb
CHANGED
@@ -14,8 +14,6 @@
|
|
14
14
|
|
15
15
|
require 'ipaddress/ipv4'
|
16
16
|
require 'ipaddress/ipv6'
|
17
|
-
require 'ipaddress/extensions/extensions'
|
18
|
-
|
19
17
|
|
20
18
|
module IPAddress
|
21
19
|
|
@@ -145,6 +143,9 @@ module IPAddress
|
|
145
143
|
false
|
146
144
|
end
|
147
145
|
|
146
|
+
#
|
147
|
+
# Deprecate method
|
148
|
+
#
|
148
149
|
def self.deprecate(message = nil) # :nodoc:
|
149
150
|
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
150
151
|
warn("DEPRECATION WARNING: #{message}")
|
@@ -185,4 +186,17 @@ def IPAddress(str)
|
|
185
186
|
IPAddress::parse str
|
186
187
|
end
|
187
188
|
|
189
|
+
#
|
190
|
+
# Compatibility with Ruby 1.8
|
191
|
+
#
|
192
|
+
if RUBY_VERSION =~ /1\.8/
|
193
|
+
class Hash # :nodoc:
|
194
|
+
alias :key :index
|
195
|
+
end
|
196
|
+
module Math # :nodoc:
|
197
|
+
def Math.log2(n)
|
198
|
+
log(n) / log(2)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
188
202
|
|
data/lib/ipaddress/ipv4.rb
CHANGED
@@ -426,14 +426,22 @@ module IPAddress;
|
|
426
426
|
end
|
427
427
|
|
428
428
|
#
|
429
|
-
# Spaceship operator to compare
|
429
|
+
# Spaceship operator to compare IPv4 objects
|
430
430
|
#
|
431
|
-
#
|
432
|
-
#
|
433
|
-
#
|
431
|
+
# Comparing IPv4 addresses is useful to ordinate
|
432
|
+
# them into lists that match our intuitive
|
433
|
+
# perception of ordered IP addresses.
|
434
|
+
#
|
435
|
+
# The first comparison criteria is the u32 value.
|
436
|
+
# For example, 10.100.100.1 will be considered
|
437
|
+
# to be less than 172.16.0.1, because, in a ordered list,
|
438
|
+
# we expect 10.100.100.1 to come before 172.16.0.1.
|
434
439
|
#
|
435
|
-
#
|
436
|
-
#
|
440
|
+
# The second criteria, in case two IPv4 objects
|
441
|
+
# have identical addresses, is the prefix. An higher
|
442
|
+
# prefix will be considered greater than a lower
|
443
|
+
# prefix. This is because we expect to see
|
444
|
+
# 10.100.100.0/24 come before 10.100.100.0/25.
|
437
445
|
#
|
438
446
|
# Example:
|
439
447
|
#
|
@@ -443,22 +451,15 @@ module IPAddress;
|
|
443
451
|
#
|
444
452
|
# ip1 < ip2
|
445
453
|
# #=> true
|
446
|
-
# ip1
|
454
|
+
# ip1 > ip3
|
447
455
|
# #=> false
|
448
456
|
#
|
457
|
+
# [ip1,ip2,ip3].sort.map{|i| i.to_string}
|
458
|
+
# #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
|
459
|
+
#
|
449
460
|
def <=>(oth)
|
450
|
-
if to_u32
|
451
|
-
|
452
|
-
elsif to_u32 < oth.to_u32
|
453
|
-
return -1
|
454
|
-
else
|
455
|
-
if prefix < oth.prefix
|
456
|
-
return 1
|
457
|
-
elsif prefix > oth.prefix
|
458
|
-
return -1
|
459
|
-
end
|
460
|
-
end
|
461
|
-
return 0
|
461
|
+
return prefix <=> oth.prefix if to_u32 == oth.to_u32
|
462
|
+
to_u32 <=> oth.to_u32
|
462
463
|
end
|
463
464
|
|
464
465
|
#
|
@@ -552,30 +553,6 @@ module IPAddress;
|
|
552
553
|
others.all? {|oth| include?(oth)}
|
553
554
|
end
|
554
555
|
|
555
|
-
#
|
556
|
-
# True if the object is an IPv4 address
|
557
|
-
#
|
558
|
-
# ip = IPAddress("192.168.10.100/24")
|
559
|
-
#
|
560
|
-
# ip.ipv4?
|
561
|
-
# #-> true
|
562
|
-
#
|
563
|
-
# def ipv4?
|
564
|
-
# true
|
565
|
-
# end
|
566
|
-
|
567
|
-
#
|
568
|
-
# True if the object is an IPv6 address
|
569
|
-
#
|
570
|
-
# ip = IPAddress("192.168.10.100/24")
|
571
|
-
#
|
572
|
-
# ip.ipv6?
|
573
|
-
# #-> false
|
574
|
-
#
|
575
|
-
# def ipv6?
|
576
|
-
# false
|
577
|
-
# end
|
578
|
-
|
579
556
|
#
|
580
557
|
# Checks if an IPv4 address objects belongs
|
581
558
|
# to a private network RFC1918
|
@@ -607,10 +584,10 @@ module IPAddress;
|
|
607
584
|
alias_method :arpa, :reverse
|
608
585
|
|
609
586
|
#
|
610
|
-
#
|
587
|
+
# Splits a network into different subnets
|
611
588
|
#
|
612
589
|
# If the IP Address is a network, it can be divided into
|
613
|
-
# multiple networks. If +self+ is not a network,
|
590
|
+
# multiple networks. If +self+ is not a network, this
|
614
591
|
# method will calculate the network from the IP and then
|
615
592
|
# subnet it.
|
616
593
|
#
|
@@ -636,15 +613,19 @@ module IPAddress;
|
|
636
613
|
# "172.16.10.64/26",
|
637
614
|
# "172.16.10.128/25"]
|
638
615
|
#
|
639
|
-
# Returns an array of
|
616
|
+
# Returns an array of IPv4 objects
|
640
617
|
#
|
641
|
-
def
|
618
|
+
def split(subnets=2)
|
642
619
|
unless (1..(2**@prefix.host_prefix)).include? subnets
|
643
620
|
raise ArgumentError, "Value #{subnets} out of range"
|
644
621
|
end
|
645
|
-
|
622
|
+
networks = subnet(newprefix(subnets))
|
623
|
+
until networks.size == subnets
|
624
|
+
networks = sum_first_found(networks)
|
625
|
+
end
|
626
|
+
return networks
|
646
627
|
end
|
647
|
-
alias_method :/, :
|
628
|
+
alias_method :/, :split
|
648
629
|
|
649
630
|
#
|
650
631
|
# Returns a new IPv4 object from the supernetting
|
@@ -667,11 +648,44 @@ module IPAddress;
|
|
667
648
|
#
|
668
649
|
# ip.supernet(22).to_string
|
669
650
|
# #=> "172.16.8.0/22"
|
670
|
-
#
|
651
|
+
#
|
652
|
+
# If +new_prefix+ is less than 1, returns 0.0.0.0/0
|
653
|
+
#
|
671
654
|
def supernet(new_prefix)
|
672
|
-
raise ArgumentError, "Can't supernet a /1 network" if new_prefix < 1
|
673
655
|
raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i
|
674
|
-
self.class.new(
|
656
|
+
return self.class.new("0.0.0.0/0") if new_prefix < 1
|
657
|
+
return self.class.new(@address+"/#{new_prefix}").network
|
658
|
+
end
|
659
|
+
|
660
|
+
#
|
661
|
+
# This method implements the subnetting function
|
662
|
+
# similar to the one described in RFC3531.
|
663
|
+
#
|
664
|
+
# By specifying a new prefix, the method calculates
|
665
|
+
# the network number for the given IPv4 object
|
666
|
+
# and calculates the subnets associated to the new
|
667
|
+
# prefix.
|
668
|
+
#
|
669
|
+
# For example, given the following network:
|
670
|
+
#
|
671
|
+
# ip = IPAddress "172.16.10.0/24"
|
672
|
+
#
|
673
|
+
# we can calculate the subnets with a /26 prefix
|
674
|
+
#
|
675
|
+
# ip.subnets(26).map{&:to_string)
|
676
|
+
# #=> ["172.16.10.0/26", "172.16.10.64/26",
|
677
|
+
# "172.16.10.128/26", "172.16.10.192/26"]
|
678
|
+
#
|
679
|
+
# The resulting number of subnets will of course always be
|
680
|
+
# a power of two.
|
681
|
+
#
|
682
|
+
def subnet(subprefix)
|
683
|
+
unless ((@prefix.to_i)..32).include? subprefix
|
684
|
+
raise ArgumentError, "New prefix must be between #@prefix and 32"
|
685
|
+
end
|
686
|
+
Array.new(2**(subprefix-@prefix.to_i)) do |i|
|
687
|
+
self.class.parse_u32(network_u32+(i*(2**(32-subprefix))), subprefix)
|
688
|
+
end
|
675
689
|
end
|
676
690
|
|
677
691
|
#
|
@@ -928,9 +942,6 @@ module IPAddress;
|
|
928
942
|
# * Class B, from 128.0.0.0 to 191.255.255.255
|
929
943
|
# * Class C, D and E, from 192.0.0.0 to 255.255.255.254
|
930
944
|
#
|
931
|
-
# Note that classes C, D and E will all have a default
|
932
|
-
# prefix of /24 or 255.255.255.0
|
933
|
-
#
|
934
945
|
# Example:
|
935
946
|
#
|
936
947
|
# ip = IPAddress::IPv4.parse_classful "10.0.0.1"
|
@@ -940,6 +951,9 @@ module IPAddress;
|
|
940
951
|
# ip.a?
|
941
952
|
# #=> true
|
942
953
|
#
|
954
|
+
# Note that classes C, D and E will all have a default
|
955
|
+
# prefix of /24 or 255.255.255.0
|
956
|
+
#
|
943
957
|
def self.parse_classful(ip)
|
944
958
|
if IPAddress.valid_ipv4?(ip)
|
945
959
|
address = ip.strip
|
@@ -954,25 +968,19 @@ module IPAddress;
|
|
954
968
|
# private methods
|
955
969
|
#
|
956
970
|
private
|
957
|
-
|
958
|
-
def
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
mul = i * (2**(32-new_prefix))
|
964
|
-
networks << IPAddress::IPv4.parse_u32(network_u32+mul, new_prefix)
|
965
|
-
end
|
966
|
-
until networks.size == subnets
|
967
|
-
networks = sum_first_found(networks)
|
971
|
+
|
972
|
+
def newprefix(num)
|
973
|
+
num.upto(32) do |i|
|
974
|
+
if (a = Math::log2(i).to_i) == Math::log2(i)
|
975
|
+
return @prefix + a
|
976
|
+
end
|
968
977
|
end
|
969
|
-
return networks
|
970
978
|
end
|
971
979
|
|
972
980
|
def sum_first_found(arr)
|
973
981
|
dup = arr.dup.reverse
|
974
982
|
dup.each_with_index do |obj,i|
|
975
|
-
a = [
|
983
|
+
a = [self.class.summarize(obj,dup[i+1])].flatten
|
976
984
|
if a.size == 1
|
977
985
|
dup[i..i+1] = a
|
978
986
|
return dup.reverse
|