ipaddress_link_local 0.8.3

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.
@@ -0,0 +1,75 @@
1
+ module IPAddress
2
+
3
+ #
4
+ # Mongoid field serialization
5
+ #
6
+ # IPAddress objects are converted to String
7
+ #
8
+ # IPAddress.mongoize IPAddress.parse("172.16.10.1")
9
+ # #=> "172.16.10.1"
10
+ #
11
+ # Prefix will be removed from host adresses
12
+ #
13
+ # IPAddress.mongoize "172.16.10.1/32"
14
+ # #=> "172.16.10.1"
15
+ #
16
+ # Prefix will be kept for network addresses
17
+ #
18
+ # IPAddress.mongoize "172.16.10.1/24"
19
+ # #=> "172.16.10.1/24"
20
+ #
21
+ # IPv6 addresses will be stored uncompressed to ease DB search and sorting
22
+ #
23
+ # IPAddress.mongoize "2001:db8::8:800:200c:417a"
24
+ # #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
25
+ # IPAddress.mongoize "2001:db8::8:800:200c:417a/64"
26
+ # #=> "2001:0db8:0000:0000:0008:0800:200c:417a/64"
27
+ #
28
+ # Invalid addresses will be serialized as nil
29
+ #
30
+ # IPAddress.mongoize "invalid"
31
+ # #=> nil
32
+ # IPAddress.mongoize ""
33
+ # #=> nil
34
+ # IPAddress.mongoize 1
35
+ # #=> nil
36
+ # IPAddress.mongoize nil
37
+ # #=> nil
38
+ #
39
+ def self.mongoize(ipaddress)
40
+ ipaddress = self.parse(ipaddress) unless ipaddress.is_a?(IPAddress)
41
+ if ipaddress.bits.length == ipaddress.prefix
42
+ ipaddress.address
43
+ elsif ipaddress.is_a?(IPAddress::IPv6)
44
+ ipaddress.to_string_uncompressed
45
+ else
46
+ ipaddress.to_string
47
+ end
48
+ rescue ArgumentError
49
+ nil
50
+ end
51
+
52
+ #
53
+ # Mongoid field deserialization
54
+ #
55
+ def self.demongoize(string)
56
+ parse(string)
57
+ rescue ArgumentError
58
+ nil
59
+ end
60
+
61
+ #
62
+ # Delegates to IPAddress.mongoize
63
+ #
64
+ def self.evolve(ipaddress)
65
+ mongoize(ipaddress)
66
+ end
67
+
68
+ #
69
+ # Sends self object to IPAddress#mongoize
70
+ #
71
+ def mongoize
72
+ IPAddress.mongoize(self)
73
+ end
74
+
75
+ end
@@ -0,0 +1,265 @@
1
+ module IPAddress
2
+
3
+ #
4
+ # =NAME
5
+ #
6
+ # IPAddress::Prefix
7
+ #
8
+ # =SYNOPSIS
9
+ #
10
+ # Parent class for Prefix32 and Prefix128
11
+ #
12
+ # =DESCRIPTION
13
+ #
14
+ # IPAddress::Prefix is the parent class for IPAddress::Prefix32
15
+ # and IPAddress::Prefix128, defining some modules in common for
16
+ # both the subclasses.
17
+ #
18
+ # IPAddress::Prefix shouldn't be accesses directly, unless
19
+ # for particular needs.
20
+ #
21
+ class Prefix
22
+
23
+ include Comparable
24
+
25
+ attr_reader :prefix
26
+
27
+ #
28
+ # Creates a new general prefix
29
+ #
30
+ def initialize(num)
31
+ @prefix = num.to_i
32
+ end
33
+
34
+ #
35
+ # Returns a string with the prefix
36
+ #
37
+ def to_s
38
+ "#@prefix"
39
+ end
40
+ alias_method :inspect, :to_s
41
+
42
+ #
43
+ # Returns the prefix
44
+ #
45
+ def to_i
46
+ @prefix
47
+ end
48
+
49
+ #
50
+ # Compare the prefix
51
+ #
52
+ def <=>(oth)
53
+ @prefix <=> oth.to_i
54
+ end
55
+
56
+ #
57
+ # Sums two prefixes or a prefix to a
58
+ # number, returns a Fixnum
59
+ #
60
+ def +(oth)
61
+ if oth.is_a? Fixnum
62
+ self.prefix + oth
63
+ else
64
+ self.prefix + oth.prefix
65
+ end
66
+ end
67
+
68
+ #
69
+ # Returns the difference between two
70
+ # prefixes, or a prefix and a number,
71
+ # as a Fixnum
72
+ #
73
+ def -(oth)
74
+ if oth.is_a? Fixnum
75
+ self.prefix - oth
76
+ else
77
+ (self.prefix - oth.prefix).abs
78
+ end
79
+ end
80
+
81
+ end # class Prefix
82
+
83
+
84
+ class Prefix32 < Prefix
85
+
86
+ IN4MASK = 0xffffffff
87
+
88
+ #
89
+ # Creates a new prefix object for 32 bits IPv4 addresses
90
+ #
91
+ # prefix = IPAddress::Prefix32.new 24
92
+ # #=> 24
93
+ #
94
+ def initialize(num)
95
+ unless (0..32).include? num
96
+ raise ArgumentError, "Prefix must be in range 0..32, got: #{num}"
97
+ end
98
+ super(num)
99
+ end
100
+
101
+ #
102
+ # Returns the length of the host portion
103
+ # of a netmask.
104
+ #
105
+ # prefix = Prefix32.new 24
106
+ #
107
+ # prefix.host_prefix
108
+ # #=> 8
109
+ #
110
+ def host_prefix
111
+ 32 - @prefix
112
+ end
113
+
114
+ #
115
+ # Transforms the prefix into a string of bits
116
+ # representing the netmask
117
+ #
118
+ # prefix = IPAddress::Prefix32.new 24
119
+ #
120
+ # prefix.bits
121
+ # #=> "11111111111111111111111100000000"
122
+ #
123
+ def bits
124
+ "%.32b" % to_u32
125
+ end
126
+
127
+ #
128
+ # Gives the prefix in IPv4 dotted decimal format,
129
+ # i.e. the canonical netmask we're all used to
130
+ #
131
+ # prefix = IPAddress::Prefix32.new 24
132
+ #
133
+ # prefix.to_ip
134
+ # #=> "255.255.255.0"
135
+ #
136
+ def to_ip
137
+ [bits].pack("B*").unpack("CCCC").join(".")
138
+ end
139
+
140
+ #
141
+ # An array of octets of the IPv4 dotted decimal
142
+ # format
143
+ #
144
+ # prefix = IPAddress::Prefix32.new 24
145
+ #
146
+ # prefix.octets
147
+ # #=> [255, 255, 255, 0]
148
+ #
149
+ def octets
150
+ to_ip.split(".").map{|i| i.to_i}
151
+ end
152
+
153
+ #
154
+ # Unsigned 32 bits decimal number representing
155
+ # the prefix
156
+ #
157
+ # prefix = IPAddress::Prefix32.new 24
158
+ #
159
+ # prefix.to_u32
160
+ # #=> 4294967040
161
+ #
162
+ def to_u32
163
+ (IN4MASK >> host_prefix) << host_prefix
164
+ end
165
+
166
+ #
167
+ # Shortcut for the octecs in the dotted decimal
168
+ # representation
169
+ #
170
+ # prefix = IPAddress::Prefix32.new 24
171
+ #
172
+ # prefix[2]
173
+ # #=> 255
174
+ #
175
+ def [](index)
176
+ octets[index]
177
+ end
178
+
179
+ #
180
+ # The hostmask is the contrary of the subnet mask,
181
+ # as it shows the bits that can change within the
182
+ # hosts
183
+ #
184
+ # prefix = IPAddress::Prefix32.new 24
185
+ #
186
+ # prefix.hostmask
187
+ # #=> "0.0.0.255"
188
+ #
189
+ def hostmask
190
+ [~to_u32].pack("N").unpack("CCCC").join(".")
191
+ end
192
+
193
+ #
194
+ # Creates a new prefix by parsing a netmask in
195
+ # dotted decimal form
196
+ #
197
+ # prefix = IPAddress::Prefix32::parse_netmask "255.255.255.0"
198
+ # #=> 24
199
+ #
200
+ def self.parse_netmask(netmask)
201
+ octets = netmask.split(".").map{|i| i.to_i}
202
+ num = octets.pack("C"*octets.size).unpack("B*").first.count "1"
203
+ return self.new(num)
204
+ end
205
+
206
+ end # class Prefix32 < Prefix
207
+
208
+ class Prefix128 < Prefix
209
+
210
+ #
211
+ # Creates a new prefix object for 128 bits IPv6 addresses
212
+ #
213
+ # prefix = IPAddress::Prefix128.new 64
214
+ # #=> 64
215
+ #
216
+ def initialize(num=128)
217
+ unless (0..128).include? num.to_i
218
+ raise ArgumentError, "Prefix must be in range 0..128, got: #{num}"
219
+ end
220
+ super(num.to_i)
221
+ end
222
+
223
+ #
224
+ # Transforms the prefix into a string of bits
225
+ # representing the netmask
226
+ #
227
+ # prefix = IPAddress::Prefix128.new 64
228
+ #
229
+ # prefix.bits
230
+ # #=> "1111111111111111111111111111111111111111111111111111111111111111"
231
+ # "0000000000000000000000000000000000000000000000000000000000000000"
232
+ #
233
+ def bits
234
+ "1" * @prefix + "0" * (128 - @prefix)
235
+ end
236
+
237
+ #
238
+ # Unsigned 128 bits decimal number representing
239
+ # the prefix
240
+ #
241
+ # prefix = IPAddress::Prefix128.new 64
242
+ #
243
+ # prefix.to_u128
244
+ # #=> 340282366920938463444927863358058659840
245
+ #
246
+ def to_u128
247
+ bits.to_i(2)
248
+ end
249
+
250
+ #
251
+ # Returns the length of the host portion
252
+ # of a netmask.
253
+ #
254
+ # prefix = Prefix128.new 96
255
+ #
256
+ # prefix.host_prefix
257
+ # #=> 32
258
+ #
259
+ def host_prefix
260
+ 128 - @prefix
261
+ end
262
+
263
+ end # class Prefix123 < Prefix
264
+
265
+ end # module IPAddress
@@ -0,0 +1,3 @@
1
+ module Ipaddress
2
+ VERSION = "0.8.3"
3
+ end
data/lib/ipaddress.rb ADDED
@@ -0,0 +1,227 @@
1
+ #
2
+ # = IPAddress
3
+ #
4
+ # A ruby library to manipulate IPv4 and IPv6 addresses
5
+ #
6
+ #
7
+ # Package:: IPAddress
8
+ # Author:: Marco Ceresa <ceresa@ieee.org>
9
+ # License:: Ruby License
10
+ #
11
+ #--
12
+ #
13
+ #++
14
+
15
+ require 'ipaddress/ipv4'
16
+ require 'ipaddress/ipv6'
17
+ require 'ipaddress/mongoid' if defined?(Mongoid)
18
+
19
+ module IPAddress
20
+
21
+ NAME = "IPAddress"
22
+ GEM = "ipaddress"
23
+ AUTHORS = ["Marco Ceresa <ceresa@ieee.org>"]
24
+
25
+ #
26
+ # Parse the argument string to create a new
27
+ # IPv4, IPv6 or Mapped IP object
28
+ #
29
+ # ip = IPAddress.parse 167837953 # 10.1.1.1
30
+ # ip = IPAddress.parse "172.16.10.1/24"
31
+ # ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
32
+ # ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
33
+ #
34
+ # All the object created will be instances of the
35
+ # correct class:
36
+ #
37
+ # ip.class
38
+ # #=> IPAddress::IPv4
39
+ # ip6.class
40
+ # #=> IPAddress::IPv6
41
+ # ip_mapped.class
42
+ # #=> IPAddress::IPv6::Mapped
43
+ #
44
+ def IPAddress::parse(str)
45
+
46
+ # Check if an int was passed
47
+ if str.kind_of? Integer
48
+ return IPAddress::IPv4.new(ntoa(str))
49
+ end
50
+
51
+ case str
52
+ when /:.+\./
53
+ IPAddress::IPv6::Mapped.new(str)
54
+ when /\./
55
+ IPAddress::IPv4.new(str)
56
+ when /:/
57
+ IPAddress::IPv6.new(str)
58
+ else
59
+ raise ArgumentError, "Unknown IP Address #{str}"
60
+ end
61
+ end
62
+
63
+ #
64
+ # Converts a unit32 to IPv4
65
+ #
66
+ # IPAddress::ntoa(167837953)
67
+ # #-> "10.1.1.1"
68
+ #
69
+ def self.ntoa(uint)
70
+ unless(uint.is_a? Numeric and uint <= 0xffffffff and uint >= 0)
71
+ raise(::ArgumentError, "not a long integer: #{uint.inspect}")
72
+ end
73
+ ret = []
74
+ 4.times do
75
+ ret.unshift(uint & 0xff)
76
+ uint >>= 8
77
+ end
78
+ ret.join('.')
79
+ end
80
+
81
+ #
82
+ # True if the object is an IPv4 address
83
+ #
84
+ # ip = IPAddress("192.168.10.100/24")
85
+ #
86
+ # ip.ipv4?
87
+ # #-> true
88
+ #
89
+ def ipv4?
90
+ self.kind_of? IPAddress::IPv4
91
+ end
92
+
93
+ #
94
+ # True if the object is an IPv6 address
95
+ #
96
+ # ip = IPAddress("192.168.10.100/24")
97
+ #
98
+ # ip.ipv6?
99
+ # #-> false
100
+ #
101
+ def ipv6?
102
+ self.kind_of? IPAddress::IPv6
103
+ end
104
+
105
+ #
106
+ # Checks if the given string is a valid IP address,
107
+ # either IPv4 or IPv6
108
+ #
109
+ # Example:
110
+ #
111
+ # IPAddress::valid? "2002::1"
112
+ # #=> true
113
+ #
114
+ # IPAddress::valid? "10.0.0.256"
115
+ # #=> false
116
+ #
117
+ def self.valid?(addr)
118
+ valid_ipv4?(addr) || valid_ipv6?(addr)
119
+ end
120
+
121
+ #
122
+ # Checks if the given string is a valid IPv4 address
123
+ #
124
+ # Example:
125
+ #
126
+ # IPAddress::valid_ipv4? "2002::1"
127
+ # #=> false
128
+ #
129
+ # IPAddress::valid_ipv4? "172.16.10.1"
130
+ # #=> true
131
+ #
132
+ def self.valid_ipv4?(addr)
133
+ if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
134
+ return $~.captures.all? {|i| i.to_i < 256}
135
+ end
136
+ false
137
+ end
138
+
139
+ #
140
+ # Checks if the argument is a valid IPv4 netmask
141
+ # expressed in dotted decimal format.
142
+ #
143
+ # IPAddress.valid_ipv4_netmask? "255.255.0.0"
144
+ # #=> true
145
+ #
146
+ def self.valid_ipv4_netmask?(addr)
147
+ arr = addr.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first.scan(/01/)
148
+ arr.empty? && valid_ipv4?(addr)
149
+ rescue
150
+ return false
151
+ end
152
+
153
+ #
154
+ # Checks if the given string is a valid IPv6 address
155
+ #
156
+ # Example:
157
+ #
158
+ # IPAddress::valid_ipv6? "2002::1"
159
+ # #=> true
160
+ #
161
+ # IPAddress::valid_ipv6? "2002::DEAD::BEEF"
162
+ # #=> false
163
+ #
164
+ def self.valid_ipv6?(addr)
165
+ # https://gist.github.com/cpetschnig/294476
166
+ # http://forums.intermapper.com/viewtopic.php?t=452
167
+ return true if /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/ =~ addr
168
+ false
169
+ end
170
+
171
+ #
172
+ # Deprecate method
173
+ #
174
+ def self.deprecate(message = nil) # :nodoc:
175
+ message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
176
+ warn("DEPRECATION WARNING: #{message}")
177
+ end
178
+
179
+ end # module IPAddress
180
+
181
+ #
182
+ # IPAddress is a wrapper method built around
183
+ # IPAddress's library classes. Its purpouse is to
184
+ # make you indipendent from the type of IP address
185
+ # you're going to use.
186
+ #
187
+ # For example, instead of creating the three types
188
+ # of IP addresses using their own contructors
189
+ #
190
+ # ip = IPAddress::IPv4.new "172.16.10.1/24"
191
+ # ip6 = IPAddress::IPv6.new "2001:db8::8:800:200c:417a/64"
192
+ # ip_mapped = IPAddress::IPv6::Mapped "::ffff:172.16.10.1/128"
193
+ #
194
+ # you can just use the IPAddress wrapper:
195
+ #
196
+ # ip = IPAddress "172.16.10.1/24"
197
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
198
+ # ip_mapped = IPAddress "::ffff:172.16.10.1/128"
199
+ #
200
+ # All the object created will be instances of the
201
+ # correct class:
202
+ #
203
+ # ip.class
204
+ # #=> IPAddress::IPv4
205
+ # ip6.class
206
+ # #=> IPAddress::IPv6
207
+ # ip_mapped.class
208
+ # #=> IPAddress::IPv6::Mapped
209
+ #
210
+ def IPAddress(str)
211
+ IPAddress::parse str
212
+ end
213
+
214
+ #
215
+ # Compatibility with Ruby 1.8
216
+ #
217
+ if RUBY_VERSION =~ /^1\.8/
218
+ class Hash # :nodoc:
219
+ alias :key :index
220
+ end
221
+ module Math # :nodoc:
222
+ def Math.log2(n)
223
+ log(n) / log(2)
224
+ end
225
+ end
226
+ end
227
+
@@ -0,0 +1,16 @@
1
+ require 'jeweler'
2
+ Jeweler::Tasks.new do |gem|
3
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
4
+ gem.name = "ipaddress_link_local"
5
+ gem.summary = %q{IPv4/IPv6 address manipulation library}
6
+ gem.description = %q{IPAddress is a Ruby library designed to make manipulation
7
+ of IPv4 and IPv6 addresses both powerful and simple. It mantains
8
+ a layer of compatibility with Ruby's own IPAddr, while
9
+ addressing many of its issues.
10
+ This gem has link-local features - only published to get gem dependencies working.}
11
+ gem.email = "ceresa@gmail.com"
12
+ gem.homepage = "https://github.com/bluemonk/ipaddress"
13
+ gem.authors = ["bluemonk", "mikemackintosh"]
14
+ gem.license = "MIT"
15
+ end
16
+ Jeweler::RubygemsDotOrgTasks.new