ipaddress 0.7.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -14,44 +14,22 @@ examples of typical usage.
14
14
 
15
15
  == Requirements
16
16
 
17
- * Ruby >= 1.8.6 (not tested with previous versions)
17
+ * Ruby >= 1.8.7 (not tested with previous versions)
18
+ * Ruby 1.9.2 or later is strongly recommended
18
19
 
19
- IPAddress works perfectly on:
20
+ IPAddress 0.8.0 has been tested on:
20
21
 
21
- * Ruby 1.8.6 (2007-03-13 patchlevel 0)
22
- * Ruby 1.8.7
23
- * Ruby 1.9.1
24
- * Ruby 1.9.2dev (2010-06-08 revision 28230)
25
- * Ruby 1.9.2dev (2010-07-15 revision 28653)
26
- * Rubinius 1.0.1 (1.8.7 release 2010-06-03 JI)
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
- It hasn't yet been tested on any other platform, so if you want to collaborate feel
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.7.0/frames]
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 will have prefix /32, which is the same
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
- The IPv4#network method creates a new IPv4 object from the network
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. Let's work out the last example:
386
+ Subnetting is easy with IPAddress. You actually have two options:
406
387
 
407
- network = IPAddress("172.16.10.0/24")
388
+ * IPv4#subnet: specify a new prefix
389
+ * IPv4#split: tell IPAddress how many subnets you want to create.
408
390
 
409
- subnets = network / 4
410
- #=> [#<IPAddress::IPv4:0xb7b10e10 @octets=[172,16,10,0] [...]
411
- #<IPAddress::IPv4:0xb7b0f1b4 @octets=[172,16,10,64] [...]
412
- #<IPAddress::IPv4:0xb7b0e5ac @octets=[172,16,10,128] [...]
413
- #<IPAddress::IPv4:0xb7b0e0c0 @octets=[172,16,10,192] [...]]
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", "172.16.10.64/26", "172.16.10.128/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
- You can also use method IPv4#subnets, which is an alias for
420
- IPv4#/. Please note that you don't have to specify a network to
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
- ip = IPAddress("172.16.10.58/24")
426
-
427
- ip.subnet(4).map{|i| i.to_string}
428
- #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26",
429
- "172.16.10.192/26"]
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
- Usually, subnetting implies dividing a network to a number of subnets
432
- which is a power of two: in this way, you can be sure that the network
433
- will be divided evenly, and all the subnets will have the same number
434
- of hosts.
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
- ==== Uneven subnetting
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
- IPAddress also handles un-even subnetting: if you specify any number
439
- (up to the prefix limit), the network will be divided so that the
440
- first power-of-two networks will be even, and all the rest will just
441
- fill out the space.
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
- As an example, let's divide network 172.16.10.0/24 into 3 different subnets:
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
- network.subnet(3).map{|i| i.to_string}
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
- We can go even further and divide into 11 subnets:
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
- network = IPAddress("172.16.10.0/24")
455
+ We can go even further and split into 11 subnets:
455
456
 
456
- network.subnet(11).map{|i| i.to_string}
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
- 1080:0000:0000:0000:0008:0800:200c:417a
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
- 1080::8:800:200c:417a
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
- 1080::8:800:200c:417a/64
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 "1080:0000:0000:0000:0008:0800:200C:417A"
616
+ ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200C:417A"
616
617
 
617
- ip6 = IPAddress "1080:0:0:0:8:800:200C:417A"
618
+ ip6 = IPAddress "2001:db8:0:0:8:800:200C:417A"
618
619
 
619
- ip6 = IPAddress "1080::8:800:200C:417A"
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 = 21932261930451111902915077091070067066
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
- #=> "1080::8:800:200c:417a/64"
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, Erik Ahlström and
928
- Steve Rawlinson for their support, feedback and bug reports.
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.7.5
1
+ 0.8.0
@@ -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
+
@@ -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
 
@@ -426,14 +426,22 @@ module IPAddress;
426
426
  end
427
427
 
428
428
  #
429
- # Spaceship operator to compare IP addresses
429
+ # Spaceship operator to compare IPv4 objects
430
430
  #
431
- # An IP address is considered to be minor if it
432
- # has a greater prefix (thus smaller hosts
433
- # portion) and a smaller u32 value.
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
- # For example, "10.100.100.1/8" is smaller than
436
- # "172.16.0.1/16", but it's bigger than "10.100.100.1/16".
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 < ip3
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 > oth.to_u32
451
- return 1
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
- # Subnetting a network
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, the
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 IPAddress objects
616
+ # Returns an array of IPv4 objects
640
617
  #
641
- def subnet(subnets=2)
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
- calculate_subnets(subnets)
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 :/, :subnet
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(@address+"/#{new_prefix}").network
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 calculate_subnets(subnets)
959
- po2 = subnets.closest_power_of_2
960
- new_prefix = @prefix + Math::log2(po2).to_i
961
- networks = Array.new
962
- (0..po2-1).each do |i|
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 = [IPAddress::IPv4.summarize(obj,dup[i+1])].flatten
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