ruby-masscan 0.2.2 → 0.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -3
- data/ChangeLog.md +15 -0
- data/lib/masscan/banner.rb +2 -0
- data/lib/masscan/command.rb +387 -20
- data/lib/masscan/output_file.rb +7 -3
- data/lib/masscan/parsers/binary.rb +4 -2
- data/lib/masscan/parsers/json.rb +5 -3
- data/lib/masscan/parsers/list.rb +5 -3
- data/lib/masscan/parsers/plain_text.rb +2 -0
- data/lib/masscan/parsers.rb +5 -3
- data/lib/masscan/program.rb +3 -1
- data/lib/masscan/status.rb +2 -0
- data/lib/masscan/version.rb +3 -1
- data/lib/masscan.rb +5 -3
- data/ruby-masscan.gemspec +1 -4
- data/spec/command_spec.rb +561 -1
- data/spec/output_file_spec.rb +2 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5c7131e7fffe842982596ea49bdc4caafdcab24c9a2b1bd1dcc0b1372ca710ef
|
|
4
|
+
data.tar.gz: 50a2a06aca667ba92b82366f904420f6d42e30d05259ebab46a372ca7b4f4618
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7c91b8b36dcd52defb23ee391cc4f3f6a04fe47cb9d5495f8a737f10210e32b1c5929cbd6da138f617b3f0eb27727285eaec1dcd05cb245d7c95f3cbd97589d
|
|
7
|
+
data.tar.gz: a714178ff916f8c469df962a3cf6aa8905c537de2f9c39d0a71fda4487ba820f6862357a1c0028e93966e8c6276e5c796b07399eee0dd87d262d33aabc589e1a
|
data/.github/workflows/ruby.yml
CHANGED
data/ChangeLog.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
### 0.3.0 / 2024-06-23
|
|
2
|
+
|
|
3
|
+
* Include `Enumerable` into {Masscan::OutputFile}.
|
|
4
|
+
* Improvements to {Masscan::Command}:
|
|
5
|
+
* Added the `rotate` attribute for the `--rotate` option.
|
|
6
|
+
* Allow the `ports` attribute to accept a raw String value.
|
|
7
|
+
* Improve validation of String values passed to `ports`, `adapter_port`,
|
|
8
|
+
`range`, `shards`, and `ips` attributes.
|
|
9
|
+
* Correct the type used for the `exclude` attribute.
|
|
10
|
+
|
|
11
|
+
### 0.2.3 / 2024-01-27
|
|
12
|
+
|
|
13
|
+
* Switched to using `require_relative` to improve load-times.
|
|
14
|
+
* Added `# frozen_string_literal: true` to all files.
|
|
15
|
+
|
|
1
16
|
### 0.2.2 / 2023-04-20
|
|
2
17
|
|
|
3
18
|
* Corrected option definitions:
|
data/lib/masscan/banner.rb
CHANGED
data/lib/masscan/command.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'command_mapper/command'
|
|
2
4
|
|
|
5
|
+
require 'ipaddr'
|
|
6
|
+
|
|
3
7
|
module Masscan
|
|
4
8
|
#
|
|
5
9
|
# Provides an interface for invoking the `masscan` utility.
|
|
@@ -86,20 +90,98 @@ module Masscan
|
|
|
86
90
|
#
|
|
87
91
|
class Command < CommandMapper::Command
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
#
|
|
94
|
+
# Represents a port number.
|
|
95
|
+
#
|
|
96
|
+
# @api private
|
|
97
|
+
#
|
|
98
|
+
# @since 0.3.0
|
|
99
|
+
#
|
|
100
|
+
class Port < CommandMapper::Types::Num
|
|
101
|
+
|
|
102
|
+
# Regular expression that validates a port number.
|
|
103
|
+
PORT_REGEXP = /[1-9][0-9]{0,3}|[1-5][0-9][0-9][0-9][0-9]|6[0-4][0-9][0-9][0-9]|65[0-4][0-9][0-9]|655[0-2][0-9]|6553[0-5]/
|
|
104
|
+
|
|
105
|
+
# Regular expression that validates either a port number or service name.
|
|
106
|
+
REGEXP = /\A#{PORT_REGEXP}\z/
|
|
90
107
|
|
|
108
|
+
#
|
|
109
|
+
# Initializes the port type.
|
|
110
|
+
#
|
|
111
|
+
def initialize
|
|
112
|
+
super(range: 1..65535)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
#
|
|
116
|
+
# Validates the given value.
|
|
117
|
+
#
|
|
118
|
+
# @param [Object] value
|
|
119
|
+
# The value to validate.
|
|
120
|
+
#
|
|
121
|
+
# @return [true, (false, String)]
|
|
122
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
123
|
+
# message if the value is not compatible.
|
|
124
|
+
#
|
|
91
125
|
def validate(value)
|
|
92
126
|
case value
|
|
93
|
-
when
|
|
94
|
-
value
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
unless valid
|
|
98
|
-
return [valid, message]
|
|
99
|
-
end
|
|
127
|
+
when String
|
|
128
|
+
unless value =~ REGEXP
|
|
129
|
+
return [false, "must be a valid port number (#{value.inspect})"]
|
|
100
130
|
end
|
|
101
131
|
|
|
102
132
|
return true
|
|
133
|
+
else
|
|
134
|
+
super(value)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#
|
|
139
|
+
# Formats the given port number.
|
|
140
|
+
#
|
|
141
|
+
# @param [Integer, String] value
|
|
142
|
+
# The given port number.
|
|
143
|
+
#
|
|
144
|
+
# @return [String]
|
|
145
|
+
# The formatted port number.
|
|
146
|
+
#
|
|
147
|
+
def format(value)
|
|
148
|
+
case value
|
|
149
|
+
when String
|
|
150
|
+
value
|
|
151
|
+
else
|
|
152
|
+
super(value)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# Represents a port range.
|
|
160
|
+
#
|
|
161
|
+
# @api private
|
|
162
|
+
#
|
|
163
|
+
# @since 0.3.0
|
|
164
|
+
#
|
|
165
|
+
class PortRange < Port
|
|
166
|
+
|
|
167
|
+
# Regular expression to validate either a port or a port range.
|
|
168
|
+
PORT_RANGE_REGEXP = /#{PORT_REGEXP}-#{PORT_REGEXP}|#{PORT_REGEXP}/
|
|
169
|
+
|
|
170
|
+
# Regular expression to validate either a port or a port range.
|
|
171
|
+
REGEXP = /\A#{PORT_RANGE_REGEXP}\z/
|
|
172
|
+
|
|
173
|
+
#
|
|
174
|
+
# Validates the given port or port range value.
|
|
175
|
+
#
|
|
176
|
+
# @param [Object] value
|
|
177
|
+
# The port or port range value to validate.
|
|
178
|
+
#
|
|
179
|
+
# @return [true, (false, String)]
|
|
180
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
181
|
+
# message if the value is not compatible.
|
|
182
|
+
#
|
|
183
|
+
def validate(value)
|
|
184
|
+
case value
|
|
103
185
|
when Range
|
|
104
186
|
valid, message = super(value.begin)
|
|
105
187
|
|
|
@@ -113,16 +195,29 @@ module Masscan
|
|
|
113
195
|
return [valid, message]
|
|
114
196
|
end
|
|
115
197
|
|
|
198
|
+
return true
|
|
199
|
+
when String
|
|
200
|
+
unless value =~ REGEXP
|
|
201
|
+
return [false, "must be a valid port range or port number (#{value.inspect})"]
|
|
202
|
+
end
|
|
203
|
+
|
|
116
204
|
return true
|
|
117
205
|
else
|
|
118
206
|
super(value)
|
|
119
207
|
end
|
|
120
208
|
end
|
|
121
209
|
|
|
210
|
+
#
|
|
211
|
+
# Formats the given port or port range value.
|
|
212
|
+
#
|
|
213
|
+
# @param [Range, Integer, String] value
|
|
214
|
+
# The port or port range value to format.
|
|
215
|
+
#
|
|
216
|
+
# @return [String]
|
|
217
|
+
# The formatted port or port range.
|
|
218
|
+
#
|
|
122
219
|
def format(value)
|
|
123
220
|
case value
|
|
124
|
-
when Array
|
|
125
|
-
value.map(&method(:format)).join(',')
|
|
126
221
|
when Range
|
|
127
222
|
"#{value.begin}-#{value.end}"
|
|
128
223
|
else
|
|
@@ -132,21 +227,135 @@ module Masscan
|
|
|
132
227
|
|
|
133
228
|
end
|
|
134
229
|
|
|
230
|
+
#
|
|
231
|
+
# Represents the type for the `-p,--ports` option.
|
|
232
|
+
#
|
|
233
|
+
# @api private
|
|
234
|
+
#
|
|
235
|
+
class PortList < CommandMapper::Types::List
|
|
236
|
+
|
|
237
|
+
# Regular expression for validating a port or port range.
|
|
238
|
+
PORT_RANGE_REGEXP = PortRange::PORT_RANGE_REGEXP
|
|
239
|
+
|
|
240
|
+
# Regular expression that validates port list String values.
|
|
241
|
+
REGEXP = /\A(?:(?:U:)?#{PORT_RANGE_REGEXP})(?:,(?:U:)?#{PORT_RANGE_REGEXP})*\z/
|
|
242
|
+
|
|
243
|
+
#
|
|
244
|
+
# Initializes the port list type.
|
|
245
|
+
#
|
|
246
|
+
def initialize
|
|
247
|
+
super(type: PortRange.new)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
#
|
|
251
|
+
# Validates a given value.
|
|
252
|
+
#
|
|
253
|
+
# @param [Array, Range, String, Object] value
|
|
254
|
+
# The port list value.
|
|
255
|
+
#
|
|
256
|
+
# @return [true, (false, String)]
|
|
257
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
258
|
+
# message if the value is not compatible.
|
|
259
|
+
#
|
|
260
|
+
def validate(value)
|
|
261
|
+
case value
|
|
262
|
+
when Range
|
|
263
|
+
@type.validate(value)
|
|
264
|
+
when String
|
|
265
|
+
unless value =~ REGEXP
|
|
266
|
+
return [false, "not a valid port list (#{value.inspect})"]
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
return true
|
|
270
|
+
else
|
|
271
|
+
super(value)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
#
|
|
276
|
+
# Formats a port list value into a String.
|
|
277
|
+
#
|
|
278
|
+
# @param [Array<String, Integer, Range>, Range<Integer,Integer>, String, #to_s] value
|
|
279
|
+
# The port list value to format.
|
|
280
|
+
#
|
|
281
|
+
# @return [String]
|
|
282
|
+
# The formatted port list string.
|
|
283
|
+
#
|
|
284
|
+
def format(value)
|
|
285
|
+
case value
|
|
286
|
+
when Range
|
|
287
|
+
# format an individual port range
|
|
288
|
+
@type.format(value)
|
|
289
|
+
when String
|
|
290
|
+
# pass strings directly through
|
|
291
|
+
value
|
|
292
|
+
else
|
|
293
|
+
super(value)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
#
|
|
300
|
+
# Represents the type for the `--shards` option.
|
|
301
|
+
#
|
|
302
|
+
# @api private
|
|
303
|
+
#
|
|
135
304
|
class Shards < CommandMapper::Types::Str
|
|
136
305
|
|
|
306
|
+
# Regular expression for validating `--shards` values.
|
|
307
|
+
REGEXP = %r{\A\d+/\d+\z}
|
|
308
|
+
|
|
309
|
+
#
|
|
310
|
+
# Validates a shards value.
|
|
311
|
+
#
|
|
312
|
+
# @param [Array, Rational, String, #to_s] value
|
|
313
|
+
# The shards value to validate.
|
|
314
|
+
#
|
|
315
|
+
# @return [true, (false, String)]
|
|
316
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
317
|
+
# message if the value is not compatible.
|
|
318
|
+
#
|
|
137
319
|
def validate(value)
|
|
138
320
|
case value
|
|
139
321
|
when Array
|
|
140
|
-
|
|
141
|
-
return [false, "
|
|
322
|
+
unless value.length == 2
|
|
323
|
+
return [false, "must contain two elements (#{value.inspect})"]
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
unless (value[0].kind_of?(Integer) && value[1].kind_of?(Integer))
|
|
327
|
+
return [false, "shard values must be Integers (#{value.inspect})"]
|
|
142
328
|
end
|
|
143
329
|
|
|
330
|
+
return true
|
|
331
|
+
when Rational
|
|
144
332
|
return true
|
|
145
333
|
else
|
|
146
|
-
super(value)
|
|
334
|
+
valid, message = super(value)
|
|
335
|
+
|
|
336
|
+
unless valid
|
|
337
|
+
return [valid, message]
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
string = value.to_s
|
|
341
|
+
|
|
342
|
+
unless string =~ REGEXP
|
|
343
|
+
return [false, "invalid shards value (#{value.inspect})"]
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
return true
|
|
147
347
|
end
|
|
148
348
|
end
|
|
149
349
|
|
|
350
|
+
#
|
|
351
|
+
# Formats a shards value into a String.
|
|
352
|
+
#
|
|
353
|
+
# @param [(Integer, Integer), Rational, #to_s] value
|
|
354
|
+
# The shards value to format.
|
|
355
|
+
#
|
|
356
|
+
# @return [String]
|
|
357
|
+
# The formatted shards value.
|
|
358
|
+
#
|
|
150
359
|
def format(value)
|
|
151
360
|
case value
|
|
152
361
|
when Array
|
|
@@ -158,8 +367,166 @@ module Masscan
|
|
|
158
367
|
|
|
159
368
|
end
|
|
160
369
|
|
|
370
|
+
#
|
|
371
|
+
# Represents the type for the `--rotate` option.
|
|
372
|
+
#
|
|
373
|
+
# @api private
|
|
374
|
+
#
|
|
375
|
+
# @since 0.3.0
|
|
376
|
+
#
|
|
377
|
+
class RotateTime < CommandMapper::Types::Str
|
|
378
|
+
|
|
379
|
+
# Regular expression to validate the `--rotate` time value.
|
|
380
|
+
REGEXP = /\A(?:\d+|hourly|\d+hours|\d+min)\z/
|
|
381
|
+
|
|
382
|
+
#
|
|
383
|
+
# Validates a `--rotate` time value.
|
|
384
|
+
#
|
|
385
|
+
# @param [Integer, String, #to_s] value
|
|
386
|
+
# The time value to validate.
|
|
387
|
+
#
|
|
388
|
+
# @return [true, (false, String)]
|
|
389
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
390
|
+
# message if the value is not compatible.
|
|
391
|
+
#
|
|
392
|
+
def validate(value)
|
|
393
|
+
case value
|
|
394
|
+
when Integer
|
|
395
|
+
return true
|
|
396
|
+
else
|
|
397
|
+
valid, message = super(value)
|
|
398
|
+
|
|
399
|
+
unless valid
|
|
400
|
+
return [valid, message]
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
string = value.to_s
|
|
404
|
+
|
|
405
|
+
unless string =~ REGEXP
|
|
406
|
+
return [false, "invalid rotation time (#{value.inspect})"]
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
return true
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
#
|
|
416
|
+
# Represents the type for the `--adapter-mac` and `--router-mac` options.
|
|
417
|
+
#
|
|
418
|
+
# @api private
|
|
419
|
+
#
|
|
420
|
+
# @since 0.3.0
|
|
421
|
+
#
|
|
422
|
+
class MACAddress < CommandMapper::Types::Str
|
|
423
|
+
|
|
424
|
+
# Regular expression to validate a MAC address.
|
|
425
|
+
REGEXP = /\A[A-Fa-f0-9]{2}(?::[A-Fa-f0-9]{2}){5}\z/
|
|
426
|
+
|
|
427
|
+
#
|
|
428
|
+
# Validates a MAC address value.
|
|
429
|
+
#
|
|
430
|
+
# @param [String, #to_s] value
|
|
431
|
+
# The MAC address value to validate.
|
|
432
|
+
#
|
|
433
|
+
# @return [true, (false, String)]
|
|
434
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
435
|
+
# message if the value is not compatible.
|
|
436
|
+
#
|
|
437
|
+
def validate(value)
|
|
438
|
+
valid, message = super(value)
|
|
439
|
+
|
|
440
|
+
unless valid
|
|
441
|
+
return [valid, message]
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
string = value.to_s
|
|
445
|
+
|
|
446
|
+
unless string =~ REGEXP
|
|
447
|
+
return [false, "invalid MAC address (#{value.inspect})"]
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
return true
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
#
|
|
456
|
+
# Represents the type for the `--range` option and `ips` argument(s).
|
|
457
|
+
#
|
|
458
|
+
# @api private
|
|
459
|
+
#
|
|
460
|
+
# @since 0.3.0
|
|
461
|
+
#
|
|
462
|
+
class Target < CommandMapper::Types::Str
|
|
463
|
+
|
|
464
|
+
# Regular expression for validating decimal octets (0-255).
|
|
465
|
+
DECIMAL_OCTET_REGEXP = /(?<=[^\d]|^)(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])(?=[^\d]|$)/
|
|
466
|
+
|
|
467
|
+
# Regular expression for validating IPv4 addresses or CIDR ranges.
|
|
468
|
+
IPV4_REGEXP = %r{#{DECIMAL_OCTET_REGEXP}(?:\.#{DECIMAL_OCTET_REGEXP}){3}(?:/\d{1,2})?}
|
|
469
|
+
|
|
470
|
+
# Regular expression for validating IPv6 addresses or CIDR ranges.
|
|
471
|
+
IPV6_REGEXP = %r{
|
|
472
|
+
(?:[0-9a-f]{1,4}:){6}#{IPV4_REGEXP}|
|
|
473
|
+
(?:[0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:#{IPV4_REGEXP}|
|
|
474
|
+
(?:[0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:#{IPV4_REGEXP}|
|
|
475
|
+
(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,4}:#{IPV4_REGEXP}|
|
|
476
|
+
(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,3}:#{IPV4_REGEXP}|
|
|
477
|
+
(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,2}:#{IPV4_REGEXP}|
|
|
478
|
+
(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,1}:#{IPV4_REGEXP}|
|
|
479
|
+
:(?::[0-9a-f]{1,4}){1,5}:#{IPV4_REGEXP}|
|
|
480
|
+
(?:(?:[0-9a-f]{1,4}:){1,5}|:):#{IPV4_REGEXP}|
|
|
481
|
+
(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,6}(?:/\d{1,3})?|
|
|
482
|
+
(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}(?:/\d{1,3})?|
|
|
483
|
+
(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}(?:/\d{1,3})?|
|
|
484
|
+
(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}(?:/\d{1,3})?|
|
|
485
|
+
(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}(?:/\d{1,3})?|
|
|
486
|
+
(?:[0-9a-f]{1,4}:){1,6}(?::[0-9a-f]{1,4}){1,1}(?:/\d{1,3})?|
|
|
487
|
+
[0-9a-f]{1,4}(?::[0-9a-f]{1,4}){7}(?:/\d{1,3})?|
|
|
488
|
+
:(?::[0-9a-f]{1,4}){1,7}(?:/\d{1,3})?|
|
|
489
|
+
(?:(?:[0-9a-f]{1,4}:){1,7}|:):(?:/\d{1,3})?
|
|
490
|
+
}x
|
|
491
|
+
|
|
492
|
+
# Regular expression for validating masscan target IPs or IP ranges.
|
|
493
|
+
REGEXP = /\A(?:#{IPV4_REGEXP}|#{IPV6_REGEXP})\z/
|
|
494
|
+
|
|
495
|
+
#
|
|
496
|
+
# Validates a IP or IP range target value.
|
|
497
|
+
#
|
|
498
|
+
# @param [IPAddr, String, #to_s] value
|
|
499
|
+
# The IP or IP range value to validate.
|
|
500
|
+
#
|
|
501
|
+
# @return [true, (false, String)]
|
|
502
|
+
# Returns true if the value is valid, or `false` and a validation error
|
|
503
|
+
# message if the value is not compatible.
|
|
504
|
+
#
|
|
505
|
+
def validate(value)
|
|
506
|
+
case value
|
|
507
|
+
when IPAddr
|
|
508
|
+
return true
|
|
509
|
+
else
|
|
510
|
+
valid, message = super(value)
|
|
511
|
+
|
|
512
|
+
unless valid
|
|
513
|
+
return [valid, message]
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
string = value.to_s
|
|
517
|
+
|
|
518
|
+
unless string =~ REGEXP
|
|
519
|
+
return [false, "invalid IP or IP range (#{value.inspect})"]
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
return true
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
end
|
|
527
|
+
|
|
161
528
|
command "masscan" do
|
|
162
|
-
option '--range', name: :range, value:
|
|
529
|
+
option '--range', name: :range, value: {type: Target.new}, repeats: true
|
|
163
530
|
option '-p', name: :ports, value: {type: PortList.new}
|
|
164
531
|
option '--banners', name: :banners
|
|
165
532
|
option '--rate', name: :rate, value: {type: Num.new}
|
|
@@ -168,12 +535,12 @@ module Masscan
|
|
|
168
535
|
option '--echo', name: :echo, value: true
|
|
169
536
|
option '--adapter', name: :adapter, value: true
|
|
170
537
|
option '--adapter-ip', name: :adapter_ip, value: true
|
|
171
|
-
option '--adapter-port', name: :adapter_port, value: {type:
|
|
172
|
-
option '--adapter-mac', name: :adapter_mac, value:
|
|
538
|
+
option '--adapter-port', name: :adapter_port, value: {type: PortRange.new}
|
|
539
|
+
option '--adapter-mac', name: :adapter_mac, value: {type: MACAddress.new}
|
|
173
540
|
option '--adapter-vlan', name: :adapter_vlan, value: true
|
|
174
|
-
option '--router-mac', name: :router_mac, value:
|
|
541
|
+
option '--router-mac', name: :router_mac, value: {type: MACAddress.new}
|
|
175
542
|
option '--ping', name: :ping
|
|
176
|
-
option '--exclude', name: :exclude, value:
|
|
543
|
+
option '--exclude', name: :exclude, value: {type: Target.new}, repeats: true
|
|
177
544
|
option '--excludefile', name: :exclude_file, value: {type: InputFile.new}, repeats: true
|
|
178
545
|
option '--includefile', name: :include_file, value: {type: InputFile.new}, repeats: true
|
|
179
546
|
option '--append-output', name: :append_output
|
|
@@ -203,7 +570,7 @@ module Masscan
|
|
|
203
570
|
option '--resume-index', name: :resume_index
|
|
204
571
|
option '--resume-count', name: :resume_count
|
|
205
572
|
option '--shards', name: :shards, value: {type: Shards.new}
|
|
206
|
-
option '--rotate', name: :rotate, value:
|
|
573
|
+
option '--rotate', name: :rotate, value: {type: RotateTime.new}
|
|
207
574
|
option '--rotate-offset', name: :rotate_offset, value: true
|
|
208
575
|
option '--rotate-size', name: :rotate_size, value: true
|
|
209
576
|
option '--rotate-dir', name: :rotate_dir, value: {type: InputDir.new}
|
|
@@ -233,7 +600,7 @@ module Masscan
|
|
|
233
600
|
option '-V', name: :version
|
|
234
601
|
option '-h', name: :help
|
|
235
602
|
|
|
236
|
-
argument :ips, repeats: true
|
|
603
|
+
argument :ips, repeats: true, type: Target.new
|
|
237
604
|
end
|
|
238
605
|
|
|
239
606
|
end
|
data/lib/masscan/output_file.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'parsers/list'
|
|
4
|
+
require_relative 'parsers/json'
|
|
5
|
+
require_relative 'parsers/binary'
|
|
4
6
|
|
|
5
7
|
module Masscan
|
|
6
8
|
#
|
|
@@ -15,6 +17,8 @@ module Masscan
|
|
|
15
17
|
#
|
|
16
18
|
class OutputFile
|
|
17
19
|
|
|
20
|
+
include Enumerable
|
|
21
|
+
|
|
18
22
|
# Mapping of formats to parsers.
|
|
19
23
|
#
|
|
20
24
|
# @api semipublic
|
data/lib/masscan/parsers/json.rb
CHANGED
data/lib/masscan/parsers/list.rb
CHANGED
data/lib/masscan/parsers.rb
CHANGED
data/lib/masscan/program.rb
CHANGED
data/lib/masscan/status.rb
CHANGED
data/lib/masscan/version.rb
CHANGED
data/lib/masscan.rb
CHANGED
data/ruby-masscan.gemspec
CHANGED
|
@@ -7,10 +7,7 @@ Gem::Specification.new do |gem|
|
|
|
7
7
|
|
|
8
8
|
gem.name = gemspec.fetch('name')
|
|
9
9
|
gem.version = gemspec.fetch('version') do
|
|
10
|
-
|
|
11
|
-
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
|
12
|
-
|
|
13
|
-
require 'masscan/version'
|
|
10
|
+
require_relative 'lib/masscan/version'
|
|
14
11
|
Masscan::VERSION
|
|
15
12
|
end
|
|
16
13
|
|
data/spec/command_spec.rb
CHANGED
|
@@ -2,6 +2,164 @@ require 'spec_helper'
|
|
|
2
2
|
require 'masscan/command'
|
|
3
3
|
|
|
4
4
|
describe Masscan::Command do
|
|
5
|
+
describe described_class::Port do
|
|
6
|
+
describe "#validate" do
|
|
7
|
+
context "when given an Integer" do
|
|
8
|
+
let(:value) { 443 }
|
|
9
|
+
|
|
10
|
+
it "must return true" do
|
|
11
|
+
expect(subject.validate(value)).to be(true)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context "but it's less than 1" do
|
|
15
|
+
let(:value) { 0 }
|
|
16
|
+
|
|
17
|
+
it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
|
|
18
|
+
expect(subject.validate(value)).to eq(
|
|
19
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "but it's greater than 65535" do
|
|
25
|
+
let(:value) { 65536 }
|
|
26
|
+
|
|
27
|
+
it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
|
|
28
|
+
expect(subject.validate(value)).to eq(
|
|
29
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "when given a String" do
|
|
36
|
+
context "and it's a number" do
|
|
37
|
+
let(:value) { '443' }
|
|
38
|
+
|
|
39
|
+
it "must return true" do
|
|
40
|
+
expect(subject.validate(value)).to be(true)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "but it's less than 1" do
|
|
44
|
+
let(:value) { '0' }
|
|
45
|
+
|
|
46
|
+
it "must return [false, \"must be a valid port number (...)\"]" do
|
|
47
|
+
expect(subject.validate(value)).to eq(
|
|
48
|
+
[false, "must be a valid port number (#{value.inspect})"]
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context "but it's greater than 65535" do
|
|
54
|
+
let(:value) { '65536' }
|
|
55
|
+
|
|
56
|
+
it "must return [false, \"must be a valid port number (...)\"]" do
|
|
57
|
+
expect(subject.validate(value)).to eq(
|
|
58
|
+
[false, "must be a valid port number (#{value.inspect})"]
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context "but it contains numbers" do
|
|
65
|
+
let(:value) { "foo" }
|
|
66
|
+
|
|
67
|
+
it "must return [false, \"must be a valid port number (...)\"]" do
|
|
68
|
+
expect(subject.validate(value)).to eq(
|
|
69
|
+
[false, "must be a valid port number (#{value.inspect})"]
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe described_class::PortRange do
|
|
78
|
+
describe "#validate" do
|
|
79
|
+
context "when given an Integer value" do
|
|
80
|
+
let(:value) { 443 }
|
|
81
|
+
|
|
82
|
+
it "must return true" do
|
|
83
|
+
expect(subject.validate(value)).to be(true)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "but it's less than 1" do
|
|
87
|
+
let(:value) { 0 }
|
|
88
|
+
|
|
89
|
+
it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
|
|
90
|
+
expect(subject.validate(value)).to eq(
|
|
91
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "but it's greater than 65535" do
|
|
97
|
+
let(:value) { 65536 }
|
|
98
|
+
|
|
99
|
+
it "must return [false, \"(...) not within the range of acceptable values (1..65535)\"]" do
|
|
100
|
+
expect(subject.validate(value)).to eq(
|
|
101
|
+
[false, "(#{value.inspect}) not within the range of acceptable values (1..65535)"]
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "when given a String value" do
|
|
108
|
+
let(:value) { '443' }
|
|
109
|
+
|
|
110
|
+
it "must return true" do
|
|
111
|
+
expect(subject.validate(value)).to be(true)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
context "but it's less than 1" do
|
|
115
|
+
let(:value) { '0' }
|
|
116
|
+
|
|
117
|
+
it "must return [false, \"must be a valid port range or port number (...)\"]" do
|
|
118
|
+
expect(subject.validate(value)).to eq(
|
|
119
|
+
[false, "must be a valid port range or port number (#{value.inspect})"]
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "but it's greater than 65535" do
|
|
125
|
+
let(:value) { '65536' }
|
|
126
|
+
|
|
127
|
+
it "must return [false, \"must be a valid port range or port number (...)\"]" do
|
|
128
|
+
expect(subject.validate(value)).to eq(
|
|
129
|
+
[false, "must be a valid port range or port number (#{value.inspect})"]
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
context "when given a Range of port numbers" do
|
|
136
|
+
let(:value) { (1..1024) }
|
|
137
|
+
|
|
138
|
+
it "must return true" do
|
|
139
|
+
expect(subject.validate(value)).to be(true)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe "#format" do
|
|
145
|
+
context "when given a single port number" do
|
|
146
|
+
let(:value) { 443 }
|
|
147
|
+
|
|
148
|
+
it "must return the formatted port number" do
|
|
149
|
+
expect(subject.format(value)).to eq(value.to_s)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "when given a Range of port numbers" do
|
|
154
|
+
let(:value) { 1..1024 }
|
|
155
|
+
|
|
156
|
+
it "must return the formatted port number range (ex: 1-102)" do
|
|
157
|
+
expect(subject.format(value)).to eq("#{value.begin}-#{value.end}")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
5
163
|
describe described_class::PortList do
|
|
6
164
|
describe "#validate" do
|
|
7
165
|
context "when given a single port number" do
|
|
@@ -35,6 +193,118 @@ describe Masscan::Command do
|
|
|
35
193
|
end
|
|
36
194
|
end
|
|
37
195
|
end
|
|
196
|
+
|
|
197
|
+
context "when given a String" do
|
|
198
|
+
context "and it contains a single number" do
|
|
199
|
+
let(:value) { "443" }
|
|
200
|
+
|
|
201
|
+
it "must return true" do
|
|
202
|
+
expect(subject.validate(value)).to be(true)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context "and it's prefixed by 'U:'" do
|
|
206
|
+
let(:value) { "U:#{super()}" }
|
|
207
|
+
|
|
208
|
+
it "must return true" do
|
|
209
|
+
expect(subject.validate(value)).to be(true)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context "and it contains a range of ports" do
|
|
215
|
+
let(:value) { "1-1024" }
|
|
216
|
+
|
|
217
|
+
it "must return true" do
|
|
218
|
+
expect(subject.validate(value)).to be(true)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
context "and it's prefixed by 'U:'" do
|
|
222
|
+
let(:value) { "U:#{super()}" }
|
|
223
|
+
|
|
224
|
+
it "must return true" do
|
|
225
|
+
expect(subject.validate(value)).to be(true)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
context "and it contains a comma separated list of port numbers" do
|
|
231
|
+
let(:value) { "80,443" }
|
|
232
|
+
|
|
233
|
+
it "must return true" do
|
|
234
|
+
expect(subject.validate(value)).to be(true)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
context "and it's prefixed by 'U:'" do
|
|
238
|
+
let(:value) { "U:#{super()}" }
|
|
239
|
+
|
|
240
|
+
it "must return true" do
|
|
241
|
+
expect(subject.validate(value)).to be(true)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
context "and it contains a comma separated list of port ranges" do
|
|
247
|
+
let(:value) { "1-42,80-8080" }
|
|
248
|
+
|
|
249
|
+
it "must return true" do
|
|
250
|
+
expect(subject.validate(value)).to be(true)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
context "and it's prefixed by 'U:'" do
|
|
254
|
+
let(:value) { "U:#{super()}" }
|
|
255
|
+
|
|
256
|
+
it "must return true" do
|
|
257
|
+
expect(subject.validate(value)).to be(true)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
context "and it contains a comma separated list of port numbers and ranges" do
|
|
263
|
+
let(:value) { "1-42,50,60,70,80-8080,9000" }
|
|
264
|
+
|
|
265
|
+
it "must return true" do
|
|
266
|
+
expect(subject.validate(value)).to be(true)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
context "and it's prefixed by 'U:'" do
|
|
270
|
+
let(:value) { "U:#{super()}" }
|
|
271
|
+
|
|
272
|
+
it "must return true" do
|
|
273
|
+
expect(subject.validate(value)).to be(true)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
context "when it contains non-digits" do
|
|
279
|
+
let(:value) { "1,2,3,4,a,b,c" }
|
|
280
|
+
|
|
281
|
+
it "must return false and a validation error message" do
|
|
282
|
+
expect(subject.validate(value)).to eq(
|
|
283
|
+
[false, "not a valid port list (#{value.inspect})"]
|
|
284
|
+
)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
context "when it contains whitespace" do
|
|
289
|
+
let(:value) { "1,2, 3,4" }
|
|
290
|
+
|
|
291
|
+
it "must return false and a validation error message" do
|
|
292
|
+
expect(subject.validate(value)).to eq(
|
|
293
|
+
[false, "not a valid port list (#{value.inspect})"]
|
|
294
|
+
)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
context "when it contains new-lines" do
|
|
299
|
+
let(:value) { "1,2,\n3,4" }
|
|
300
|
+
|
|
301
|
+
it "must return false and a validation error message" do
|
|
302
|
+
expect(subject.validate(value)).to eq(
|
|
303
|
+
[false, "not a valid port list (#{value.inspect})"]
|
|
304
|
+
)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
38
308
|
end
|
|
39
309
|
|
|
40
310
|
describe "#format" do
|
|
@@ -69,6 +339,14 @@ describe Masscan::Command do
|
|
|
69
339
|
end
|
|
70
340
|
end
|
|
71
341
|
end
|
|
342
|
+
|
|
343
|
+
context "when given a String" do
|
|
344
|
+
let(:value) { "22,25,80,443" }
|
|
345
|
+
|
|
346
|
+
it "must return the String" do
|
|
347
|
+
expect(subject.format(value)).to eq(value)
|
|
348
|
+
end
|
|
349
|
+
end
|
|
72
350
|
end
|
|
73
351
|
end
|
|
74
352
|
|
|
@@ -89,12 +367,42 @@ describe Masscan::Command do
|
|
|
89
367
|
expect(subject.validate(value)).to be(true)
|
|
90
368
|
end
|
|
91
369
|
|
|
370
|
+
context "but the Array length is 1" do
|
|
371
|
+
let(:value) { [1] }
|
|
372
|
+
|
|
373
|
+
it "must return a validation error" do
|
|
374
|
+
expect(subject.validate(value)).to eq(
|
|
375
|
+
[false, "must contain two elements (#{value.inspect})"]
|
|
376
|
+
)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
92
380
|
context "but the Array length is > 2" do
|
|
93
381
|
let(:value) { [1,2,3] }
|
|
94
382
|
|
|
95
383
|
it "must return a validation error" do
|
|
96
384
|
expect(subject.validate(value)).to eq(
|
|
97
|
-
[false, "
|
|
385
|
+
[false, "must contain two elements (#{value.inspect})"]
|
|
386
|
+
)
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
context "when given a String" do
|
|
392
|
+
context "and it matches X/Y" do
|
|
393
|
+
let(:value) { "1/2" }
|
|
394
|
+
|
|
395
|
+
it "must return true" do
|
|
396
|
+
expect(subject.validate(value)).to be(true)
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
context "but it does not match X/Y" do
|
|
401
|
+
let(:value) { "1" }
|
|
402
|
+
|
|
403
|
+
it "must return a validation error" do
|
|
404
|
+
expect(subject.validate(value)).to eq(
|
|
405
|
+
[false, "invalid shards value (#{value.inspect})"]
|
|
98
406
|
)
|
|
99
407
|
end
|
|
100
408
|
end
|
|
@@ -139,4 +447,256 @@ describe Masscan::Command do
|
|
|
139
447
|
end
|
|
140
448
|
end
|
|
141
449
|
end
|
|
450
|
+
|
|
451
|
+
describe described_class::RotateTime do
|
|
452
|
+
describe "#validate" do
|
|
453
|
+
context "when given an Integer" do
|
|
454
|
+
let(:value) { 42 }
|
|
455
|
+
|
|
456
|
+
it "must return true" do
|
|
457
|
+
expect(subject.validate(value)).to be(true)
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
context "when given a String" do
|
|
462
|
+
context "but the String is a number" do
|
|
463
|
+
let(:value) { '42' }
|
|
464
|
+
|
|
465
|
+
it "must return true" do
|
|
466
|
+
expect(subject.validate(value)).to be(true)
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
context "but the String is 'hourly'" do
|
|
471
|
+
let(:value) { 'hourly' }
|
|
472
|
+
|
|
473
|
+
it "must return true" do
|
|
474
|
+
expect(subject.validate(value)).to be(true)
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
context "but the String is '<N>hours'" do
|
|
479
|
+
let(:value) { '2hours' }
|
|
480
|
+
|
|
481
|
+
it "must return true" do
|
|
482
|
+
expect(subject.validate(value)).to be(true)
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
context "but the String is '<N>min'" do
|
|
487
|
+
let(:value) { '10min' }
|
|
488
|
+
|
|
489
|
+
it "must return true" do
|
|
490
|
+
expect(subject.validate(value)).to be(true)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
context "but the String is not a number" do
|
|
495
|
+
let(:value) { "abc" }
|
|
496
|
+
|
|
497
|
+
it "must return a validation error" do
|
|
498
|
+
expect(subject.validate(value)).to eq([false, "invalid rotation time (#{value.inspect})"])
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
context "but the String contains a new-line" do
|
|
503
|
+
let(:value) { "10\nfoo" }
|
|
504
|
+
|
|
505
|
+
it "must return a validation error" do
|
|
506
|
+
expect(subject.validate(value)).to eq([false, "invalid rotation time (#{value.inspect})"])
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
describe described_class::MACAddress do
|
|
514
|
+
describe "#validate" do
|
|
515
|
+
context "when given a String" do
|
|
516
|
+
context "and it's a valid MAC address" do
|
|
517
|
+
let(:value) { "00:11:22:33:44:55" }
|
|
518
|
+
|
|
519
|
+
it "must return true" do
|
|
520
|
+
expect(subject.validate(value)).to be(true)
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
context "but an octent contains less than two hex digits" do
|
|
525
|
+
let(:value) { "0:11:22:33:44" }
|
|
526
|
+
|
|
527
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
528
|
+
expect(subject.validate(value)).to eq(
|
|
529
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
530
|
+
)
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
context "but an octent contains more than two hex digits" do
|
|
535
|
+
let(:value) { "000:11:22:33:44" }
|
|
536
|
+
|
|
537
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
538
|
+
expect(subject.validate(value)).to eq(
|
|
539
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
540
|
+
)
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
context "but it's contains less than six octets" do
|
|
545
|
+
let(:value) { "00:11:22:33:44" }
|
|
546
|
+
|
|
547
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
548
|
+
expect(subject.validate(value)).to eq(
|
|
549
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
550
|
+
)
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
context "but it's contains more than six octets" do
|
|
555
|
+
let(:value) { "00:11:22:33:44:55:66" }
|
|
556
|
+
|
|
557
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
558
|
+
expect(subject.validate(value)).to eq(
|
|
559
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
560
|
+
)
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
context "but it contains non-hex characters" do
|
|
565
|
+
let(:value) { "000:11:22:33:44:xx" }
|
|
566
|
+
|
|
567
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
568
|
+
expect(subject.validate(value)).to eq(
|
|
569
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
570
|
+
)
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
context "but it is not separated by ':' characters" do
|
|
575
|
+
let(:value) { "00.11.22.33.44.55" }
|
|
576
|
+
|
|
577
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
578
|
+
expect(subject.validate(value)).to eq(
|
|
579
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
580
|
+
)
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
context "but it contains spaces" do
|
|
585
|
+
let(:value) { "00:11:22: 33:44:55" }
|
|
586
|
+
|
|
587
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
588
|
+
expect(subject.validate(value)).to eq(
|
|
589
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
590
|
+
)
|
|
591
|
+
end
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
context "but it contains new-line characters" do
|
|
595
|
+
let(:value) { "00:11:22:\n33:44:55" }
|
|
596
|
+
|
|
597
|
+
it "must return [false, \"invalid MAC address (...)\"]" do
|
|
598
|
+
expect(subject.validate(value)).to eq(
|
|
599
|
+
[false, "invalid MAC address (#{value.inspect})"]
|
|
600
|
+
)
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
describe described_class::Target do
|
|
608
|
+
describe "#validate" do
|
|
609
|
+
context "when given an IPAddr object" do
|
|
610
|
+
let(:value) { IPAddr.new('127.0.0.1') }
|
|
611
|
+
|
|
612
|
+
it "must return true" do
|
|
613
|
+
expect(subject.validate(value)).to be(true)
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
context "when given a String" do
|
|
618
|
+
context "and it's an IPv4 address" do
|
|
619
|
+
let(:value) { '127.0.0.1' }
|
|
620
|
+
|
|
621
|
+
it "must return true" do
|
|
622
|
+
expect(subject.validate(value)).to be(true)
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
context "and it's an IPv4 range" do
|
|
627
|
+
let(:value) { '127.0.0.1/24' }
|
|
628
|
+
|
|
629
|
+
it "must return true" do
|
|
630
|
+
expect(subject.validate(value)).to be(true)
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
context "and it's an IPv6 address" do
|
|
635
|
+
context "but it's in compressed notation" do
|
|
636
|
+
let(:value) { '::1' }
|
|
637
|
+
|
|
638
|
+
it "must return true" do
|
|
639
|
+
expect(subject.validate(value)).to be(true)
|
|
640
|
+
end
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
context "and it's in full notation" do
|
|
644
|
+
let(:value) { '2606:2800:220:1:248:1893:25c8:1946' }
|
|
645
|
+
|
|
646
|
+
it "must return true" do
|
|
647
|
+
expect(subject.validate(value)).to be(true)
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
context "and it's an IPv6 range" do
|
|
653
|
+
context "but it's in compressed notation" do
|
|
654
|
+
let(:value) { '::1/32' }
|
|
655
|
+
|
|
656
|
+
it "must return true" do
|
|
657
|
+
expect(subject.validate(value)).to be(true)
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
context "and it's in full notation" do
|
|
662
|
+
let(:value) { '2606:2800:220:1:248:1893:25c8:1946/32' }
|
|
663
|
+
|
|
664
|
+
it "must return true" do
|
|
665
|
+
expect(subject.validate(value)).to be(true)
|
|
666
|
+
end
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
context "but it contains non-hex characters" do
|
|
671
|
+
let(:value) { '2606:2800:220:1:248:1893:25c8:xxxx/32' }
|
|
672
|
+
|
|
673
|
+
it "must return [false, \"invalid IP or IP range (...)\"]" do
|
|
674
|
+
expect(subject.validate(value)).to eq(
|
|
675
|
+
[false, "invalid IP or IP range (#{value.inspect})"]
|
|
676
|
+
)
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
context "but it contains spaces" do
|
|
681
|
+
let(:value) { '2606:2800:220:1: 248:1893:25c8:1946/32' }
|
|
682
|
+
|
|
683
|
+
it "must return [false, \"invalid IP or IP range (...)\"]" do
|
|
684
|
+
expect(subject.validate(value)).to eq(
|
|
685
|
+
[false, "invalid IP or IP range (#{value.inspect})"]
|
|
686
|
+
)
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
context "but it contains new-line characters" do
|
|
691
|
+
let(:value) { "2606:2800:220:1:\n248:1893:25c8:1946/32" }
|
|
692
|
+
|
|
693
|
+
it "must return [false, \"invalid IP or IP range (...)\"]" do
|
|
694
|
+
expect(subject.validate(value)).to eq(
|
|
695
|
+
[false, "invalid IP or IP range (#{value.inspect})"]
|
|
696
|
+
)
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
end
|
|
142
702
|
end
|
data/spec/output_file_spec.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-masscan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Postmodern
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-06-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: command_mapper
|
|
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
111
111
|
version: '0'
|
|
112
112
|
requirements:
|
|
113
113
|
- masscan >= 1.0.0
|
|
114
|
-
rubygems_version: 3.
|
|
114
|
+
rubygems_version: 3.5.9
|
|
115
115
|
signing_key:
|
|
116
116
|
specification_version: 4
|
|
117
117
|
summary: A Ruby interface to masscan.
|