ruby-masscan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ require 'rspec'
2
+
3
+ shared_examples_for "Parser.open" do
4
+ context "when not given a block" do
5
+ it "must return the opened file" do
6
+ file = subject.open(path)
7
+
8
+ expect(file).to be_kind_of(File)
9
+ expect(file.closed?).to be(false)
10
+ end
11
+ end
12
+
13
+ context "when given a block" do
14
+ it "must yield the opened file" do
15
+ file_class = nil
16
+ file_opened = nil
17
+
18
+ subject.open(path) do |file|
19
+ file_class = file.class
20
+ file_opened = !file.closed?
21
+ end
22
+
23
+ expect(file_class).to be(File)
24
+ expect(file_opened).to be(true)
25
+ end
26
+ end
27
+ end
28
+
29
+ shared_examples_for "Parser.parse" do
30
+ context "when given a block" do
31
+ it "must yield Masscan::Status and Masscan::Banner objects" do
32
+ yielded_record_classes = []
33
+
34
+ subject.parse(io) do |record|
35
+ yielded_record_classes << record.class
36
+ end
37
+
38
+ expect(yielded_record_classes.uniq).to eq([
39
+ Masscan::Status,
40
+ Masscan::Banner
41
+ ])
42
+ end
43
+ end
44
+
45
+ context "when given no block" do
46
+ let(:expected_records) do
47
+ [].tap do |yielded_records|
48
+ subject.parse(subject.open(path)) do |record|
49
+ yielded_records << record
50
+ end
51
+ end
52
+ end
53
+
54
+ it "must return an Enumerator" do
55
+ expect(subject.parse(io).to_a).to eq(expected_records)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+ require 'masscan/parsers/plain_text'
3
+
4
+ describe Masscan::Parsers::PlainText do
5
+ module TestPlainText
6
+ extend Masscan::Parsers::PlainText
7
+ end
8
+
9
+ subject { TestPlainText }
10
+
11
+ describe "#parse_status" do
12
+ context "when given 'open'" do
13
+ it "must return :open" do
14
+ expect(subject.parse_status("open")).to be(:open)
15
+ end
16
+ end
17
+
18
+ context "when given 'closed'" do
19
+ it "must return :closed" do
20
+ expect(subject.parse_status("closed")).to be(:closed)
21
+ end
22
+ end
23
+
24
+ context "when given an unknown String" do
25
+ it "must return the String" do
26
+ expect(subject.parse_status("foo")).to eq("foo")
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "#parse_reason" do
32
+ context "when given one flag" do
33
+ it "must map it to a keyword and return an Array" do
34
+ expect(subject.parse_reason("rst")).to eq([:rst])
35
+ end
36
+ end
37
+
38
+ context "when given multiple flags" do
39
+ it "must split them and map them to keyword" do
40
+ expect(subject.parse_reason("syn-ack")).to eq([:syn, :ack])
41
+ end
42
+ end
43
+
44
+ context "when given an unknown String" do
45
+ it "must return the String" do
46
+ expect(subject.parse_reason("foo")).to eq(["foo"])
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#parse_ip_protocol" do
52
+ context "when given 'tcp'" do
53
+ it "must return :tcp" do
54
+ expect(subject.parse_ip_protocol("tcp")).to be(:tcp)
55
+ end
56
+ end
57
+
58
+ context "when given 'udp'" do
59
+ it "must return :udp" do
60
+ expect(subject.parse_ip_protocol("udp")).to be(:udp)
61
+ end
62
+ end
63
+
64
+ context "when given 'icmp'" do
65
+ it "must return :icmp" do
66
+ expect(subject.parse_ip_protocol("icmp")).to be(:icmp)
67
+ end
68
+ end
69
+
70
+ context "when given 'sctp'" do
71
+ it "must return :sctp" do
72
+ expect(subject.parse_ip_protocol("sctp")).to be(:sctp)
73
+ end
74
+ end
75
+
76
+ context "when given an unknown String" do
77
+ it "must return the String" do
78
+ expect(subject.parse_ip_protocol("foo")).to eq("foo")
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#parse_app_protocol" do
84
+ described_class::APP_PROTOCOLS.each do |string,keyword|
85
+ context "when given '#{string}'" do
86
+ it "must return #{keyword.inspect}" do
87
+ expect(subject.parse_app_protocol(string)).to be(keyword)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "when given an unknown String" do
93
+ it "must return the String" do
94
+ expect(subject.parse_app_protocol("foo")).to eq("foo")
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#parse_timestamp" do
100
+ let(:timestamp) { 1629960470 }
101
+ let(:time) { Time.at(timestamp) }
102
+
103
+ it "must parse a given UNIX timestamp and return a Time object" do
104
+ expect(subject.parse_timestamp(timestamp)).to eq(time)
105
+ end
106
+ end
107
+
108
+ describe "#parse_ip" do
109
+ let(:ip_string) { "1.2.3.4" }
110
+ let(:ip_addr) { IPAddr.new(ip_string) }
111
+
112
+ it "must parse a given IP string and return an IPAddr" do
113
+ expect(subject.parse_ip(ip_string)).to eq(ip_addr)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ module Fixtures
6
+ DIR = File.join(__dir__,'fixtures')
7
+
8
+ def self.join(*names)
9
+ File.join(DIR,*names)
10
+ end
11
+ end
data/spec/task_spec.rb ADDED
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+ require 'masscan/task'
3
+
4
+ describe Masscan::Task do
5
+ describe "#ports=" do
6
+ context "when given an empty Array" do
7
+ before { subject.ports = [] }
8
+
9
+ it "should ignore empty port Arrays" do
10
+ subject.ports = []
11
+
12
+ expect(subject.arguments).to eq([])
13
+ end
14
+ end
15
+
16
+ context "when given a String" do
17
+ let(:ports) { '80,21,25' }
18
+
19
+ before { subject.ports = ports }
20
+
21
+ it "should emit the String as is" do
22
+ expect(subject.arguments).to eq(['-p', ports])
23
+ end
24
+ end
25
+
26
+ context "when given an Array of Strings" do
27
+ let(:ports) { %w[80 21 25] }
28
+
29
+ before { subject.ports = ports }
30
+
31
+ it "should format an Array of String ports" do
32
+ expect(subject.arguments).to eq(['-p', ports.join(',')])
33
+ end
34
+ end
35
+
36
+ context "when given an Array of Integers" do
37
+ let(:ports) { [80, 21, 25] }
38
+
39
+ before { subject.ports = ports }
40
+
41
+ it "should format an Array of Integer ports" do
42
+ expect(subject.arguments).to eq(['-p', ports.join(',')])
43
+ end
44
+ end
45
+
46
+ context "when given an Array containing a Range" do
47
+ let(:ports) { [80, 21..25] }
48
+
49
+ before { subject.ports = ports }
50
+
51
+ it "should format the Range" do
52
+ expect(subject.arguments).to eq([
53
+ '-p', "#{ports[0]},#{ports[1].begin}-#{ports[1].end}"
54
+ ])
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#shards=" do
60
+ context "when given a Rational value" do
61
+ let(:rational) { (1/2r) }
62
+
63
+ before { subject.shards = rational }
64
+
65
+ it "must format it into \#{numerator}/\#{denominator}" do
66
+ expect(subject.arguments).to eq([
67
+ "--shards", "#{rational.numerator}/#{rational.denominator}"
68
+ ])
69
+ end
70
+ end
71
+
72
+ context "when given an Array value" do
73
+ let(:array) { [1, 2] }
74
+
75
+ before { subject.shards = array }
76
+
77
+ it "must format it into \#{array[0]}/\#{array[1]}" do
78
+ expect(subject.arguments).to eq([
79
+ "--shards", "#{array[0]}/#{array[1]}"
80
+ ])
81
+ end
82
+
83
+ context "but the Array length is > 2" do
84
+ let(:array) { [1,2,3] }
85
+
86
+ before { subject.shards = array }
87
+
88
+ it do
89
+ expect {
90
+ subject.arguments
91
+ }.to raise_error(ArgumentError,"#{described_class}#shards= does not accept more than two values")
92
+ end
93
+ end
94
+ end
95
+
96
+ context "otherwise" do
97
+ let(:object) { :"1/2" }
98
+
99
+ before { subject.shards = object }
100
+
101
+ it "must convert the value to a String" do
102
+ expect(subject.arguments).to eq([
103
+ "--shards", object.to_s
104
+ ])
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "#http_field=" do
110
+ let(:name) { 'X-Foo' }
111
+ let(:value) { 'bar' }
112
+
113
+ before { subject.http_field = [ [name, value] ] }
114
+
115
+ it "must join two values together with a ':'" do
116
+ expect(subject.arguments).to eq([
117
+ "--http-field", "#{name}:#{value}"
118
+ ])
119
+ end
120
+ end
121
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-masscan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rprogram
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ description: A Ruby interface to masscan, an Internet-scale port scanner. Allows automating
42
+ masscan and parsing masscan Binary, List, JSON, and output file formats.
43
+ email: postmodern.mod3@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files:
47
+ - ChangeLog.md
48
+ - LICENSE.txt
49
+ - README.md
50
+ files:
51
+ - ".document"
52
+ - ".editorconfig"
53
+ - ".github/workflows/ruby.yml"
54
+ - ".gitignore"
55
+ - ".rspec"
56
+ - ".yardopts"
57
+ - ChangeLog.md
58
+ - Gemfile
59
+ - LICENSE.txt
60
+ - README.md
61
+ - Rakefile
62
+ - gemspec.yml
63
+ - lib/masscan.rb
64
+ - lib/masscan/banner.rb
65
+ - lib/masscan/output_file.rb
66
+ - lib/masscan/parsers.rb
67
+ - lib/masscan/parsers/binary.rb
68
+ - lib/masscan/parsers/json.rb
69
+ - lib/masscan/parsers/list.rb
70
+ - lib/masscan/parsers/plain_text.rb
71
+ - lib/masscan/program.rb
72
+ - lib/masscan/status.rb
73
+ - lib/masscan/task.rb
74
+ - lib/masscan/version.rb
75
+ - ruby-masscan.gemspec
76
+ - spec/fixtures/masscan.bin
77
+ - spec/fixtures/masscan.json
78
+ - spec/fixtures/masscan.list
79
+ - spec/fixtures/masscan.ndjson
80
+ - spec/fixtures/masscan.xml
81
+ - spec/output_file_spec.rb
82
+ - spec/parsers/binary_spec.rb
83
+ - spec/parsers/json_spec.rb
84
+ - spec/parsers/list_spec.rb
85
+ - spec/parsers/parser_examples.rb
86
+ - spec/parsers/plain_text_spec.rb
87
+ - spec/spec_helper.rb
88
+ - spec/task_spec.rb
89
+ homepage: https://github.com/postmodern/ruby-masscan#readme
90
+ licenses:
91
+ - MIT
92
+ metadata:
93
+ documentation_uri: https://rubydoc.info/gems/ruby-masscan
94
+ source_code_uri: https://github.com/postmodern/ruby-masscan
95
+ bug_tracker_uri: https://github.com/postmodern/ruby-masscan/issues
96
+ changelog_uri: https://github.com/postmodern/ruby-masscan/blob/master/ChangeLog.md
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: 2.0.0
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements:
112
+ - masscan >= 1.0.0
113
+ rubygems_version: 3.2.22
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: A Ruby interface to masscan.
117
+ test_files: []