netaddr 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of netaddr might be problematic. Click here for more details.

data/Errors CHANGED
@@ -1,13 +1,7 @@
1
1
  =Error Classes
2
2
 
3
- Exception -
4
- |
5
- --StandardError -
6
- |
7
- --BoundaryError => CIDR or EUI is out of bounds for a valid address
8
- |
9
- --ValidationError => CIDR or EUI is not a valid address
10
- |
11
- --VersionError => CIDR or EUI is of improper version for requested operation
12
- |
13
- |
3
+ +-Exception
4
+ +-StandardError
5
+ +-BoundaryError => CIDR or EUI is out of bounds for a valid address
6
+ +-ValidationError => CIDR or EUI failed validation checks
7
+ +-VersionError => CIDR or EUI is of improper version for requested operation
data/README CHANGED
@@ -1,19 +1,19 @@
1
1
  =Introduction
2
2
 
3
- NetAddr arose through my need as a network engineer for a
4
- back-end module that could easily handle such advanced tasks
5
- as automating the subnetting/supernetting
6
- of IP space, performing calculations on IP CIDR blocks, and other
7
- various items. At that time there were no modules that could
8
- do any of the things that I needed, so I set out to create my own.
9
- Since it proved to be fairly useful to me, I decided to share the
10
- code with the Ruby community.
3
+ NetAddr arose through my need as a network engineer for a
4
+ back-end module that could easily handle such advanced tasks
5
+ as automating the subnetting/supernetting
6
+ of IP space, performing calculations on IP CIDR blocks, and other
7
+ various items. At that time there were no modules that could
8
+ do any of the things that I needed, so I set out to create my own.
9
+ Since it has proven to be fairly useful to me, I have decided to share the
10
+ code with the Ruby community.
11
11
 
12
- I have added things that I find immediately useful for me. I am
13
- open to suggestions if there is something that I could add to make
14
- your life easier. Comments are also welcome (positive ones in particular).
12
+ I have added things that I find immediately useful for me. I am
13
+ open to suggestions if there is something that I could add to make
14
+ your life easier.
15
15
 
16
- Dustin Spinhirne
16
+ Dustin Spinhirne
17
17
 
18
18
 
19
19
  =Example Script
data/lib/cidr.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  =begin rdoc
2
- Copyright (c) 2006 Dustin Spinhirne (www.spinhirne.com)
2
+ Copyleft (c) 2006 Dustin Spinhirne (www.spinhirne.com)
3
3
 
4
4
  Licensed under the same terms as Ruby, No Warranty is provided.
5
5
  =end
@@ -14,10 +14,10 @@ module NetAddr
14
14
  #This class accepts a CIDR address, via the CIDR.create method,
15
15
  #in (x.x.x.x/yy or xxxx::/yy) format for IPv4 and IPv6, or (x.x.x.x/y.y.y.y) for IPv4.
16
16
  #CIDR.create then creates either a CIDRv4 or CIDRv6 object. An optional tag hash may be
17
- #provided with each CIDR as a way of adding custom labels to the object.
17
+ #provided with each CIDR as a way of adding custom labels.
18
18
  #
19
19
  #Upon initialization, the IP version is auto-detected and assigned to the
20
- #object. The original IP/Netmask passed within the CIDR is stored and then
20
+ #CIDR. The original IP/Netmask passed within the CIDR is stored and then
21
21
  #used to determine the confines of the CIDR block. Various properties of the
22
22
  #CIDR block are accessible via several different methods. There are also
23
23
  #methods for modifying the CIDR or creating new derivative CIDR's.
@@ -83,6 +83,10 @@ private_class_method :new
83
83
  # cidr4_2 = NetAddr::CIDR.create(0x0a010001,
84
84
  # :PackedNetmask => 0xffffff00
85
85
  # :Version => 4)
86
+ # cidr4_3 = NetAddr::CIDRv4.new('192.168.1.1',
87
+ # :WildcardMask => ['0.7.0.255', :inversed])
88
+ # cidr4_4 = NetAddr::CIDRv4.new('192.168.5.0',
89
+ # :WildcardMask => ['255.248.255.0'])
86
90
  # cidr6 = NetAddr::CIDR.create('fec0::/64')
87
91
  # cidr6 = NetAddr::CIDR.create('fec0::/64',
88
92
  # :Tag => {'interface' => 'g0/1'})
@@ -94,13 +98,16 @@ private_class_method :new
94
98
  # :PackedNetmask -- Integer representation of an IP Netmask (optional)
95
99
  # :Version -- IP version - Integer (optional)
96
100
  # :Tag -- Custom descriptor tag - Hash, tag => value. (optional)
101
+ # :WildcardMask -- 2 element Array. First element contains a special bit mask used for
102
+ # advanced IP pattern matching. The second element should be :inversed if this
103
+ # bit mask is in inverse format. (optional)
97
104
  #
98
105
  def CIDR.create(addr, options=nil)
99
- known_args = [:PackedNetmask, :Version, :Tag]
106
+ known_args = [:PackedNetmask, :Version, :Tag, :WildcardMask]
100
107
  cidr = nil
101
108
  packed_ip = nil
102
109
  version = nil
103
-
110
+
104
111
  # validate addr arg
105
112
  if (addr.kind_of?(String))
106
113
  cidr = addr
@@ -109,7 +116,7 @@ private_class_method :new
109
116
  else
110
117
  raise ArgumentError, "String or Integer expected for argument 'addr' but #{addr.class} provided."
111
118
  end
112
-
119
+
113
120
  # validate options
114
121
  if (options)
115
122
  raise ArgumentError, "Hash expected for argument 'options' but " +
@@ -123,7 +130,7 @@ private_class_method :new
123
130
  end
124
131
  end
125
132
  end
126
-
133
+
127
134
  # attempt to determine version if not provided
128
135
  if (!version)
129
136
  if (packed_ip)
@@ -132,15 +139,15 @@ private_class_method :new
132
139
  else
133
140
  version = 6
134
141
  end
135
- else
142
+ else
136
143
  if (cidr =~ /\./ && cidr !~ /:/)
137
144
  version = 4
138
145
  elsif (cidr =~ /:/)
139
146
  version = 6
140
147
  end
141
- end
148
+ end
142
149
  end
143
-
150
+
144
151
  # create CIDRvX object
145
152
  if (version == 4)
146
153
  return(NetAddr::CIDRv4.new(addr, options))
@@ -149,7 +156,7 @@ private_class_method :new
149
156
  else
150
157
  raise ArgumentError, "IP version omitted or could not be detected."
151
158
  end
152
-
159
+
153
160
  end
154
161
 
155
162
  #==============================================================================#
@@ -247,6 +254,8 @@ private_class_method :new
247
254
  #* -1 if the current CIDR is contained by (is subnet of) the provided CIDR
248
255
  #* nil if the two CIDR addresses are unrelated
249
256
  #
257
+ # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
258
+ # cidr4_2 = NetAddr::CIDR.create('192.168.1.0/26')
250
259
  # comp1 = cidr4.cmp(cidr4_2)
251
260
  # comp2 = cidr4.cmp('192.168.1.0/26')
252
261
  #
@@ -263,8 +272,8 @@ private_class_method :new
263
272
  rescue Exception => error
264
273
  raise ArgumentError, "Provided argument raised the following " +
265
274
  "errors: #{error}"
266
- end
267
275
  end
276
+ end
268
277
 
269
278
  if (cidr.version != @version)
270
279
  raise VersionError, "Attempted to compare a version #{cidr.version} CIDR " +
@@ -485,7 +494,8 @@ end
485
494
  #Return true if the current CIDR and the provided CIDR are equal
486
495
  #(base address and netmask are equal).
487
496
  #
488
- # cidr4.eql?('192.168.1.1/24')
497
+ # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
498
+ # cidr4.eql?('192.168.1.0/24')
489
499
  #
490
500
  #===Arguments:
491
501
  #* CIDR address or NetAddr::CIDR object
@@ -523,8 +533,8 @@ end
523
533
  #Given a list of subnets of the current CIDR, return a new list with any
524
534
  #holes (missing subnets) filled in.
525
535
  #
536
+ # cidr4 = NetAddr::CIDR.create('192.168.1.0/24')
526
537
  # subnets = cidr4.fill_in(['192.168.1.0/27','192.168.1.64/26','192.168.1.128/25'])
527
- # subnets = cidr4.fill_in(:List => ['192.168.1.0/27','192.168.1.64/26'], :Objectify => true)
528
538
  #
529
539
  #===Arguments:
530
540
  #* Array of CIDR addresses, or Array of NetAddr::CIDR objects
@@ -622,29 +632,6 @@ end
622
632
  end
623
633
  end
624
634
 
625
- #==============================================================================#
626
- # hostmask_ext()
627
- #==============================================================================#
628
-
629
- #===Synopsis
630
- #Provide IPv4 Hostmask in extended format (y.y.y.y).
631
- #
632
- # puts cidr4.hostmask_ext(
633
- #
634
- #===Arguments:
635
- #* none
636
- #
637
- #===Returns:
638
- #* String
639
- #
640
- def hostmask_ext()
641
- if (@version == 4)
642
- return(NetAddr.unpack_ip_addr(@hostmask, :Version => @version))
643
- else
644
- return(nil)
645
- end
646
- end
647
-
648
635
  #==============================================================================#
649
636
  # ip()
650
637
  #==============================================================================#
@@ -754,9 +741,7 @@ end
754
741
  #==============================================================================#
755
742
 
756
743
  #===Synopsis
757
- #Provide last IP address in this CIDR object. The broadcast() method is
758
- #aliased to this method, and thus works for IPv6 despite the fact that the
759
- #IPv6 protocol does not support IP broadcasting
744
+ #Provide last IP address in this CIDR object.
760
745
  #
761
746
  # puts cidr4.last()
762
747
  #
@@ -799,9 +784,47 @@ end
799
784
  end
800
785
 
801
786
  return(ip)
787
+ end
788
+
789
+ #==============================================================================#
790
+ # matches?()
791
+ #==============================================================================#
792
+
793
+ #===Synopsis
794
+ #Given an IP address (or if a CIDR, then the original IP of that CIDR), determine
795
+ #if it falls within the range of addresses resulting from the combination of the
796
+ #IP and Wildcard Mask of this CIDR.
797
+ #
798
+ # cidr4 = NetAddr.CIDRv4.new('10.0.0.0', :WildcardMask => ['0.7.0.255', :inversed])
799
+ # cidr4.matches?('10.0.0.22') -> true
800
+ # cidr4.matches?('10.8.0.1') -> false
801
+ # cidr4.matches?('10.1.0.1') -> true
802
+ # cidr4.matches?('10.0.1.22') -> false
803
+ #
804
+ #===Arguments:
805
+ #* IP address as a String or a CIDR object
806
+ #
807
+ #===Returns:
808
+ #* True or False
809
+ #
810
+ def matches?(ip)
811
+ packed = nil
812
+ if (!ip.kind_of?(NetAddr::CIDR))
813
+ begin
814
+ packed = NetAddr.pack_ip_addr(ip, :Version => @version)
815
+ rescue NetAddr::ValidationError
816
+ raise NetAddr::ValidationError, "Provided IP must be a valid IPv#{@version} address."
817
+ end
818
+ else
819
+ raise NetAddr::ValidationError, "Provided CIDR must be of type #{self.class}" if (ip.class != self.class)
820
+ packed = ip.packed_ip
821
+ end
822
+
823
+ mask = ~@wildcard_mask & @all_f
824
+
825
+ return(true) if (@ip & mask == packed & mask)
826
+ return(false)
802
827
  end
803
-
804
- alias :broadcast :last
805
828
 
806
829
  #==============================================================================#
807
830
  # multicast_mac()
@@ -881,29 +904,6 @@ end
881
904
  return("/#{bits}")
882
905
  end
883
906
 
884
- #==============================================================================#
885
- # netmask_ext()
886
- #==============================================================================#
887
-
888
- #===Synopsis
889
- #Provide IPv4 netmask in extended format (y.y.y.y).
890
- #
891
- # puts cidr4.netmask_ext()
892
- #
893
- #===Arguments:
894
- #* none
895
- #
896
- #===Returns:
897
- #* String
898
- #
899
- def netmask_ext()
900
- if (@version == 4)
901
- return(NetAddr.unpack_ip_addr(@netmask))
902
- else
903
- return(nil)
904
- end
905
- end
906
-
907
907
  #==============================================================================#
908
908
  # network()
909
909
  #==============================================================================#
@@ -1097,7 +1097,7 @@ end
1097
1097
  #
1098
1098
  # cidr4 = NetAddr::CIDR.create('192.168.1.1/24')
1099
1099
  # puts cidr4.nth(1)
1100
- # puts cidr4.nth(:Index => 1, :Objectify => true
1100
+ # puts cidr4.nth(1, :Objectify => true
1101
1101
  #
1102
1102
  #===Arguments:
1103
1103
  #* Index number as an Integer
@@ -1225,6 +1225,25 @@ end
1225
1225
  return(@network)
1226
1226
  end
1227
1227
 
1228
+ #==============================================================================#
1229
+ # packed_wildcard_mask()
1230
+ #==============================================================================#
1231
+
1232
+ #===Synopsis
1233
+ #Provide an Integer representation of the IPv4 Wildcard Mask.
1234
+ #
1235
+ # puts cidr4.packed_wildcard_mask()
1236
+ #
1237
+ #===Arguments:
1238
+ #* none
1239
+ #
1240
+ #===Returns:
1241
+ #* Integer
1242
+ #
1243
+ def packed_wildcard_mask()
1244
+ return(@wildcard_mask)
1245
+ end
1246
+
1228
1247
  #==============================================================================#
1229
1248
  # range()
1230
1249
  #==============================================================================#
@@ -1323,7 +1342,7 @@ end
1323
1342
  #and 192.168.0.128/25 will be returned as the remainders.
1324
1343
  #
1325
1344
  # cidr4.remainder('192.168.1.32/27').each {|x| puts x}
1326
- # cidr4.remainder(:Exclude => '192.168.1.32/27', :Objectify => true).each {|x| puts x.desc}
1345
+ # cidr4.remainder('192.168.1.32/27', :Objectify => true).each {|x| puts x.desc}
1327
1346
  #
1328
1347
  #===Arguments:
1329
1348
  #* CIDR address or NetAddr::CIDR object
@@ -1485,7 +1504,7 @@ end
1485
1504
  #==============================================================================#
1486
1505
 
1487
1506
  #===Synopsis
1488
- #Provide number of IP addresses within this object.
1507
+ #Provide number of IP addresses within this CIDR.
1489
1508
  #
1490
1509
  # puts cidr4.size()
1491
1510
  #
@@ -1504,7 +1523,7 @@ end
1504
1523
  #==============================================================================#
1505
1524
 
1506
1525
  #===Synopsis
1507
- #Subnet this object. There are 2 ways to subnet:
1526
+ #Subnet this CIDR. There are 2 ways to subnet:
1508
1527
  # * By providing the netmask (in bits) of the new subnets in :Bits.
1509
1528
  # * By providing the number of IP addresses needed in the new subnets in :IPCount
1510
1529
  #
@@ -1647,6 +1666,52 @@ end
1647
1666
  end
1648
1667
 
1649
1668
 
1669
+ #==============================================================================#
1670
+ # wildcard_mask()
1671
+ #==============================================================================#
1672
+
1673
+ #===Synopsis
1674
+ #Set or return the wildcard mask. Wildcard masks are typically used for matching
1675
+ #entries in an access-list.
1676
+ #
1677
+ # cidr4.wildcard_mask() -> reads the current wildcard mask
1678
+ # cidr4.wildcard_mask('0.0.0.255', :inversed) -> sets wildcard mask using a reversed mask
1679
+ # cidr4.wildcard_mask('255.255.255.0') -> sets wildcard mask using a standard mask
1680
+ #
1681
+ #===Arguments:
1682
+ #* wildcard mask as a String or Integer
1683
+ #* the label :inversed if the mask is bit-flipped. (optional)
1684
+ #
1685
+ #===Returns:
1686
+ #* nil
1687
+ #
1688
+ def wildcard_mask(mask=nil, inversed=nil)
1689
+ if (mask)
1690
+ if (mask.kind_of?(Integer))
1691
+ packed = mask
1692
+ else
1693
+ packed = nil
1694
+ begin
1695
+ packed = NetAddr.pack_ip_addr(mask, :Version => @version)
1696
+ rescue NetAddr::ValidationError
1697
+ raise NetAddr::ValidationError, "Wildcard Mask must be a valid IPv#{@version} address."
1698
+ end
1699
+ end
1700
+ packed = packed ^ @all_f if (inversed != :inversed)
1701
+ @wildcard_mask = packed
1702
+ ret_val = nil
1703
+ else
1704
+ if (inversed != :inversed)
1705
+ ret_val = NetAddr.unpack_ip_addr(@wildcard_mask ^ @all_f, :Version => @version)
1706
+ else
1707
+ ret_val = NetAddr.unpack_ip_addr(@wildcard_mask, :Version => @version)
1708
+ end
1709
+ end
1710
+
1711
+ return(ret_val)
1712
+ end
1713
+
1714
+
1650
1715
  # PRIVATE INSTANCE METHODS
1651
1716
  private
1652
1717
 
@@ -1700,6 +1765,8 @@ end # end class CIDR
1700
1765
 
1701
1766
 
1702
1767
 
1768
+
1769
+
1703
1770
  # IPv4 CIDR address - Inherits all methods from NetAddr::CIDR.
1704
1771
  # Addresses of this class are composed of a 32-bit address space.
1705
1772
  class CIDRv4 < CIDR
@@ -1720,15 +1787,24 @@ public_class_method :new
1720
1787
  # cidr4 = NetAddr::CIDRv4.new('192.168.1.1 255.255.255.0')
1721
1788
  # cidr4_2 = NetAddr::CIDRv4.new(0x0a010001,
1722
1789
  # :PackedNetmask => 0xffffff00)
1790
+ # cidr4_3 = NetAddr::CIDRv4.new('192.168.1.1',
1791
+ # :WildcardMask => ['0.7.0.255', :inversed])
1792
+ # cidr4_4 = NetAddr::CIDRv4.new('192.168.5.0',
1793
+ # :WildcardMask => ['255.248.255.0'])
1794
+ # cidr4_5 = NetAddr::CIDRv4.new('192.168.1.1',
1795
+ # :WildcardMask => 0x000700ff)
1723
1796
  #
1724
1797
  #===Arguments:
1725
1798
  #* CIDR address as a String, or a packed IP address as an Integer
1726
1799
  #* Optional Hash with the following keys:
1727
1800
  # :PackedNetmask -- Integer representation of an IP Netmask (optional)
1728
1801
  # :Tag -- Custom descriptor tag - Hash, tag => value. (optional)
1802
+ # :WildcardMask -- 2 element Array. First element contains a special bit mask used for
1803
+ # advanced IP pattern matching. The second element should be :inversed if this
1804
+ # bit mask is in inverse format. (optional)
1729
1805
  #
1730
1806
  def initialize(addr, options=nil)
1731
- known_args = [:PackedNetmask, :Tag]
1807
+ known_args = [:PackedNetmask, :Tag, :WildcardMask]
1732
1808
  @tag = {}
1733
1809
  @version = 4
1734
1810
  @max_bits = 32
@@ -1753,17 +1829,43 @@ public_class_method :new
1753
1829
  packed_netmask = options[:PackedNetmask]
1754
1830
  raise ArgumentError, "Expected Integer, but #{packed_netmask.class} " +
1755
1831
  "provided for option :PackedNetmask." if (!packed_netmask.kind_of?(Integer))
1756
- end
1757
-
1832
+ end
1833
+
1758
1834
  if (options.has_key?(:Tag))
1759
1835
  @tag = options[:Tag]
1760
1836
  if (!@tag.kind_of? Hash)
1761
1837
  raise ArgumentError, "Expected Hash, but #{@tag.class} provided for option :Tag."
1762
1838
  end
1763
1839
  end
1840
+
1841
+ if (options.has_key?(:WildcardMask))
1842
+ if (!options[:WildcardMask].kind_of?(Array))
1843
+ raise ArgumentError, "Expected Array, but #{options[:WildcardMask].class} provided for option :WildcardMask."
1844
+ end
1845
+ wildcardmask = options[:WildcardMask][0]
1846
+ inversed = false
1847
+ inversed = true if (options[:WildcardMask][1] && options[:WildcardMask][1] == :inversed)
1848
+
1849
+ if (wildcardmask.kind_of?(Integer))
1850
+ begin
1851
+ @wildcard_mask = wildcardmask
1852
+ NetAddr.validate_ip_addr(@wildcard_mask, :Version => @version)
1853
+ rescue NetAddr::ValidationError
1854
+ raise NetAddr::ValidationError, ":WildcardMask must be a valid IPv#{@version} address."
1855
+ end
1856
+ else
1857
+ begin
1858
+ @wildcard_mask = NetAddr.pack_ip_addr(wildcardmask, :Version => @version)
1859
+ rescue NetAddr::ValidationError
1860
+ raise NetAddr::ValidationError, ":WildcardMask must be a valid IPv#{@version} address."
1861
+ end
1862
+ end
1863
+
1864
+ @wildcard_mask = @wildcard_mask ^ @all_f if (inversed)
1865
+ end
1764
1866
  end
1765
-
1766
-
1867
+
1868
+
1767
1869
  if (packed_ip)
1768
1870
  # validate & store packed_ip
1769
1871
  NetAddr.validate_ip_addr(packed_ip, :Version => @version)
@@ -1806,11 +1908,58 @@ public_class_method :new
1806
1908
  # set @network & @hostmask
1807
1909
  @network = (@ip & @netmask)
1808
1910
  @hostmask = @netmask ^ @all_f
1911
+ @wildcard_mask = @hostmask if (!@wildcard_mask)
1809
1912
 
1810
1913
  end
1811
1914
 
1812
- end
1813
1915
 
1916
+ #==============================================================================#
1917
+ # broadcast()
1918
+ #==============================================================================#
1919
+
1920
+ # Alias for last
1921
+ alias :broadcast :last
1922
+
1923
+ #==============================================================================#
1924
+ # hostmask_ext()
1925
+ #==============================================================================#
1926
+
1927
+ #===Synopsis
1928
+ #Provide IPv4 Hostmask in extended format (y.y.y.y).
1929
+ #
1930
+ # puts cidr4.hostmask_ext(
1931
+ #
1932
+ #===Arguments:
1933
+ #* none
1934
+ #
1935
+ #===Returns:
1936
+ #* String
1937
+ #
1938
+ def hostmask_ext()
1939
+ return(NetAddr.unpack_ip_addr(@hostmask, :Version => @version))
1940
+ end
1941
+
1942
+ #==============================================================================#
1943
+ # netmask_ext()
1944
+ #==============================================================================#
1945
+
1946
+ #===Synopsis
1947
+ #Provide IPv4 netmask in extended format (y.y.y.y).
1948
+ #
1949
+ # puts cidr4.netmask_ext()
1950
+ #
1951
+ #===Arguments:
1952
+ #* none
1953
+ #
1954
+ #===Returns:
1955
+ #* String
1956
+ #
1957
+ def netmask_ext()
1958
+ return(NetAddr.unpack_ip_addr(@netmask))
1959
+ end
1960
+
1961
+ end # end class CIDRv4
1962
+
1814
1963
 
1815
1964
  # IPv6 CIDR address - Inherits all methods from NetAddr::CIDR.
1816
1965
  # Addresses of this class are composed of a 128-bit address space.
@@ -1832,15 +1981,20 @@ public_class_method :new
1832
1981
  # cidr6 = NetAddr::CIDRv6.new('fec0::/64',
1833
1982
  # :Tag => {'interface' => 'g0/1'})
1834
1983
  # cidr6_2 = NetAddr::CIDRv6.new('::ffff:192.168.1.1/96')
1984
+ # cidr6_3 = NetAddr::CIDRv6.new('fec0::',
1985
+ # :WildcardMask => '0000:ffff::ffff')
1835
1986
  #
1836
1987
  #===Arguments:
1837
1988
  #* CIDR address as a String, or a packed IP address as an Integer
1838
1989
  #* Optional Hash with the following keys:
1839
1990
  # :PackedNetmask -- Integer representation of an IP Netmask (optional)
1840
1991
  # :Tag -- Custom descriptor tag - Hash, tag => value. (optional)
1992
+ # :WildcardMask -- 2 element Array. First element contains a special bit mask used for
1993
+ # advanced IP pattern matching. The second element should be :inversed if this
1994
+ # bit mask is in inverse format. (optional)
1841
1995
  #
1842
1996
  def initialize(addr, options=nil)
1843
- known_args = [:PackedNetmask, :Tag]
1997
+ known_args = [:PackedNetmask, :Tag, :WildcardMask]
1844
1998
  @tag = {}
1845
1999
  @version = 6
1846
2000
  @max_bits = 128
@@ -1873,18 +2027,44 @@ public_class_method :new
1873
2027
  raise ArgumentError, "Expected Hash, but #{@tag.class} provided for option :Tag."
1874
2028
  end
1875
2029
  end
2030
+
2031
+ if (options.has_key?(:WildcardMask))
2032
+ if (!options[:WildcardMask].kind_of?(Array))
2033
+ raise ArgumentError, "Expected Array, but #{options[:WildcardMask].class} provided for option :WildcardMask."
2034
+ end
2035
+ wildcardmask = options[:WildcardMask][0]
2036
+ inversed = false
2037
+ inversed = true if (options[:WildcardMask][1] && options[:WildcardMask][1] == :inversed)
2038
+
2039
+ if (wildcardmask.kind_of?(Integer))
2040
+ begin
2041
+ @wildcard_mask = wildcardmask
2042
+ NetAddr.validate_ip_addr(@wildcard_mask, :Version => @version)
2043
+ rescue NetAddr::ValidationError
2044
+ raise NetAddr::ValidationError, ":WildcardMask must be a valid IPv#{@version} address."
2045
+ end
2046
+ else
2047
+ begin
2048
+ @wildcard_mask = NetAddr.pack_ip_addr(wildcardmask, :Version => @version)
2049
+ rescue NetAddr::ValidationError
2050
+ raise NetAddr::ValidationError, ":WildcardMask must be a valid IPv#{@version} address."
2051
+ end
2052
+ end
2053
+
2054
+ @wildcard_mask = @wildcard_mask ^ @all_f if (inversed)
2055
+ end
1876
2056
  end
1877
-
1878
-
1879
- if (packed_ip)
2057
+
2058
+
2059
+ if (packed_ip)
1880
2060
  # validate & store packed_ip
1881
2061
  NetAddr.validate_ip_addr(packed_ip, :Version => @version)
1882
2062
  @ip = packed_ip
1883
-
1884
- else
2063
+
2064
+ else
1885
2065
  # if ipv6 and extended netmask was provided, then raise exception
1886
- raise ArgumentError, "Garbage provided at end of IPv6 address." if (cidr =~ /.+\s+.+/ )
1887
-
2066
+ raise ArgumentError, "Garbage provided at end of IPv6 address." if (cidr =~ /.+\s+.+/ )
2067
+
1888
2068
  # get ip and netmask
1889
2069
  if (cidr =~ /\//)
1890
2070
  ip,netmask = cidr.split(/\//)
@@ -1894,16 +2074,16 @@ public_class_method :new
1894
2074
  else
1895
2075
  ip = cidr
1896
2076
  end
1897
-
1898
- # pack ip
1899
- @ip = NetAddr.pack_ip_addr(ip, :Version => @version)
2077
+
2078
+ # pack ip
2079
+ @ip = NetAddr.pack_ip_addr(ip, :Version => @version)
1900
2080
  end
1901
2081
 
1902
2082
  # if no netmask or packed_netmask, then set
1903
2083
  # else validate. packed_netmask takes precedence over netmask
1904
2084
  if (!netmask && !packed_netmask)
1905
2085
  @netmask = @all_f
1906
- else
2086
+ else
1907
2087
  if (packed_netmask)
1908
2088
  NetAddr.validate_ip_netmask(packed_netmask, :Packed => true, :Version => @version)
1909
2089
  @netmask = packed_netmask
@@ -1912,14 +2092,15 @@ public_class_method :new
1912
2092
  @netmask = NetAddr.pack_ip_netmask(netmask, :Version => @version)
1913
2093
  end
1914
2094
  end
1915
-
2095
+
1916
2096
  # set @network & @hostmask
1917
2097
  @network = (@ip & @netmask)
1918
2098
  @hostmask = @netmask ^ @all_f
2099
+ @wildcard_mask = @hostmask if (!@wildcard_mask)
1919
2100
 
1920
2101
  end
1921
2102
 
1922
- end
2103
+ end # end class CIDRv6
1923
2104
 
1924
2105
  end # module NetAddr
1925
2106
  __END__
data/lib/eui.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  =begin rdoc
2
- Copyright (c) 2006 Dustin Spinhirne (www.spinhirne.com)
2
+ Copyleft (c) 2006 Dustin Spinhirne (www.spinhirne.com)
3
3
 
4
4
  Licensed under the same terms as Ruby, No Warranty is provided.
5
5
  =end
data/lib/methods.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  =begin rdoc
2
- Copyright (c) 2006 Dustin Spinhirne (www.spinhirne.com)
2
+ Copyleft (c) 2006 Dustin Spinhirne (www.spinhirne.com)
3
3
 
4
4
  Licensed under the same terms as Ruby, No Warranty is provided.
5
5
  =end
@@ -14,11 +14,11 @@ module NetAddr
14
14
  #Given a list of CIDR addresses or NetAddr::CIDR objects of the same version,
15
15
  #merge (summarize) them in the most efficient way possible. Summarization
16
16
  #will only occur when the newly created supernets will not result in the
17
- #'creation' of additional space. For example the following blocks
17
+ #'creation' of new IP space. For example the following blocks
18
18
  #(192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would be summarized into
19
19
  #192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22
20
20
  #
21
- #I have designed this with enough flexibility that you can pass in CIDR
21
+ #I have designed this with enough flexibility so that you can pass in CIDR
22
22
  #addresses that arent even related (ex. 192.168.1.0/26, 192.168.1.64/27, 192.168.1.96/27
23
23
  #10.1.0.0/26, 10.1.0.64/26) and they will be merged properly (ie 192.168.1.0/25,
24
24
  #and 10.1.0.0/25 would be returned).
@@ -52,13 +52,13 @@ def merge(list,options=nil)
52
52
  raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
53
53
  NetAddr.validate_args(options.keys,known_args)
54
54
 
55
- if (options.has_key?(:Short) && options[:Short] == true)
56
- short = true
57
- end
58
-
59
55
  if (options.has_key?(:Objectify) && options[:Objectify] == true)
60
56
  objectify = true
61
- end
57
+ end
58
+
59
+ if (options.has_key?(:Short) && options[:Short] == true)
60
+ short = true
61
+ end
62
62
  end
63
63
 
64
64
  # make sure all are valid types of the same IP version
@@ -181,7 +181,7 @@ module_function :merge
181
181
 
182
182
  #===Synopsis
183
183
  #Given the number of IP addresses required in a subnet, return the minimum
184
- #netmask (in bits) required for that subnet. IP version is assumed to be 4 unless specified otherwise.
184
+ #netmask (bits by default) required for that subnet. IP version is assumed to be 4 unless specified otherwise.
185
185
  #
186
186
  # Example:
187
187
  # netmask = NetAddr.minumum_size(14)
@@ -190,14 +190,16 @@ module_function :merge
190
190
  #===Arguments:
191
191
  #* IP count as an Integer
192
192
  #* Optional Hash with the following keys:
193
+ # :Extended -- If true, then return the netmask in extended format (y.y.y.y) for IPv4
193
194
  # :Version -- IP version - Integer(optional)
194
195
  #
195
196
  #===Returns:
196
- #* Integer
197
+ #* Integer or String
197
198
  #
198
199
  def minimum_size(ipcount, options=nil)
199
200
  version = 4
200
- known_args = [:Version]
201
+ extended = false
202
+ known_args = [:Version, :Extended]
201
203
 
202
204
  # validate ipcount
203
205
  raise ArgumentError, "Integer expected for argument 'ipcount' but #{ipcount.class} provided." if (!ipcount.kind_of?(Integer))
@@ -211,10 +213,14 @@ def minimum_size(ipcount, options=nil)
211
213
  if (options.has_key?(:Version))
212
214
  version = options[:Version]
213
215
  end
216
+
217
+ if (options.has_key?(:Extended) && options[:Extended] == true)
218
+ extended = true
219
+ end
214
220
  end
215
221
 
216
222
  if (version == 4)
217
- max_bits = 32
223
+ max_bits = 32
218
224
  else
219
225
  max_bits = 128
220
226
  end
@@ -232,6 +238,7 @@ def minimum_size(ipcount, options=nil)
232
238
  end
233
239
  subnet_bits = max_bits - bits_needed
234
240
 
241
+ return(NetAddr.unpack_ip_addr(NetAddr.pack_ip_netmask(subnet_bits))) if (extended && version == 4)
235
242
  return(subnet_bits)
236
243
  end
237
244
  module_function :minimum_size
@@ -440,8 +447,8 @@ module_function :pack_ip_netmask
440
447
  #Given two CIDR addresses or NetAddr::CIDR objects of the same version,
441
448
  #return all IP addresses between them. NetAddr.range will use the original IP
442
449
  #address passed during the initialization of the NetAddr::CIDR objects, or the
443
- #base address of any CIDR addresses passed. The default behavior is to be
444
- #non-inclusive (dont include boundaries as part of returned data)
450
+ #ip address of any CIDR addresses passed. The default behavior is to be
451
+ #non-inclusive (don't include boundaries as part of returned data)
445
452
  #
446
453
  # Example:
447
454
  # list = NetAddr.range(cidr1,cidr2, :Limit => 10)
@@ -503,7 +510,7 @@ def range(cidr1, cidr2, options=nil)
503
510
  end
504
511
 
505
512
  if( options.has_key?(:Short) && options[:Short] == true )
506
- short = true
513
+ short = true
507
514
  end
508
515
 
509
516
  if( options.has_key?(:Inclusive) && options[:Inclusive] == true )
@@ -652,7 +659,7 @@ module_function :shorten
652
659
  #===Synopsis
653
660
  #Given a list of CIDR addresses or NetAddr::CIDR objects,
654
661
  #sort them from lowest to highest by Network/Netmask. NetAddr.sort will use the
655
- #original IP address passed during the initialization of any NetAddr::CIDR
662
+ #base address passed during the initialization of any NetAddr::CIDR
656
663
  #objects, or the base address of any CIDR addresses passed
657
664
  #
658
665
  # Example:
@@ -1233,6 +1240,87 @@ def validate_ip_netmask(netmask, options=nil)
1233
1240
  end
1234
1241
  module_function :validate_ip_netmask
1235
1242
 
1243
+ #==============================================================================#
1244
+ # wildcard()
1245
+ #==============================================================================#
1246
+
1247
+ #===Synopsis
1248
+ #Convert a wildcard IP into a valid CIDR address. Wildcards must always be at
1249
+ #the end of the address. Any data located after the first wildcard will be lost.
1250
+ #Shorthand notation is prohibited for IPv6 addresses.
1251
+ #IPv6 encoded IPv4 addresses are not currently supported.
1252
+ #
1253
+ # Examples:
1254
+ # NetAddr.wildcard('192.168.*')
1255
+ # NetAddr.wildcard('192.168.1.*')
1256
+ # NetAddr.wildcard('fec0:*')
1257
+ # NetAddr.wildcard('fec0:1:*')
1258
+ #
1259
+ #===Arguments:
1260
+ #* Wildcard IP address as a String
1261
+ #
1262
+ #===Returns:
1263
+ #* CIDR object
1264
+ #
1265
+ def wildcard(ip)
1266
+ version = 4
1267
+
1268
+ # do operations per version of address
1269
+ if (ip =~ /\./ && ip !~ /:/)
1270
+ octets = []
1271
+ mask = 0
1272
+
1273
+ ip.split('.').each do |x|
1274
+ if (x =~ /\*/)
1275
+ break
1276
+ end
1277
+ octets.push(x)
1278
+ end
1279
+
1280
+ octets.length.times do
1281
+ mask = mask << 8
1282
+ mask = mask | 0xff
1283
+ end
1284
+
1285
+ until (octets.length == 4)
1286
+ octets.push('0')
1287
+ mask = mask << 8
1288
+ end
1289
+ ip = octets.join('.')
1290
+
1291
+ elsif (ip =~ /:/)
1292
+ version = 6
1293
+ fields = []
1294
+ mask = 0
1295
+
1296
+ raise ArgumentError, "IPv6 encoded IPv4 addresses are unsupported." if (ip =~ /\./)
1297
+ raise ArgumentError, "Shorthand IPv6 addresses are unsupported." if (ip =~ /::/)
1298
+
1299
+ ip.split(':').each do |x|
1300
+ if (x =~ /\*/)
1301
+ break
1302
+ end
1303
+ fields.push(x)
1304
+ end
1305
+
1306
+ fields.length.times do
1307
+ mask = mask << 16
1308
+ mask = mask | 0xffff
1309
+ end
1310
+
1311
+ until (fields.length == 8)
1312
+ fields.push('0')
1313
+ mask = mask << 16
1314
+ end
1315
+ ip = fields.join(':')
1316
+ end
1317
+
1318
+ # make & return cidr
1319
+ cidr = NetAddr::CIDR.create(ip, :PackedNetmask => mask, :Version => version)
1320
+ return(cidr)
1321
+ end
1322
+ module_function :wildcard
1323
+
1236
1324
  #==============================================================================#
1237
1325
  # NetStruct
1238
1326
  #==============================================================================#
@@ -1246,7 +1334,7 @@ module_function :validate_ip_netmask
1246
1334
  # * parent - parent NetStruct in tree
1247
1335
  # * children - Array of children NetStruct objects
1248
1336
  #
1249
- NetStruct = Struct.new(:cidr, :parent, :children)
1337
+ NetStruct = Struct.new(:cidr, :parent, :children) #:nodoc:
1250
1338
 
1251
1339
 
1252
1340
  # PRIVATE METHODS
data/lib/net_addr.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  =begin rdoc
2
- Copyright (c) 2006 Dustin Spinhirne (www.spinhirne.com)
2
+ Copyleft (c) 2006 Dustin Spinhirne (www.spinhirne.com)
3
3
 
4
4
  Licensed under the same terms as Ruby, No Warranty is provided.
5
5
  =end
data/lib/tree.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  =begin rdoc
2
- Copyright (c) 2006 Dustin Spinhirne (www.spinhirne.com)
2
+ Copyleft (c) 2006 Dustin Spinhirne (www.spinhirne.com)
3
3
 
4
4
  Licensed under the same terms as Ruby, No Warranty is provided.
5
5
  =end
@@ -695,7 +695,7 @@ class Tree
695
695
  #==============================================================================#
696
696
 
697
697
  #===Synopsis
698
- # Print the tree in a nicely formatted string.
698
+ # Print the tree as a nicely formatted string.
699
699
  #
700
700
  # puts tree.show()
701
701
  #
data/tests/cidr_test.rb CHANGED
@@ -19,6 +19,10 @@ class TestCIDR < Test::Unit::TestCase
19
19
  assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1/64')}
20
20
  assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1/64')}
21
21
  assert_nothing_raised(Exception){NetAddr::CIDR.create(0x0a0a0a0a, :PackedNetmask => 0xffffffff)}
22
+ assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1', :WildcardMask => ['0.0.7.255', :inversed]) }
23
+ assert_nothing_raised(Exception){NetAddr::CIDR.create('192.168.1.1', :WildcardMask => [0x000007ff, :inversed]) }
24
+ assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1', :WildcardMask => ['0000:ffff::ffff', :inversed])}
25
+ assert_nothing_raised(Exception){NetAddr::CIDR.create('fec0::1', :WildcardMask => [0xffff, :inversed])}
22
26
 
23
27
  assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('192.168.1.1 255.255.0.0'))
24
28
  assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('192.168.1.1/24 255.255.0.0'))
@@ -27,6 +31,8 @@ class TestCIDR < Test::Unit::TestCase
27
31
  assert_kind_of(NetAddr::CIDRv4, NetAddr::CIDR.create('10.10.10.10/32', :PackedNetmask => 0xffffff00))
28
32
 
29
33
  assert_raise(ArgumentError){ NetAddr::CIDR.create(:Version => 4) }
34
+ assert_raise(NetAddr::ValidationError){ NetAddr::CIDR.create('192.168.1.1', :WildcardMask => ['0000:ffff::ffff', :inversed]) }
35
+ assert_raise(NetAddr::ValidationError){ NetAddr::CIDR.create('fec0::1', :WildcardMask => ['0.0.7.255', :inversed]) }
30
36
  end
31
37
 
32
38
  def test_new
@@ -67,6 +73,26 @@ class TestCIDR < Test::Unit::TestCase
67
73
  assert_raise(NetAddr::ValidationError){ NetAddr::CIDRv4.new('192.168.1.0 a') }
68
74
  end
69
75
 
76
+ def test_matches?
77
+ cidr = NetAddr::CIDR.create('10.0.0.0/24')
78
+ assert(cidr.matches?('10.0.0.22'))
79
+ assert(!cidr.matches?('10.1.1.1'))
80
+
81
+ cidr = NetAddr::CIDR.create('10.0.248.0')
82
+ cidr.wildcard_mask('255.248.255.0')
83
+ assert(cidr.matches?('10.1.248.0'))
84
+ assert(!cidr.matches?('10.8.248.0'))
85
+
86
+ cidr = NetAddr::CIDR.create('10.0.248.0')
87
+ cidr.wildcard_mask('0.7.0.255', :inversed)
88
+ assert(cidr.matches?('10.1.248.0'))
89
+ assert(!cidr.matches?('10.8.248.0'))
90
+
91
+ cidr = NetAddr::CIDR.create('fec0::1')
92
+ cidr.wildcard_mask('0000:ffff::ffff', :inversed)
93
+ assert(cidr.matches?('fec0:1::1'))
94
+ assert(!cidr.matches?('fec0:0:1::1'))
95
+ end
70
96
 
71
97
  def test_cmp
72
98
 
@@ -396,6 +422,29 @@ class TestCIDR < Test::Unit::TestCase
396
422
  subnet4 = cidr4.subnet(:IPCount => 31)
397
423
  assert_equal('192.168.1.0/27', subnet4[0])
398
424
  end
425
+
426
+ def test_wildcard_mask
427
+ cidr = NetAddr::CIDR.create('10.1.0.0/24')
428
+ assert_equal('0.0.0.255', cidr.wildcard_mask(nil,:inversed))
429
+ assert_equal('255.255.255.0', cidr.wildcard_mask)
430
+
431
+ cidr.wildcard_mask('0.7.0.255', :inversed)
432
+ assert_equal('0.7.0.255', cidr.wildcard_mask(nil,:inversed))
433
+ assert_equal('255.248.255.0', cidr.wildcard_mask())
434
+ cidr.wildcard_mask('255.248.255.0')
435
+ assert_equal('0.7.0.255', cidr.wildcard_mask(nil,:inversed))
436
+ assert_equal('255.248.255.0', cidr.wildcard_mask())
437
+ cidr.wildcard_mask('0.0.0.0')
438
+ assert_equal('0.0.0.0', cidr.wildcard_mask)
439
+ assert_raise(NetAddr::ValidationError){ cidr.wildcard_mask('0000:ffff::ffff') }
440
+
441
+ cidr = NetAddr::CIDR.create('fec0::1/64')
442
+ assert_equal('0000:0000:0000:0000:ffff:ffff:ffff:ffff', cidr.wildcard_mask(nil,:inversed))
443
+ cidr.wildcard_mask('0000:ffff::ffff', :inversed)
444
+ assert_equal('0000:ffff:0000:0000:0000:0000:0000:ffff', cidr.wildcard_mask(nil,:inversed))
445
+ assert_raise(NetAddr::ValidationError){ cidr.wildcard_mask('0.7.0.255', :inversed) }
446
+
447
+ end
399
448
 
400
449
 
401
450
  end
@@ -65,6 +65,10 @@ class TestMethods < Test::Unit::TestCase
65
65
  assert_raise(ArgumentError) {NetAddr.minimum_size(200, :test => true)}
66
66
  assert_equal(24, NetAddr.minimum_size(200))
67
67
  assert_equal(96, NetAddr.minimum_size(2**32-1, :Version => 6))
68
+ assert_equal('255.255.255.0', NetAddr.minimum_size(200, :Extended => true))
69
+ assert_equal('255.255.255.224', NetAddr.minimum_size(17, :Extended => true))
70
+ assert_equal(24, NetAddr.minimum_size(200, :Extended => false))
71
+ assert_equal(96, NetAddr.minimum_size(2**32-1, :Version => 6, :Extended => true))
68
72
 
69
73
  assert_raise(ArgumentError){ NetAddr.minimum_size({}) }
70
74
  end
@@ -296,6 +300,29 @@ class TestMethods < Test::Unit::TestCase
296
300
  end
297
301
 
298
302
 
303
+ def test_wildcard
304
+ cidr = NetAddr.wildcard('192.168.*')
305
+ assert_equal(NetAddr::CIDRv4, cidr.class )
306
+ assert_equal(16, cidr.bits)
307
+ assert_equal('192.168.0.0', cidr.network)
308
+
309
+ cidr = NetAddr.wildcard('192.*.1.0')
310
+ assert_equal(8, cidr.bits)
311
+ assert_equal('192.0.0.0', cidr.network)
312
+
313
+ cidr = NetAddr.wildcard('fec0:*')
314
+ assert_equal(NetAddr::CIDRv6, cidr.class )
315
+ assert_equal(16, cidr.bits)
316
+ assert_equal('fec0:0000:0000:0000:0000:0000:0000:0000', cidr.network)
317
+
318
+ cidr = NetAddr.wildcard('fec0:1:*')
319
+ assert_equal(32, cidr.bits)
320
+ assert_equal('fec0:0001:0000:0000:0000:0000:0000:0000', cidr.network)
321
+
322
+ assert_raise(ArgumentError){NetAddr.wildcard('fec0::*')}
323
+ assert_raise(ArgumentError){NetAddr.wildcard('::ffff:192.168.*')}
324
+ end
325
+
299
326
  end
300
327
 
301
328
 
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: netaddr
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.0
7
- date: 2006-08-17 00:00:00 -05:00
6
+ version: 1.1.0
7
+ date: 2007-01-05 00:00:00 -06:00
8
8
  summary: A package for manipulating network addresses.
9
9
  require_paths:
10
10
  - lib
@@ -25,20 +25,21 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
25
25
  platform: ruby
26
26
  signing_key:
27
27
  cert_chain:
28
+ post_install_message:
28
29
  authors:
29
30
  - Dustin Spinhirne
30
31
  files:
32
+ - lib/methods.rb
31
33
  - lib/cidr.rb
32
34
  - lib/eui.rb
33
- - lib/methods.rb
34
- - lib/tree.rb
35
35
  - lib/net_addr.rb
36
+ - lib/tree.rb
36
37
  - README
37
38
  - Errors
38
39
  test_files:
39
40
  - tests/cidr_test.rb
40
- - tests/eui_test.rb
41
41
  - tests/methods_test.rb
42
+ - tests/eui_test.rb
42
43
  - tests/tree_test.rb
43
44
  rdoc_options: []
44
45