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