ronin-support 1.0.1 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +38 -0
  3. data/README.md +0 -1
  4. data/lib/ronin/support/archive/core_ext/file.rb +43 -0
  5. data/lib/ronin/support/archive/core_ext.rb +1 -1
  6. data/lib/ronin/support/binary/array.rb +1 -1
  7. data/lib/ronin/support/binary/buffer.rb +3 -3
  8. data/lib/ronin/support/binary/core_ext.rb +2 -0
  9. data/lib/ronin/support/binary/cstring.rb +43 -0
  10. data/lib/ronin/support/binary/ctypes/array_type.rb +1 -1
  11. data/lib/ronin/support/binary/ctypes/os/bsd.rb +1 -1
  12. data/lib/ronin/support/binary/ctypes/unbounded_array_type.rb +1 -1
  13. data/lib/ronin/support/binary/packet.rb +77 -0
  14. data/lib/ronin/support/binary/stack.rb +3 -3
  15. data/lib/ronin/support/binary/template.rb +1 -5
  16. data/lib/ronin/support/binary.rb +1 -0
  17. data/lib/ronin/support/cli/io_shell.rb +2 -0
  18. data/lib/ronin/support/compression/core_ext/file.rb +16 -0
  19. data/lib/ronin/support/core_ext/kernel.rb +0 -4
  20. data/lib/ronin/support/crypto/cert.rb +17 -9
  21. data/lib/ronin/support/crypto/core_ext/file.rb +32 -0
  22. data/lib/ronin/support/crypto/core_ext/string.rb +34 -2
  23. data/lib/ronin/support/encoding/base16.rb +1 -1
  24. data/lib/ronin/support/encoding/base32.rb +1 -1
  25. data/lib/ronin/support/encoding/c/core_ext/string.rb +1 -1
  26. data/lib/ronin/support/encoding/c.rb +2 -2
  27. data/lib/ronin/support/encoding/core_ext/string.rb +2 -2
  28. data/lib/ronin/support/encoding/hex/core_ext/string.rb +1 -1
  29. data/lib/ronin/support/encoding/hex.rb +2 -2
  30. data/lib/ronin/support/encoding/js.rb +1 -1
  31. data/lib/ronin/support/encoding/powershell.rb +1 -1
  32. data/lib/ronin/support/encoding/quoted_printable.rb +3 -1
  33. data/lib/ronin/support/encoding/ruby.rb +1 -1
  34. data/lib/ronin/support/encoding/uuencoding.rb +3 -1
  35. data/lib/ronin/support/encoding/xml.rb +1 -1
  36. data/lib/ronin/support/network/dns/mixin.rb +2 -10
  37. data/lib/ronin/support/network/http/core_ext/uri/http.rb +8 -0
  38. data/lib/ronin/support/network/ip.rb +45 -14
  39. data/lib/ronin/support/network/ip_range.rb +4 -4
  40. data/lib/ronin/support/network/ssl/mixin.rb +2 -0
  41. data/lib/ronin/support/path.rb +1 -1
  42. data/lib/ronin/support/text/homoglyph/core_ext/string.rb +33 -0
  43. data/lib/ronin/support/text/patterns/network.rb +20 -20
  44. data/lib/ronin/support/text/random/mixin.rb +17 -17
  45. data/lib/ronin/support/text/random.rb +23 -23
  46. data/lib/ronin/support/text/typo/core_ext/string.rb +24 -0
  47. data/lib/ronin/support/version.rb +1 -1
  48. metadata +2 -2
@@ -54,10 +54,10 @@ class String
54
54
 
55
55
  #
56
56
  # @return [String]
57
- # The SHA2 checksum of the String.
57
+ # The SHA256 checksum of the String.
58
58
  #
59
59
  # @example
60
- # "hello".sha2
60
+ # "hello".sha256
61
61
  # # => "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
62
62
  #
63
63
  # @api public
@@ -152,6 +152,10 @@ class String
152
152
  # @return [String]
153
153
  # The encrypted String.
154
154
  #
155
+ # @example
156
+ # "top secret".encrypt('aes-256-cbc', password: 's3cr3t')
157
+ # # => "\xF0[\x17\xDA\xA2\x82\x93\xF4\xB6s\xB5\xD8\x1F\xF2\xC6\\"
158
+ #
155
159
  # @see http://rubydoc.info/stdlib/openssl/OpenSSL/Cipher
156
160
  #
157
161
  # @since 0.6.0
@@ -191,6 +195,10 @@ class String
191
195
  # @return [String]
192
196
  # The decrypted String.
193
197
  #
198
+ # @example
199
+ # "\xF0[\x17\xDA\xA2\x82\x93\xF4\xB6s\xB5\xD8\x1F\xF2\xC6\\".decrypt('aes-256-cbc', password: 's3cr3t')
200
+ # # => "top secret"
201
+ #
194
202
  # @see http://rubydoc.info/stdlib/openssl/OpenSSL/Cipher
195
203
  #
196
204
  # @since 0.6.0
@@ -236,6 +244,10 @@ class String
236
244
  # @raise [ArgumentError]
237
245
  # Either the the `key:` or `password:` keyword argument must be given.
238
246
  #
247
+ # @example
248
+ # "top secret".aes_encrypt(key_size: 256, password: 's3cr3t')
249
+ # # => "\xF0[\x17\xDA\xA2\x82\x93\xF4\xB6s\xB5\xD8\x1F\xF2\xC6\\"
250
+ #
239
251
  # @since 1.0.0
240
252
  #
241
253
  def aes_encrypt(**kwargs)
@@ -275,6 +287,10 @@ class String
275
287
  # @raise [ArgumentError]
276
288
  # Either the the `key:` or `password:` keyword argument must be given.
277
289
  #
290
+ # @example
291
+ # "\xF0[\x17\xDA\xA2\x82\x93\xF4\xB6s\xB5\xD8\x1F\xF2\xC6\\".aes_decrypt(key_size: 256, password: 's3cr3t')
292
+ # # => "top secret"
293
+ #
278
294
  # @since 1.0.0
279
295
  #
280
296
  def aes_decrypt(**kwargs)
@@ -311,6 +327,10 @@ class String
311
327
  # @raise [ArgumentError]
312
328
  # Either the the `key:` or `password:` keyword argument must be given.
313
329
  #
330
+ # @example
331
+ # "top secret".aes128_encrypt(password: 's3cr3t')
332
+ # # => "\x88\xA53\xE9|\xE2\x8E\xA0\xABv\xCF\x94\x17\xBB*\xC5"
333
+ #
314
334
  # @since 1.0.0
315
335
  #
316
336
  def aes128_encrypt(**kwargs)
@@ -347,6 +367,10 @@ class String
347
367
  # @raise [ArgumentError]
348
368
  # Either the the `key:` or `password:` keyword argument must be given.
349
369
  #
370
+ # @example
371
+ # "\x88\xA53\xE9|\xE2\x8E\xA0\xABv\xCF\x94\x17\xBB*\xC5".aes128_decrypt(password: 's3cr3t')
372
+ # # => "top secret"
373
+ #
350
374
  # @since 1.0.0
351
375
  #
352
376
  def aes128_decrypt(**kwargs)
@@ -383,6 +407,10 @@ class String
383
407
  # @raise [ArgumentError]
384
408
  # Either the the `key:` or `password:` keyword argument must be given.
385
409
  #
410
+ # @example
411
+ # "top secret".aes256_encrypt(password: 's3cr3t')
412
+ # # => "\xF0[\x17\xDA\xA2\x82\x93\xF4\xB6s\xB5\xD8\x1F\xF2\xC6\\"
413
+ #
386
414
  # @since 1.0.0
387
415
  #
388
416
  def aes256_encrypt(**kwargs)
@@ -419,6 +447,10 @@ class String
419
447
  # @raise [ArgumentError]
420
448
  # Either the the `key:` or `password:` keyword argument must be given.
421
449
  #
450
+ # @example
451
+ # "\xF0[\x17\xDA\xA2\x82\x93\xF4\xB6s\xB5\xD8\x1F\xF2\xC6\\".aes256_decrypt(password: 's3cr3t')
452
+ # # => "top secret"
453
+ #
422
454
  # @since 1.0.0
423
455
  #
424
456
  def aes256_decrypt(**kwargs)
@@ -71,7 +71,7 @@ module Ronin
71
71
  # # => "hello"
72
72
  #
73
73
  def self.decode(data)
74
- decoded = String.new
74
+ decoded = String.new(encoding: Encoding::ASCII_8BIT)
75
75
 
76
76
  data.scan(/../).each do |hex_char|
77
77
  decoded << hex_char.to_i(16).chr
@@ -63,7 +63,7 @@ module Ronin
63
63
  # The Base32 decoded String.
64
64
  #
65
65
  def self.decode(data)
66
- decoded = String.new
66
+ decoded = String.new(encoding: Encoding::UTF_8)
67
67
 
68
68
  each_chunk(data,8) do |chunk|
69
69
  chunk.decode(decoded)
@@ -47,7 +47,7 @@ class String
47
47
  # The unescaped C String.
48
48
  #
49
49
  # @example
50
- # "\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64".c_unescape
50
+ # "\\x68\\x65\\x6c\\x6c\\x6f\\x20\\x77\\x6f\\x72\\x6c\\x64".c_unescape
51
51
  # # => "hello world"
52
52
  #
53
53
  # @see Ronin::Support::Encoding::C.unescape
@@ -213,11 +213,11 @@ module Ronin
213
213
  # The unescaped C String.
214
214
  #
215
215
  # @example
216
- # Encoding::C.unescape("\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64")
216
+ # Encoding::C.unescape("\\x68\\x65\\x6c\\x6c\\x6f\\x20\\x77\\x6f\\x72\\x6c\\x64")
217
217
  # # => "hello world"
218
218
  #
219
219
  def self.unescape(data)
220
- unescaped = String.new
220
+ unescaped = String.new(encoding: Encoding::UTF_8)
221
221
  scanner = StringScanner.new(data)
222
222
 
223
223
  until scanner.eos?
@@ -48,7 +48,7 @@ class String
48
48
  def encode_bytes(include: nil, exclude: nil)
49
49
  included = (Chars::CharSet.new(*include) if include)
50
50
  excluded = (Chars::CharSet.new(*exclude) if exclude)
51
- formatted = String.new
51
+ formatted = String.new(encoding: ::Encoding::UTF_8)
52
52
 
53
53
  each_byte do |b|
54
54
  formatted << if (included.nil? || included.include_byte?(b)) &&
@@ -90,7 +90,7 @@ class String
90
90
  def encode_chars(include: nil, exclude: nil)
91
91
  included = (Chars::CharSet.new(*include) if include)
92
92
  excluded = (Chars::CharSet.new(*exclude) if exclude)
93
- formatted = String.new
93
+ formatted = String.new(encoding: ::Encoding::UTF_8)
94
94
 
95
95
  each_char do |c|
96
96
  formatted << if (included.nil? || included.include_char?(c)) &&
@@ -79,7 +79,7 @@ class String
79
79
  # The hex unescaped version of the String.
80
80
  #
81
81
  # @example
82
- # "hello\\nworld".hex_escape
82
+ # "hello\\nworld".hex_unescape
83
83
  # # => "hello\nworld"
84
84
  #
85
85
  # @see Ronin::Support::Encoding::Hex.unescape
@@ -188,11 +188,11 @@ module Ronin
188
188
  # the same String if it is not quoted.
189
189
  #
190
190
  # @example
191
- # Encoding::Hex.unescape("\"hello\\nworld\"")
191
+ # Encoding::Hex.unescape("hello\\nworld")
192
192
  # # => "hello\nworld"
193
193
  #
194
194
  def self.unescape(data)
195
- buffer = String.new
195
+ buffer = String.new(encoding: Encoding::UTF_8)
196
196
  scanner = StringScanner.new(data)
197
197
 
198
198
  until scanner.eos?
@@ -182,7 +182,7 @@ module Ronin
182
182
  # # => "hello world"
183
183
  #
184
184
  def self.unescape(data)
185
- unescaped = String.new
185
+ unescaped = String.new(encoding: Encoding::UTF_8)
186
186
 
187
187
  data.scan(/[\\%]u[0-9a-fA-F]{1,4}|[\\%][0-9a-fA-F]{1,2}|\\[btnfr\'\"\\]|./) do |c|
188
188
  unescaped << BACKSLASHED_CHARS.fetch(c) do
@@ -191,7 +191,7 @@ module Ronin
191
191
  # # => "hello\nworld"
192
192
  #
193
193
  def self.unescape(data)
194
- unescaped = String.new
194
+ unescaped = String.new(encoding: Encoding::UTF_8)
195
195
  scanner = StringScanner.new(data)
196
196
 
197
197
  until scanner.eos?
@@ -22,7 +22,9 @@ module Ronin
22
22
  module Support
23
23
  class Encoding < ::Encoding
24
24
  #
25
- # Contains methods for encoding/decoding Quoted Printable data.
25
+ # Contains methods for encoding/decoding [Quoted Printable] data.
26
+ #
27
+ # [Quoted-Printable]: https://en.wikipedia.org/wiki/Quoted-printable
26
28
  #
27
29
  # ## Core-Ext Methods
28
30
  #
@@ -174,7 +174,7 @@ module Ronin
174
174
  # # => "hello"
175
175
  #
176
176
  def self.unescape(data)
177
- unescaped = String.new
177
+ unescaped = String.new(encoding: Encoding::UTF_8)
178
178
  scanner = StringScanner.new(data)
179
179
 
180
180
  until scanner.eos?
@@ -20,7 +20,9 @@ module Ronin
20
20
  module Support
21
21
  class Encoding < ::Encoding
22
22
  #
23
- # Contains methods for encoding/decoding UUEncoded data.
23
+ # Contains methods for encoding/decoding [UUEncoded][uuencoding] data.
24
+ #
25
+ # [uuencoding]: https://en.wikipedia.org/wiki/Uuencoding
24
26
  #
25
27
  # ## Core-Ext Methods
26
28
  #
@@ -312,7 +312,7 @@ module Ronin
312
312
  # @see http://rubydoc.info/stdlib/cgi/CGI.unescapeHash
313
313
  #
314
314
  def self.unescape(data)
315
- unescaped = String.new
315
+ unescaped = String.new(encoding: Encoding::UTF_8)
316
316
  scanner = StringScanner.new(data)
317
317
 
318
318
  until scanner.eos?
@@ -25,6 +25,8 @@ module Ronin
25
25
  #
26
26
  # Provides helper methods for performing DNS queries.
27
27
  #
28
+ # @api public
29
+ #
28
30
  module Mixin
29
31
  #
30
32
  # Sets the DNS nameservers to query.
@@ -79,8 +81,6 @@ module Ronin
79
81
  # @return [Resolv, Resolv::DNS]
80
82
  # The DNS Resolver.
81
83
  #
82
- # @api public
83
- #
84
84
  def dns_resolver(nameservers: nil, nameserver: nil)
85
85
  if nameserver
86
86
  Network::DNS.resolver(nameserver: nameserver)
@@ -111,8 +111,6 @@ module Ronin
111
111
  # @return [String, nil]
112
112
  # The address of the hostname.
113
113
  #
114
- # @api public
115
- #
116
114
  def dns_get_address(host,**kwargs)
117
115
  dns_resolver(**kwargs).get_address(host.to_s)
118
116
  end
@@ -137,8 +135,6 @@ module Ronin
137
135
  # @return [Array<String>]
138
136
  # The addresses of the hostname.
139
137
  #
140
- # @api public
141
- #
142
138
  def dns_get_addresses(host,**kwargs)
143
139
  dns_resolver(**kwargs).get_addresses(host.to_s)
144
140
  end
@@ -161,8 +157,6 @@ module Ronin
161
157
  # @return [String, nil]
162
158
  # The hostname of the address.
163
159
  #
164
- # @api public
165
- #
166
160
  def dns_get_name(ip,**kwargs)
167
161
  dns_resolver(**kwargs).get_name(ip.to_s)
168
162
  end
@@ -187,8 +181,6 @@ module Ronin
187
181
  # @return [Array<String>]
188
182
  # The hostnames of the address.
189
183
  #
190
- # @api public
191
- #
192
184
  def dns_get_names(ip,**kwargs)
193
185
  dns_resolver(**kwargs).get_names(ip.to_s)
194
186
  end
@@ -33,6 +33,10 @@ module URI
33
33
  # @return [Integer]
34
34
  # The HTTP Response Status.
35
35
  #
36
+ # @example
37
+ # URI('http://github.com/').status
38
+ # # => 301
39
+ #
36
40
  # @see Ronin::Support::Network::HTTP.response_status
37
41
  #
38
42
  # @since 0.3.0
@@ -53,6 +57,10 @@ module URI
53
57
  #
54
58
  # @see Ronin::Support::Network::HTTP.ok?
55
59
  #
60
+ # @example
61
+ # URI('https://example.com/').ok?
62
+ # # => true
63
+ #
56
64
  # @since 0.3.0
57
65
  #
58
66
  def ok?(**kwargs)
@@ -66,11 +66,6 @@ module Ronin
66
66
  #
67
67
  class IP < IPAddr
68
68
 
69
- # The address of the IP.
70
- #
71
- # @return [String]
72
- attr_reader :address
73
-
74
69
  #
75
70
  # Initializes the IP address.
76
71
  #
@@ -92,9 +87,15 @@ module Ronin
92
87
  # the IP address.
93
88
  #
94
89
  def initialize(address,family=Socket::AF_UNSPEC)
95
- # XXX: remove the %iface suffix for ruby < 3.1.0
96
- if address.kind_of?(String) && address =~ /%.+$/
97
- address = address.sub(/%.+$/,'')
90
+ case address
91
+ when String
92
+ # XXX: remove the %iface suffix for ruby < 3.1.0
93
+ if address =~ /%.+$/
94
+ address = address.sub(/%.+$/,'')
95
+ end
96
+
97
+ # pre-cache the given IP address String
98
+ @address = address
98
99
  end
99
100
 
100
101
  begin
@@ -102,13 +103,33 @@ module Ronin
102
103
  rescue IPAddr::InvalidAddressError
103
104
  raise(InvalidIP,"invalid IP address: #{address.inspect}")
104
105
  end
106
+ end
105
107
 
106
- @address = case address
107
- when String then address.to_s
108
- else to_s
109
- end
108
+ protected
109
+
110
+ #
111
+ # Sets the IP address using the numeric IP address value.
112
+ #
113
+ # @param [Integer] addr
114
+ # The new numeric IP address value.
115
+ #
116
+ # @param [Integer] family
117
+ # Optional IP address family.
118
+ #
119
+ # @return [self]
120
+ #
121
+ # @api private
122
+ #
123
+ def set(addr,*family)
124
+ super(addr,*family)
125
+
126
+ # unset the cached IP address since the numeric address has changed
127
+ @address = nil
128
+ return self
110
129
  end
111
130
 
131
+ public
132
+
112
133
  # The URI for https://ipinfo.io/ip
113
134
  IPINFO_URI = URI::HTTPS.build(host: 'ipinfo.io', path: '/ip')
114
135
 
@@ -286,6 +307,16 @@ module Ronin
286
307
  ipv4? && (@addr & 0xff) == 0x00
287
308
  end
288
309
 
310
+ #
311
+ # The IP address.
312
+ #
313
+ # @return [String]
314
+ # The String version of the IP address.
315
+ #
316
+ def address
317
+ @address ||= to_s
318
+ end
319
+
289
320
  #
290
321
  # The Autonomous System Number (ASN) information for the IP address.
291
322
  #
@@ -519,8 +550,8 @@ module Ronin
519
550
  end
520
551
 
521
552
  alias canonical to_string
522
- alias to_uint to_i
523
553
  alias to_str to_s
554
+ alias to_uint to_i
524
555
 
525
556
  #
526
557
  # Inspects the IP.
@@ -529,7 +560,7 @@ module Ronin
529
560
  # The inspected IP object.
530
561
  #
531
562
  def inspect
532
- "#<#{self.class}: #{@address}>"
563
+ "#<#{self.class}: #{address}>"
533
564
  end
534
565
 
535
566
  end
@@ -40,7 +40,7 @@ module Ronin
40
40
  #
41
41
  # Enumerating over a IP-glob range:
42
42
  #
43
- # IPRange.each('10.0.1-3.*/24') { |ip| puts ip }
43
+ # IPRange.each('10.0.1-3.*') { |ip| puts ip }
44
44
  # # 10.0.1.1
45
45
  # # 10.0.1.2
46
46
  # # ...
@@ -75,7 +75,7 @@ module Ronin
75
75
  # ip_range = IPRange.new('10.0.0.1/24')
76
76
  #
77
77
  # @example Initializing an IP-glob range:
78
- # ip_range = IPRange.new('10.0.1-3.*/24')
78
+ # ip_range = IPRange.new('10.0.1-3.*')
79
79
  #
80
80
  def initialize(string)
81
81
  @range = if self.class.glob?(string) then Glob.new(string)
@@ -125,7 +125,7 @@ module Ronin
125
125
  # # 10.0.0.255
126
126
  #
127
127
  # @example Enumerating over a IP-glob range:
128
- # IPRange.each('10.0.1-3.*/24') { |ip| puts ip }
128
+ # IPRange.each('10.0.1-3.*') { |ip| puts ip }
129
129
  # # 10.0.1.1
130
130
  # # 10.0.1.2
131
131
  # # ...
@@ -228,7 +228,7 @@ module Ronin
228
228
  # # 10.0.0.255
229
229
  #
230
230
  # @example Enumerating over a IP-glob range:
231
- # ip_range = IPRange.new('10.0.1-3.*/24')
231
+ # ip_range = IPRange.new('10.0.1-3.*')
232
232
  # ip_range.each { |ip| puts ip }
233
233
  # # 10.0.1.1
234
234
  # # 10.0.1.2
@@ -267,6 +267,8 @@ module Ronin
267
267
  socket = tcp_connect(host,port,bind_host: bind_host,
268
268
  bind_port: bind_port)
269
269
  ssl_socket = ssl_socket(socket,**kwargs)
270
+
271
+ ssl_socket.hostname = host
270
272
  ssl_socket.connect
271
273
 
272
274
  if block_given?
@@ -115,7 +115,7 @@ module Ronin
115
115
  # # => #<Ronin::Support::Path:../../../../../../../etc/passwd>
116
116
  #
117
117
  def join(*names)
118
- joined_path = if root? then String.new
118
+ joined_path = if root? then String.new(encoding: Encoding::UTF_8)
119
119
  else self.to_s
120
120
  end
121
121
 
@@ -39,6 +39,10 @@ class String
39
39
  # @raise [Ronin::Support::Text::Homoglyph::NotViable]
40
40
  # No homoglyph replaceable characters were found in the String.
41
41
  #
42
+ # @example
43
+ # "microsoft".homoglyph
44
+ # # => "microsoft"
45
+ #
42
46
  # @see Ronin::Support::Text::Homoglyph.substitute
43
47
  #
44
48
  # @api public
@@ -68,6 +72,11 @@ class String
68
72
  # @return [Enumerator]
69
73
  # If no block is given, an Enumerator object will be returned.
70
74
  #
75
+ # @example
76
+ # "microsoft".each_homoglyph do |homoglyph|
77
+ # # ...
78
+ # end
79
+ #
71
80
  # @see Ronin::Support::Text::Homoglyph.each_substitution
72
81
  #
73
82
  # @api public
@@ -95,6 +104,30 @@ class String
95
104
  # @return [Array<String>]
96
105
  # All variation of the given String.
97
106
  #
107
+ # @example
108
+ # "microsoft".homoglyphs
109
+ # # =>
110
+ # # ["ⅿicrosoft",
111
+ # # "microsoft",
112
+ # # "mіcrosoft",
113
+ # # "mⅰcrosoft",
114
+ # # "microsoft",
115
+ # # "miϲrosoft",
116
+ # # "miсrosoft",
117
+ # # "miⅽrosoft",
118
+ # # "microsoft",
119
+ # # "microsoft",
120
+ # # "micrοsoft",
121
+ # # "microsοft",
122
+ # # "micrоsoft",
123
+ # # "microsоft",
124
+ # # "microsoft",
125
+ # # "microsoft",
126
+ # # "microѕoft",
127
+ # # "microsoft",
128
+ # # "microsoft",
129
+ # # "microsoft"]
130
+ #
98
131
  # @see Ronin::Support::Text::Homoglyph.each_substitution
99
132
  #
100
133
  # @api public
@@ -45,26 +45,26 @@ module Ronin
45
45
  # A regular expression for matching IPv6 Addresses.
46
46
  #
47
47
  # @since 1.0.0
48
- IPV6_ADDR = Regexp.union(
49
- /(?:[0-9a-f]{1,4}:){6}#{IPV4_ADDR}/,
50
- /(?:[0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:#{IPV4_ADDR}/,
51
- /(?:[0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:#{IPV4_ADDR}/,
52
- /(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,4}:#{IPV4_ADDR}/,
53
- /(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,3}:#{IPV4_ADDR}/,
54
- /(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,2}:#{IPV4_ADDR}/,
55
- /(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,1}:#{IPV4_ADDR}/,
56
- /:(?::[0-9a-f]{1,4}){1,5}:#{IPV4_ADDR}/,
57
- /(?:(?:[0-9a-f]{1,4}:){1,5}|:):#{IPV4_ADDR}/,
58
- %r{(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,6}(?:/\d{1,3})?},
59
- %r{(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}(?:/\d{1,3})?},
60
- %r{(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}(?:/\d{1,3})?},
61
- %r{(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}(?:/\d{1,3})?},
62
- %r{(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}(?:/\d{1,3})?},
63
- %r{(?:[0-9a-f]{1,4}:){1,6}(?::[0-9a-f]{1,4}){1,1}(?:/\d{1,3})?},
64
- %r{[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){7}(?:/\d{1,3})?},
65
- %r{:(?::[0-9a-f]{1,4}){1,7}(?:/\d{1,3})?},
66
- %r{(?:(?:[0-9a-f]{1,4}:){1,7}|:):(?:/\d{1,3})?}
67
- )
48
+ IPV6_ADDR = %r{
49
+ (?:[0-9a-f]{1,4}:){6}#{IPV4_ADDR}|
50
+ (?:[0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:#{IPV4_ADDR}|
51
+ (?:[0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:#{IPV4_ADDR}|
52
+ (?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,4}:#{IPV4_ADDR}|
53
+ (?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,3}:#{IPV4_ADDR}|
54
+ (?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,2}:#{IPV4_ADDR}|
55
+ (?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,1}:#{IPV4_ADDR}|
56
+ :(?::[0-9a-f]{1,4}){1,5}:#{IPV4_ADDR}|
57
+ (?:(?:[0-9a-f]{1,4}:){1,5}|:):#{IPV4_ADDR}|
58
+ (?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,6}(?:/\d{1,3})?|
59
+ (?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}(?:/\d{1,3})?|
60
+ (?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}(?:/\d{1,3})?|
61
+ (?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}(?:/\d{1,3})?|
62
+ (?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}(?:/\d{1,3})?|
63
+ (?:[0-9a-f]{1,4}:){1,6}(?::[0-9a-f]{1,4}){1,1}(?:/\d{1,3})?|
64
+ [0-9a-f]{1,4}(?::[0-9a-f]{1,4}){7}(?:/\d{1,3})?|
65
+ :(?::[0-9a-f]{1,4}){1,7}(?:/\d{1,3})?|
66
+ (?:(?:[0-9a-f]{1,4}:){1,7}|:):(?:/\d{1,3})?
67
+ }x
68
68
 
69
69
  # A regular expression for matching IP Addresses.
70
70
  #