ip_address_simple 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +15 -0
- data/lib/ip_address.rb +118 -0
- data/lib/ip_address_range.rb +5 -0
- data/test/tc_ip_address.rb +42 -0
- data/test/tc_ip_address_range.rb +19 -0
- data/test/ts_all.rb +3 -0
- metadata +53 -0
data/README
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
== IP Address Simple
|
2
|
+
IpAddress is a class that makes common IP address handling a doddle.
|
3
|
+
It provides support for...
|
4
|
+
|
5
|
+
* interchange between string and integer IP representations
|
6
|
+
* masking / sub-netting
|
7
|
+
* IPv4 and IPv6
|
8
|
+
|
9
|
+
== Author
|
10
|
+
Copyright 2007 Andre Ben Hamou
|
11
|
+
mailto:andre@prfsa.com
|
12
|
+
|
13
|
+
== License
|
14
|
+
This library and all associated materials are release under the terms of
|
15
|
+
version 3 of the GNU Public License (http://www.gnu.org/copyleft/gpl.html).
|
data/lib/ip_address.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require "ip_address_range"
|
2
|
+
|
3
|
+
class IpAddress
|
4
|
+
IP_BITS = {4 => 32, 6 => 128}
|
5
|
+
IP_MAX = {4 => (1 << 32) - 1, 6 => (1 << 128) - 1}
|
6
|
+
|
7
|
+
# Takes an Integer or a String representation of an IP address and coerces it to a representation of the requested type (:integer / :string).
|
8
|
+
# If the version (4 / 6) is not specified then it will be guessed with guess_version.
|
9
|
+
def self.coerce(value, to_type, version = nil)
|
10
|
+
raise "unknown type #{to_type.inspect} requested" unless [:integer, :string].include?(to_type)
|
11
|
+
version ||= guess_version(value)
|
12
|
+
|
13
|
+
case value
|
14
|
+
when Integer
|
15
|
+
if to_type == :integer then value
|
16
|
+
elsif version == 4 then [24, 16, 8, 0].map { |shift| (value >> shift) & 255 }.join(".")
|
17
|
+
else sprintf("%.32x", value).scan(/.{4}/).join(":")
|
18
|
+
end
|
19
|
+
when String
|
20
|
+
if to_type == :string then value
|
21
|
+
elsif version == 4 then value.split(".").inject(0) { |total, octet| (total << 8) + octet.to_i }
|
22
|
+
else value.delete(":").to_i(16)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Takes an Integer or a String and guesses whether it represents an IPv4 or IPv6 address.
|
28
|
+
# For an Integer, IPv4 is assumed unless the value is greater than IP_MAX[4].
|
29
|
+
# For a String, IPv6 is assumed if it contains at least one colon (:).
|
30
|
+
def self.guess_version(value)
|
31
|
+
case value
|
32
|
+
when Integer then value > IP_MAX[4] ? 6 : 4
|
33
|
+
when String then value =~ /:/ ? 6 : 4
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Takes an Integer bitcount (bits) and returns an appropriate masking Integer.
|
38
|
+
# For example, a /24 network (in IPv4) corresponds to a mask of 255.255.255.0 or the number 4294967040.
|
39
|
+
# If the version (4 / 6) is not specified then it will be assumed to be 4 unless bits > 32.
|
40
|
+
def self.mask_from_slash_bits(bits, version = nil)
|
41
|
+
raise "bits > 128" if bits > 128
|
42
|
+
version ||= bits > 32 ? 6 : 4
|
43
|
+
|
44
|
+
max = IP_MAX[version]
|
45
|
+
left_shift = IP_BITS[version] - bits
|
46
|
+
(max << left_shift) & max
|
47
|
+
end
|
48
|
+
|
49
|
+
# Takes an Integer or a String representation of a network mask and returns the number of addresses it encodes.
|
50
|
+
# If the version (4 / 6) is not specified then it will be guessed with guess_version.
|
51
|
+
def self.mask_size(value, version = nil)
|
52
|
+
version ||= guess_version(value)
|
53
|
+
(coerce(value, :integer, version) ^ IP_MAX[version]) + 1
|
54
|
+
end
|
55
|
+
|
56
|
+
include Comparable
|
57
|
+
|
58
|
+
attr_reader :integer, :string, :version
|
59
|
+
|
60
|
+
# Takes an Integer or a String representation of an IP address and creates a new IpAddress object with it.
|
61
|
+
# If the version (4 / 6) is not specified then it will be guessed with guess_version.
|
62
|
+
def initialize(value, version = nil)
|
63
|
+
@version = version || IpAddress.guess_version(value)
|
64
|
+
@integer = IpAddress.coerce(value, :integer, @version)
|
65
|
+
@string = IpAddress.coerce(value, :string, @version)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Adds the specified Integer value to that of the IpAddress and returns a new IpAddress based on the sum.
|
69
|
+
def +(value)
|
70
|
+
IpAddress.new(@integer + value, @version)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Subtracts the specified Integer value from that of the IpAddress and returns a new IpAddress based on the difference.
|
74
|
+
def -(value)
|
75
|
+
IpAddress.new(@integer - value, @version)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the range of IpAddresses in the specified /bits network. Basically a convenience wrapper around mask.
|
79
|
+
def /(bits)
|
80
|
+
mask(IpAddress.mask_from_slash_bits(bits, @version))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Compares one IpAddress with another based on the Integer representation of their values.
|
84
|
+
def <=>(other)
|
85
|
+
@integer <=> other.integer
|
86
|
+
end
|
87
|
+
|
88
|
+
# Takes an Integer or a String representation of a network mask and returns the range of IpAddresses in that network.
|
89
|
+
def mask(value)
|
90
|
+
base_int = @integer & IpAddress.coerce(value, :integer, @version)
|
91
|
+
IpAddressRange.new(IpAddress.new(base_int, @version), IpAddress.new(base_int + IpAddress.mask_size(value, @version) - 1))
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the next IpAddress after this one.
|
95
|
+
def succ
|
96
|
+
self + 1
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_i
|
100
|
+
@integer
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_s
|
104
|
+
@string
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Integer
|
109
|
+
def to_ip(version = nil)
|
110
|
+
IpAddress.new(self, version)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class String
|
115
|
+
def to_ip(version = nil)
|
116
|
+
IpAddress.new(self, version)
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ip_address"
|
3
|
+
|
4
|
+
class TestIpAddress < Test::Unit::TestCase # :nodoc:
|
5
|
+
def setup
|
6
|
+
@ip = IpAddress.new("10.0.0.1")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_basics
|
10
|
+
[@ip, IpAddress.new(167772161)].each do |ip|
|
11
|
+
assert_equal(4, ip.version)
|
12
|
+
assert_equal(167772161, ip.integer)
|
13
|
+
assert_equal(167772161, ip.to_i)
|
14
|
+
assert_equal("10.0.0.1", ip.string)
|
15
|
+
assert_equal("10.0.0.1", ip.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
ip = IpAddress.new(182735, 6)
|
19
|
+
assert_equal(6, ip.version)
|
20
|
+
assert_equal(182735, ip.integer)
|
21
|
+
assert_equal("0000:0000:0000:0000:0000:0000:0002:c9cf", ip.string)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_arithmetic
|
25
|
+
other = @ip + 256
|
26
|
+
assert_kind_of(IpAddress, other)
|
27
|
+
assert_equal("10.0.1.1", other.string)
|
28
|
+
other = @ip - 256
|
29
|
+
assert_kind_of(IpAddress, other)
|
30
|
+
assert_equal("9.255.255.1", other.string)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_comparison
|
34
|
+
other = @ip + 20
|
35
|
+
assert(@ip < other)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_conversion
|
39
|
+
assert_equal(@ip, "10.0.0.1".to_ip)
|
40
|
+
assert_equal(@ip, 167772161.to_ip)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ip_address"
|
3
|
+
|
4
|
+
class TestIpAddressRange < Test::Unit::TestCase # :nodoc:
|
5
|
+
def setup
|
6
|
+
@ip = IpAddress.new("10.0.0.1")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_range_masking
|
10
|
+
[@ip.mask("255.255.255.252"), @ip / 30].each do |range|
|
11
|
+
assert_kind_of(IpAddressRange, range)
|
12
|
+
assert_kind_of(IpAddress, range.first)
|
13
|
+
assert_equal("10.0.0.0", range.first.string)
|
14
|
+
assert_kind_of(IpAddress, range.last)
|
15
|
+
assert_equal("10.0.0.3", range.last.string)
|
16
|
+
assert_equal(4, range.size)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/test/ts_all.rb
ADDED
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: ip_address_simple
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2007-10-13 00:00:00 +01:00
|
8
|
+
summary: Simple IP address manipulation library
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: andre@prfsa.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project: ip-addr-simple
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Andre Ben Hamou
|
31
|
+
files:
|
32
|
+
- README
|
33
|
+
- lib/ip_address.rb
|
34
|
+
- lib/ip_address_range.rb
|
35
|
+
- test/tc_ip_address.rb
|
36
|
+
- test/tc_ip_address_range.rb
|
37
|
+
- test/ts_all.rb
|
38
|
+
test_files:
|
39
|
+
- test/tc_ip_address.rb
|
40
|
+
- test/tc_ip_address_range.rb
|
41
|
+
rdoc_options:
|
42
|
+
- --main
|
43
|
+
- README
|
44
|
+
extra_rdoc_files:
|
45
|
+
- README
|
46
|
+
executables: []
|
47
|
+
|
48
|
+
extensions: []
|
49
|
+
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
dependencies: []
|
53
|
+
|