ruby-masscan 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +7 -0
- data/lib/masscan/banner.rb +31 -1
- data/lib/masscan/parsers/binary.rb +52 -46
- data/lib/masscan/parsers/json.rb +13 -13
- data/lib/masscan/parsers/list.rb +11 -13
- data/lib/masscan/status.rb +33 -0
- data/lib/masscan/version.rb +1 -1
- data/spec/parsers/binary_spec.rb +504 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f03fa94f7c501646be712a24b98fe07a6dd156c054c7ae27714cac80b1fbb5e8
|
4
|
+
data.tar.gz: a346c7b055da689cad8571a38383b43a5e797889d6206b85ca7d2a64e25b904f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecdea1cc3b62cf1d0dbb2b7771807c05f2e6339b573f6208dcfb21e94fdaad160e51adc077e158ec6c4b4bc9426c7925dfd376d53d455922c5e318e6ee999936
|
7
|
+
data.tar.gz: 88bbf9a1332946ae7688fae852a1a3565269a853eff17434dc8e0b1fd7eae2c3e14b09cc64fa3fc80a06781f3fd644b97e5f97fcc52ccd2aa71cbc2a32b15f3c
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
### 0.1.1 / 2021-09-09
|
2
|
+
|
3
|
+
* Added missing {Masscan::Banner#ttl}.
|
4
|
+
* Fixed {Masscan::Parsers::Binary} to populate {Masscan::Banner#ttl}.
|
5
|
+
* Fixed {Masscan::Parsers::Binary#parse_status} to populate
|
6
|
+
{Masscan::Status#reason} and {Masscan::Status#ttl}.
|
7
|
+
|
1
8
|
### 0.1.0 / 2021-08-31
|
2
9
|
|
3
10
|
* Initial release:
|
data/lib/masscan/banner.rb
CHANGED
@@ -2,7 +2,37 @@ module Masscan
|
|
2
2
|
#
|
3
3
|
# Represents a banner record.
|
4
4
|
#
|
5
|
-
class Banner < Struct.new(:protocol,:port,:ip,:timestamp,:app_protocol,:payload)
|
5
|
+
class Banner < Struct.new(:protocol,:port,:ttl,:ip,:timestamp,:app_protocol,:payload)
|
6
|
+
|
7
|
+
#
|
8
|
+
# Initializes the banner.
|
9
|
+
#
|
10
|
+
# @param [:icmp, :tcp, :udp, :sctp] protocol
|
11
|
+
# The IP protocol.
|
12
|
+
#
|
13
|
+
# @param [Integer] port
|
14
|
+
# The port number.
|
15
|
+
#
|
16
|
+
# @param [Integer, nil] ttl
|
17
|
+
# The optional TTL.
|
18
|
+
#
|
19
|
+
# @param [IPAddr] ip
|
20
|
+
# The IP address.
|
21
|
+
#
|
22
|
+
# @param [Time] timestamp
|
23
|
+
# The record timestamp.
|
24
|
+
#
|
25
|
+
# @param [Symbol] app_protocol
|
26
|
+
# The application protocol.
|
27
|
+
#
|
28
|
+
# @param [String] payload
|
29
|
+
# The banner/capture payload.
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
def initialize(protocol: , port: , ttl: nil, ip: , timestamp: , app_protocol: , payload: )
|
34
|
+
super(protocol,port,ttl,ip,timestamp,app_protocol,payload)
|
35
|
+
end
|
6
36
|
|
7
37
|
alias service app_protocol
|
8
38
|
alias banner payload
|
@@ -366,12 +366,14 @@ module Masscan
|
|
366
366
|
end
|
367
367
|
|
368
368
|
return Status.new(
|
369
|
-
status,
|
370
|
-
protocol,
|
371
|
-
port,
|
372
|
-
|
373
|
-
|
374
|
-
|
369
|
+
status: status,
|
370
|
+
protocol: protocol,
|
371
|
+
port: port,
|
372
|
+
reason: reason,
|
373
|
+
ttl: ttl,
|
374
|
+
ip: ip,
|
375
|
+
timestamp: timestamp,
|
376
|
+
mac: mac
|
375
377
|
)
|
376
378
|
end
|
377
379
|
|
@@ -396,12 +398,13 @@ module Masscan
|
|
396
398
|
ttl = 0
|
397
399
|
|
398
400
|
return Banner.new(
|
399
|
-
ip_proto,
|
400
|
-
port,
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
401
|
+
protocol: ip_proto,
|
402
|
+
port: port,
|
403
|
+
ttl: ttl,
|
404
|
+
ip: ip,
|
405
|
+
timestamp: timestamp,
|
406
|
+
app_protocol: app_proto,
|
407
|
+
payload: payload
|
405
408
|
)
|
406
409
|
end
|
407
410
|
|
@@ -419,7 +422,7 @@ module Masscan
|
|
419
422
|
return
|
420
423
|
end
|
421
424
|
|
422
|
-
timestamp, ip,
|
425
|
+
timestamp, ip, ip_proto, port, app_proto, payload = buffer.unpack('L>L>CS>S>A*')
|
423
426
|
|
424
427
|
timestamp = decode_timestamp(timestamp)
|
425
428
|
ip = decode_ipv4(ip)
|
@@ -430,12 +433,13 @@ module Masscan
|
|
430
433
|
ttl = 0
|
431
434
|
|
432
435
|
return Banner.new(
|
433
|
-
ip_proto,
|
434
|
-
port,
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
436
|
+
protocol: ip_proto,
|
437
|
+
port: port,
|
438
|
+
ttl: ttl,
|
439
|
+
ip: ip,
|
440
|
+
timestamp: timestamp,
|
441
|
+
app_protocol: app_proto,
|
442
|
+
payload: payload
|
439
443
|
)
|
440
444
|
end
|
441
445
|
|
@@ -467,14 +471,14 @@ module Masscan
|
|
467
471
|
end
|
468
472
|
|
469
473
|
return Status.new(
|
470
|
-
status,
|
471
|
-
ip_proto,
|
472
|
-
port,
|
473
|
-
reason,
|
474
|
-
ttl,
|
475
|
-
ip,
|
476
|
-
timestamp,
|
477
|
-
mac
|
474
|
+
status: status,
|
475
|
+
protocol: ip_proto,
|
476
|
+
port: port,
|
477
|
+
reason: reason,
|
478
|
+
ttl: ttl,
|
479
|
+
ip: ip,
|
480
|
+
timestamp: timestamp,
|
481
|
+
mac: mac
|
478
482
|
)
|
479
483
|
end
|
480
484
|
|
@@ -499,12 +503,13 @@ module Masscan
|
|
499
503
|
app_proto = lookup_app_protocol(app_proto)
|
500
504
|
|
501
505
|
return Banner.new(
|
502
|
-
ip_proto,
|
503
|
-
port,
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
506
|
+
protocol: ip_proto,
|
507
|
+
port: port,
|
508
|
+
ttl: ttl,
|
509
|
+
ip: ip,
|
510
|
+
timestamp: timestamp,
|
511
|
+
app_protocol: app_proto,
|
512
|
+
payload: payload
|
508
513
|
)
|
509
514
|
end
|
510
515
|
|
@@ -541,13 +546,13 @@ module Masscan
|
|
541
546
|
ipv6 = decode_ipv6(ipv6_hi,ipv6_lo)
|
542
547
|
|
543
548
|
return Status.new(
|
544
|
-
status,
|
545
|
-
ip_proto,
|
546
|
-
port,
|
547
|
-
reason,
|
548
|
-
ttl,
|
549
|
-
ipv6,
|
550
|
-
timestamp
|
549
|
+
status: status,
|
550
|
+
protocol: ip_proto,
|
551
|
+
port: port,
|
552
|
+
reason: reason,
|
553
|
+
ttl: ttl,
|
554
|
+
ip: ipv6,
|
555
|
+
timestamp: timestamp
|
551
556
|
)
|
552
557
|
end
|
553
558
|
|
@@ -577,12 +582,13 @@ module Masscan
|
|
577
582
|
ipv6 = decode_ipv6(ipv6_hi,ipv6_lo)
|
578
583
|
|
579
584
|
return Banner.new(
|
580
|
-
ip_proto,
|
581
|
-
port,
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
585
|
+
protocol: ip_proto,
|
586
|
+
port: port,
|
587
|
+
ttl: ttl,
|
588
|
+
ip: ipv6,
|
589
|
+
timestamp: timestamp,
|
590
|
+
app_protocol: app_proto,
|
591
|
+
payload: payload
|
586
592
|
)
|
587
593
|
end
|
588
594
|
|
data/lib/masscan/parsers/json.rb
CHANGED
@@ -74,12 +74,12 @@ module Masscan
|
|
74
74
|
service_banner = service_json['banner']
|
75
75
|
|
76
76
|
yield Banner.new(
|
77
|
-
proto,
|
78
|
-
port,
|
79
|
-
ip,
|
80
|
-
timestamp,
|
81
|
-
service_name,
|
82
|
-
service_banner
|
77
|
+
protocol: proto,
|
78
|
+
port: port,
|
79
|
+
ip: ip,
|
80
|
+
timestamp: timestamp,
|
81
|
+
app_protocol: service_name,
|
82
|
+
payload: service_banner
|
83
83
|
)
|
84
84
|
else
|
85
85
|
status = parse_status(port_json['status'])
|
@@ -87,13 +87,13 @@ module Masscan
|
|
87
87
|
reason = parse_reason(port_json['reason'])
|
88
88
|
|
89
89
|
yield Status.new(
|
90
|
-
status,
|
91
|
-
proto,
|
92
|
-
port,
|
93
|
-
reason,
|
94
|
-
ttl,
|
95
|
-
ip,
|
96
|
-
timestamp
|
90
|
+
status: status,
|
91
|
+
protocol: proto,
|
92
|
+
port: port,
|
93
|
+
reason: reason,
|
94
|
+
ttl: ttl,
|
95
|
+
ip: ip,
|
96
|
+
timestamp: timestamp
|
97
97
|
)
|
98
98
|
end
|
99
99
|
end
|
data/lib/masscan/parsers/list.rb
CHANGED
@@ -57,24 +57,22 @@ module Masscan
|
|
57
57
|
type, ip_proto, port, ip, timestamp = line.split(' ',5)
|
58
58
|
|
59
59
|
yield Status.new(
|
60
|
-
parse_status(type),
|
61
|
-
parse_ip_protocol(ip_proto),
|
62
|
-
port.to_i,
|
63
|
-
|
64
|
-
|
65
|
-
parse_ip(ip),
|
66
|
-
parse_timestamp(timestamp)
|
60
|
+
status: parse_status(type),
|
61
|
+
protocol: parse_ip_protocol(ip_proto),
|
62
|
+
port: port.to_i,
|
63
|
+
ip: parse_ip(ip),
|
64
|
+
timestamp: parse_timestamp(timestamp)
|
67
65
|
)
|
68
66
|
elsif line.start_with?('banner ')
|
69
67
|
type, ip_proto, port, ip, timestamp, app_proto, banner = line.split(' ',7)
|
70
68
|
|
71
69
|
yield Banner.new(
|
72
|
-
parse_ip_protocol(ip_proto),
|
73
|
-
port.to_i,
|
74
|
-
parse_ip(ip),
|
75
|
-
parse_timestamp(timestamp),
|
76
|
-
parse_app_protocol(app_proto),
|
77
|
-
banner
|
70
|
+
protocol: parse_ip_protocol(ip_proto),
|
71
|
+
port: port.to_i,
|
72
|
+
ip: parse_ip(ip),
|
73
|
+
timestamp: parse_timestamp(timestamp),
|
74
|
+
app_protocol: parse_app_protocol(app_proto),
|
75
|
+
payload: banner
|
78
76
|
)
|
79
77
|
end
|
80
78
|
end
|
data/lib/masscan/status.rb
CHANGED
@@ -3,5 +3,38 @@ module Masscan
|
|
3
3
|
# Represents a port status record.
|
4
4
|
#
|
5
5
|
class Status < Struct.new(:status,:protocol,:port,:reason,:ttl,:ip,:timestamp,:mac)
|
6
|
+
|
7
|
+
#
|
8
|
+
# Initializes the status record.
|
9
|
+
#
|
10
|
+
# @param [:open, :closed] status
|
11
|
+
# The status of the port.
|
12
|
+
#
|
13
|
+
# @param [:icmp, :tcp, :udp, :sctp] protocol
|
14
|
+
# The IP protocol.
|
15
|
+
#
|
16
|
+
# @param [Integer] port
|
17
|
+
# The port number.
|
18
|
+
#
|
19
|
+
# @param [Array<:fin, :syn, :rst, :psh, :ack, :urg, :ece, :cwr>, nil] reason
|
20
|
+
# Flags indicating why the port was open or closed.
|
21
|
+
#
|
22
|
+
# @param [Integer, nil] ttl
|
23
|
+
# TTL.
|
24
|
+
#
|
25
|
+
# @param [IPAddr] ip
|
26
|
+
# The IP address.
|
27
|
+
#
|
28
|
+
# @param [Time] timestamp
|
29
|
+
# The record timestamp.
|
30
|
+
#
|
31
|
+
# @param [String, nil] mac
|
32
|
+
# Optional mac address.
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
#
|
36
|
+
def initialize(status: , protocol: , port: , reason: nil, ttl: nil, ip: , timestamp: , mac: nil)
|
37
|
+
super(status,protocol,port,reason,ttl,ip,timestamp,mac)
|
38
|
+
end
|
6
39
|
end
|
7
40
|
end
|
data/lib/masscan/version.rb
CHANGED
data/spec/parsers/binary_spec.rb
CHANGED
@@ -221,4 +221,508 @@ describe Masscan::Parsers::Binary do
|
|
221
221
|
end
|
222
222
|
end
|
223
223
|
end
|
224
|
+
|
225
|
+
describe ".parse_status" do
|
226
|
+
let(:timestamp) { 1629960470 }
|
227
|
+
let(:time) { Time.at(timestamp) }
|
228
|
+
|
229
|
+
let(:ipaddr) { IPAddr.new("1.2.3.4") }
|
230
|
+
let(:ip_uint) { ipaddr.to_i }
|
231
|
+
|
232
|
+
let(:ip_proto) { :tcp }
|
233
|
+
let(:ip_proto_uint) { described_class::IP_PROTOCOLS.invert[:tcp] }
|
234
|
+
|
235
|
+
let(:port) { 1111 }
|
236
|
+
|
237
|
+
let(:ttl) { 54 }
|
238
|
+
|
239
|
+
let(:reason) { [:syn, :ack] }
|
240
|
+
let(:reason_uint) { 0x02 | 0x10 }
|
241
|
+
|
242
|
+
let(:buffer) do
|
243
|
+
[
|
244
|
+
timestamp, ip_uint, port, reason_uint, ttl
|
245
|
+
].pack("L>L>S>CC")
|
246
|
+
end
|
247
|
+
|
248
|
+
let(:status) { :open }
|
249
|
+
|
250
|
+
subject { super().parse_status(buffer,status) }
|
251
|
+
|
252
|
+
context "when the buffer length is less than 12" do
|
253
|
+
let(:buffer) { "A" * 11 }
|
254
|
+
|
255
|
+
it "must return nil" do
|
256
|
+
expect(subject).to be(nil)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
it "must decode the timestamp field" do
|
261
|
+
expect(subject.timestamp).to eq(time)
|
262
|
+
end
|
263
|
+
|
264
|
+
it "must set #status" do
|
265
|
+
expect(subject.status).to eq(status)
|
266
|
+
end
|
267
|
+
|
268
|
+
it "must decode the ip field" do
|
269
|
+
expect(subject.ip).to eq(ipaddr)
|
270
|
+
end
|
271
|
+
|
272
|
+
context "when the port is 53" do
|
273
|
+
let(:port) { 53 }
|
274
|
+
let(:ip_proto) { :udp }
|
275
|
+
|
276
|
+
it "must default the ip_proto :udp" do
|
277
|
+
expect(subject.protocol).to eq(ip_proto)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
context "when the port is 123" do
|
282
|
+
let(:port) { 123 }
|
283
|
+
let(:ip_proto) { :udp }
|
284
|
+
|
285
|
+
it "must default the ip_proto :udp" do
|
286
|
+
expect(subject.protocol).to eq(ip_proto)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
context "when the port is 137" do
|
291
|
+
let(:port) { 137 }
|
292
|
+
let(:ip_proto) { :udp }
|
293
|
+
|
294
|
+
it "must default the ip_proto :udp" do
|
295
|
+
expect(subject.protocol).to eq(ip_proto)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context "when the port is 161" do
|
300
|
+
let(:port) { 161 }
|
301
|
+
let(:ip_proto) { :udp }
|
302
|
+
|
303
|
+
it "must default the ip_proto :udp" do
|
304
|
+
expect(subject.protocol).to eq(ip_proto)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
context "when the port is 36422" do
|
309
|
+
let(:port) { 36422 }
|
310
|
+
let(:ip_proto) { :sctp }
|
311
|
+
|
312
|
+
it "must default the ip_proto :sctp" do
|
313
|
+
expect(subject.protocol).to eq(ip_proto)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
context "when the port is 36412" do
|
318
|
+
let(:port) { 36412 }
|
319
|
+
let(:ip_proto) { :sctp }
|
320
|
+
|
321
|
+
it "must default the ip_proto :sctp" do
|
322
|
+
expect(subject.protocol).to eq(ip_proto)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context "when the port is 2905" do
|
327
|
+
let(:port) { 2905 }
|
328
|
+
let(:ip_proto) { :sctp }
|
329
|
+
|
330
|
+
it "must default the ip_proto :sctp" do
|
331
|
+
expect(subject.protocol).to eq(ip_proto)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
it "must default the ip_proto to :tcp" do
|
336
|
+
expect(subject.protocol).to eq(:tcp)
|
337
|
+
end
|
338
|
+
|
339
|
+
it "must decode the port field" do
|
340
|
+
expect(subject.port).to eq(port)
|
341
|
+
end
|
342
|
+
|
343
|
+
it "must decode the ttl field" do
|
344
|
+
expect(subject.ttl).to eq(ttl)
|
345
|
+
end
|
346
|
+
|
347
|
+
it "must decode the reason field" do
|
348
|
+
expect(subject.reason).to eq(reason)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
describe ".parser_banner3" do
|
353
|
+
let(:timestamp) { 1629960470 }
|
354
|
+
let(:time) { Time.at(timestamp) }
|
355
|
+
|
356
|
+
let(:ipaddr) { IPAddr.new("1.2.3.4") }
|
357
|
+
let(:ip_uint) { ipaddr.to_i }
|
358
|
+
|
359
|
+
let(:port) { 1111 }
|
360
|
+
|
361
|
+
let(:app_proto) { :html_title }
|
362
|
+
let(:app_proto_uint) do
|
363
|
+
described_class::APP_PROTOCOLS.index(app_proto)
|
364
|
+
end
|
365
|
+
|
366
|
+
let(:payload) { "404 - Not Found" }
|
367
|
+
|
368
|
+
let(:buffer) do
|
369
|
+
p([timestamp, ip_uint, port, app_proto_uint, payload]).pack("L>L>S>S>A*")
|
370
|
+
end
|
371
|
+
|
372
|
+
subject { super().parse_banner3(buffer) }
|
373
|
+
|
374
|
+
it "must default #ip_proto to :tcp" do
|
375
|
+
expect(subject.protocol).to eq(:tcp)
|
376
|
+
end
|
377
|
+
|
378
|
+
it "must default #ttl to 0" do
|
379
|
+
expect(subject.ttl).to eq(0)
|
380
|
+
end
|
381
|
+
|
382
|
+
it "must decode the port field" do
|
383
|
+
expect(subject.port).to eq(port)
|
384
|
+
end
|
385
|
+
|
386
|
+
it "must decode the ip field" do
|
387
|
+
expect(subject.ip).to eq(ipaddr)
|
388
|
+
end
|
389
|
+
|
390
|
+
it "must decode the timestamp field" do
|
391
|
+
expect(subject.timestamp).to eq(time)
|
392
|
+
end
|
393
|
+
|
394
|
+
it "must decode the app_proto field" do
|
395
|
+
expect(subject.app_protocol).to eq(app_proto)
|
396
|
+
end
|
397
|
+
|
398
|
+
it "must decode the payload field" do
|
399
|
+
expect(subject.payload).to eq(payload)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
describe ".parser_banner4" do
|
404
|
+
let(:timestamp) { 1629960470 }
|
405
|
+
let(:time) { Time.at(timestamp) }
|
406
|
+
|
407
|
+
let(:ipaddr) { IPAddr.new("1.2.3.4") }
|
408
|
+
let(:ip_uint) { ipaddr.to_i }
|
409
|
+
|
410
|
+
let(:ip_proto) { :tcp }
|
411
|
+
let(:ip_proto_uint) { described_class::IP_PROTOCOLS.invert[:tcp] }
|
412
|
+
|
413
|
+
let(:port) { 1111 }
|
414
|
+
|
415
|
+
let(:app_proto) { :html_title }
|
416
|
+
let(:app_proto_uint) do
|
417
|
+
described_class::APP_PROTOCOLS.index(app_proto)
|
418
|
+
end
|
419
|
+
|
420
|
+
let(:payload) { "404 - Not Found" }
|
421
|
+
|
422
|
+
let(:buffer) do
|
423
|
+
[
|
424
|
+
timestamp, ip_uint, ip_proto_uint, port, app_proto_uint, payload
|
425
|
+
].pack("L>L>CS>S>A*")
|
426
|
+
end
|
427
|
+
|
428
|
+
subject { super().parse_banner4(buffer) }
|
429
|
+
|
430
|
+
context "when the buffer length is less than 13" do
|
431
|
+
let(:buffer) { "A" * 12 }
|
432
|
+
|
433
|
+
it "must return nil" do
|
434
|
+
expect(subject).to be(nil)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
it "must decode the ip_proto field" do
|
439
|
+
expect(subject.protocol).to eq(:tcp)
|
440
|
+
end
|
441
|
+
|
442
|
+
it "must default #ttl to 0" do
|
443
|
+
expect(subject.ttl).to eq(0)
|
444
|
+
end
|
445
|
+
|
446
|
+
it "must decode the port field" do
|
447
|
+
expect(subject.port).to eq(port)
|
448
|
+
end
|
449
|
+
|
450
|
+
it "must decode the ip field" do
|
451
|
+
expect(subject.ip).to eq(ipaddr)
|
452
|
+
end
|
453
|
+
|
454
|
+
it "must decode the timestamp field" do
|
455
|
+
expect(subject.timestamp).to eq(time)
|
456
|
+
end
|
457
|
+
|
458
|
+
it "must decode the app_proto field" do
|
459
|
+
expect(subject.app_protocol).to eq(app_proto)
|
460
|
+
end
|
461
|
+
|
462
|
+
it "must decode the payload field" do
|
463
|
+
expect(subject.payload).to eq(payload)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
describe ".parse_status2" do
|
468
|
+
let(:timestamp) { 1629960470 }
|
469
|
+
let(:time) { Time.at(timestamp) }
|
470
|
+
|
471
|
+
let(:ipaddr) { IPAddr.new("1.2.3.4") }
|
472
|
+
let(:ip_uint) { ipaddr.to_i }
|
473
|
+
|
474
|
+
let(:ip_proto) { :tcp }
|
475
|
+
let(:ip_proto_uint) { described_class::IP_PROTOCOLS.invert[:tcp] }
|
476
|
+
|
477
|
+
let(:port) { 1111 }
|
478
|
+
|
479
|
+
let(:ttl) { 54 }
|
480
|
+
|
481
|
+
let(:reason) { [:syn, :ack] }
|
482
|
+
let(:reason_uint) { 0x02 | 0x10 }
|
483
|
+
|
484
|
+
let(:buffer) do
|
485
|
+
[
|
486
|
+
timestamp, ip_uint, ip_proto_uint, port, reason_uint, ttl
|
487
|
+
].pack("L>L>CS>CC")
|
488
|
+
end
|
489
|
+
|
490
|
+
let(:status) { :open }
|
491
|
+
|
492
|
+
subject { super().parse_status2(buffer,status) }
|
493
|
+
|
494
|
+
context "when the buffer length is less than 13" do
|
495
|
+
let(:buffer) { "A" * 12 }
|
496
|
+
|
497
|
+
it "must return nil" do
|
498
|
+
expect(subject).to be(nil)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
it "must decode the timestamp field" do
|
503
|
+
expect(subject.timestamp).to eq(time)
|
504
|
+
end
|
505
|
+
|
506
|
+
it "must set #status" do
|
507
|
+
expect(subject.status).to eq(status)
|
508
|
+
end
|
509
|
+
|
510
|
+
it "must decode the ip field" do
|
511
|
+
expect(subject.ip).to eq(ipaddr)
|
512
|
+
end
|
513
|
+
|
514
|
+
it "must decode the ip_proto field" do
|
515
|
+
expect(subject.protocol).to eq(ip_proto)
|
516
|
+
end
|
517
|
+
|
518
|
+
it "must decode the port field" do
|
519
|
+
expect(subject.port).to eq(port)
|
520
|
+
end
|
521
|
+
|
522
|
+
it "must decode the ttl field" do
|
523
|
+
expect(subject.ttl).to eq(ttl)
|
524
|
+
end
|
525
|
+
|
526
|
+
it "must decode the reason field" do
|
527
|
+
expect(subject.reason).to eq(reason)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
describe ".parser_banner9" do
|
532
|
+
let(:timestamp) { 1629960470 }
|
533
|
+
let(:time) { Time.at(timestamp) }
|
534
|
+
|
535
|
+
let(:ipaddr) { IPAddr.new("1.2.3.4") }
|
536
|
+
let(:ip_uint) { ipaddr.to_i }
|
537
|
+
|
538
|
+
let(:ip_proto) { :tcp }
|
539
|
+
let(:ip_proto_uint) { described_class::IP_PROTOCOLS.invert[:tcp] }
|
540
|
+
|
541
|
+
let(:port) { 1111 }
|
542
|
+
|
543
|
+
let(:app_proto) { :html_title }
|
544
|
+
let(:app_proto_uint) do
|
545
|
+
described_class::APP_PROTOCOLS.index(app_proto)
|
546
|
+
end
|
547
|
+
|
548
|
+
let(:ttl) { 54 }
|
549
|
+
|
550
|
+
let(:payload) { "404 - Not Found" }
|
551
|
+
|
552
|
+
let(:buffer) do
|
553
|
+
[
|
554
|
+
timestamp, ip_uint, ip_proto_uint, port, app_proto_uint, ttl, payload
|
555
|
+
].pack("L>L>CS>S>CA*")
|
556
|
+
end
|
557
|
+
|
558
|
+
subject { super().parse_banner9(buffer) }
|
559
|
+
|
560
|
+
context "when the buffer length is less than 14" do
|
561
|
+
let(:buffer) { "A" * 13 }
|
562
|
+
|
563
|
+
it "must return nil" do
|
564
|
+
expect(subject).to be(nil)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
it "must decode the ip_proto field" do
|
569
|
+
expect(subject.protocol).to eq(:tcp)
|
570
|
+
end
|
571
|
+
|
572
|
+
it "must decode the ttl field" do
|
573
|
+
expect(subject.ttl).to eq(ttl)
|
574
|
+
end
|
575
|
+
|
576
|
+
it "must decode the port field" do
|
577
|
+
expect(subject.port).to eq(port)
|
578
|
+
end
|
579
|
+
|
580
|
+
it "must decode the ip field" do
|
581
|
+
expect(subject.ip).to eq(ipaddr)
|
582
|
+
end
|
583
|
+
|
584
|
+
it "must decode the timestamp field" do
|
585
|
+
expect(subject.timestamp).to eq(time)
|
586
|
+
end
|
587
|
+
|
588
|
+
it "must decode the app_proto field" do
|
589
|
+
expect(subject.app_protocol).to eq(app_proto)
|
590
|
+
end
|
591
|
+
|
592
|
+
it "must decode the payload field" do
|
593
|
+
expect(subject.payload).to eq(payload)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
describe ".parse_status6" do
|
598
|
+
let(:timestamp) { 1629960470 }
|
599
|
+
let(:time) { Time.at(timestamp) }
|
600
|
+
|
601
|
+
let(:ipaddr) { IPAddr.new("2606:2800:220:1:248:1893:25c8:1946") }
|
602
|
+
let(:ip_uint) { ipaddr.to_i }
|
603
|
+
let(:ipv6_hi) { (ip_uint & (0xffffffff_ffffffff << 64)) >> 64 }
|
604
|
+
let(:ipv6_lo) { (ip_uint & 0xffffffff_ffffffff) }
|
605
|
+
|
606
|
+
let(:ip_version) { 6 }
|
607
|
+
|
608
|
+
let(:ip_proto) { :tcp }
|
609
|
+
let(:ip_proto_uint) { described_class::IP_PROTOCOLS.invert[:tcp] }
|
610
|
+
|
611
|
+
let(:port) { 1111 }
|
612
|
+
|
613
|
+
let(:ttl) { 54 }
|
614
|
+
|
615
|
+
let(:reason) { [:syn, :ack] }
|
616
|
+
let(:reason_uint) { 0x02 | 0x10 }
|
617
|
+
|
618
|
+
let(:buffer) do
|
619
|
+
[
|
620
|
+
timestamp, ip_proto_uint, port, reason_uint, ttl, ip_version, ipv6_hi, ipv6_lo
|
621
|
+
].pack("L>CS>CCCQ>Q>")
|
622
|
+
end
|
623
|
+
|
624
|
+
let(:status) { :open }
|
625
|
+
|
626
|
+
subject { super().parse_status6(buffer,status) }
|
627
|
+
|
628
|
+
context "if the ip_version is not 6" do
|
629
|
+
let(:ip_version) { 9 }
|
630
|
+
|
631
|
+
it do
|
632
|
+
expect {
|
633
|
+
described_class.parse_status6(buffer,status)
|
634
|
+
}.to raise_error(described_class::CorruptedFile,"expected ip_version to be 6: #{ip_version.inspect}")
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
it "must decode the timestamp field" do
|
639
|
+
expect(subject.timestamp).to eq(time)
|
640
|
+
end
|
641
|
+
|
642
|
+
it "must set #status" do
|
643
|
+
expect(subject.status).to eq(status)
|
644
|
+
end
|
645
|
+
|
646
|
+
it "must decode the ip field" do
|
647
|
+
expect(subject.ip).to eq(ipaddr)
|
648
|
+
end
|
649
|
+
|
650
|
+
it "must decode the ip_proto field" do
|
651
|
+
expect(subject.protocol).to eq(ip_proto)
|
652
|
+
end
|
653
|
+
|
654
|
+
it "must decode the port field" do
|
655
|
+
expect(subject.port).to eq(port)
|
656
|
+
end
|
657
|
+
|
658
|
+
it "must decode the ttl field" do
|
659
|
+
expect(subject.ttl).to eq(ttl)
|
660
|
+
end
|
661
|
+
|
662
|
+
it "must decode the reason field" do
|
663
|
+
expect(subject.reason).to eq(reason)
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
describe ".parser_banner6" do
|
668
|
+
let(:timestamp) { 1629960470 }
|
669
|
+
let(:time) { Time.at(timestamp) }
|
670
|
+
|
671
|
+
let(:ipaddr) { IPAddr.new("2606:2800:220:1:248:1893:25c8:1946") }
|
672
|
+
let(:ip_uint) { ipaddr.to_i }
|
673
|
+
let(:ipv6_hi) { (ip_uint & (0xffffffff_ffffffff << 64)) >> 64 }
|
674
|
+
let(:ipv6_lo) { (ip_uint & 0xffffffff_ffffffff) }
|
675
|
+
|
676
|
+
let(:ip_version) { 6 }
|
677
|
+
|
678
|
+
let(:ip_proto) { :tcp }
|
679
|
+
let(:ip_proto_uint) { described_class::IP_PROTOCOLS.invert[:tcp] }
|
680
|
+
|
681
|
+
let(:port) { 1111 }
|
682
|
+
|
683
|
+
let(:app_proto) { :html_title }
|
684
|
+
let(:app_proto_uint) do
|
685
|
+
described_class::APP_PROTOCOLS.index(app_proto)
|
686
|
+
end
|
687
|
+
|
688
|
+
let(:ttl) { 54 }
|
689
|
+
|
690
|
+
let(:payload) { "404 - Not Found" }
|
691
|
+
|
692
|
+
let(:buffer) do
|
693
|
+
[
|
694
|
+
timestamp, ip_proto_uint, port, app_proto_uint, ttl, ip_version, ipv6_hi, ipv6_lo, payload
|
695
|
+
].pack("L>CS>S>CCQ>Q>A*")
|
696
|
+
end
|
697
|
+
|
698
|
+
subject { super().parse_banner6(buffer) }
|
699
|
+
|
700
|
+
it "must decode the ip_proto field" do
|
701
|
+
expect(subject.protocol).to eq(:tcp)
|
702
|
+
end
|
703
|
+
|
704
|
+
it "must decode the ttl field" do
|
705
|
+
expect(subject.ttl).to eq(ttl)
|
706
|
+
end
|
707
|
+
|
708
|
+
it "must decode the port field" do
|
709
|
+
expect(subject.port).to eq(port)
|
710
|
+
end
|
711
|
+
|
712
|
+
it "must decode the ip field" do
|
713
|
+
expect(subject.ip).to eq(ipaddr)
|
714
|
+
end
|
715
|
+
|
716
|
+
it "must decode the timestamp field" do
|
717
|
+
expect(subject.timestamp).to eq(time)
|
718
|
+
end
|
719
|
+
|
720
|
+
it "must decode the app_proto field" do
|
721
|
+
expect(subject.app_protocol).to eq(app_proto)
|
722
|
+
end
|
723
|
+
|
724
|
+
it "must decode the payload field" do
|
725
|
+
expect(subject.payload).to eq(payload)
|
726
|
+
end
|
727
|
+
end
|
224
728
|
end
|
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.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rprogram
|