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,7 @@
1
+ module Masscan
2
+ #
3
+ # Represents a port status record.
4
+ #
5
+ class Status < Struct.new(:status,:protocol,:port,:reason,:ttl,:ip,:timestamp,:mac)
6
+ end
7
+ end
@@ -0,0 +1,179 @@
1
+ require 'rprogram/task'
2
+
3
+ module Masscan
4
+ #
5
+ # ## `masscan` options:
6
+ #
7
+ # * `--range` - `masscan.range`
8
+ # * `-p` - `masscan.ports`
9
+ # * `--banners` - `masscan.banners`
10
+ # * `--rate` - `masscan.rate`
11
+ # * `--conf` - `masscan.config_file`
12
+ # * `--resume` - `masscan.resume`
13
+ # * `--echo` - `masscan.echo`
14
+ # * `--adapter` - `masscan.adapter`
15
+ # * `--adapter-ip` - `masscan.adapter_ip`
16
+ # * `--adapter-port` - `masscan.adapter_port`
17
+ # * `--adapter-mac` - `masscan.adapter_mac`
18
+ # * `--adapter-vlan` - `masscan.adapter_vlan`
19
+ # * `--router-mac` - `masscan.router_mac`
20
+ # * `--ping` - `masscan.ping`
21
+ # * `--exclude` - `masscan.exclude`
22
+ # * `--excludefile` - `masscan.exclude_file`
23
+ # * `--includefile` - `masscan.include_file`
24
+ # * `--append-output` - `masscan.append_output`
25
+ # * `--iflist` - `masscan.list_interfaces`
26
+ # * `--retries` - `masscan.retries`
27
+ # * `--nmap` - `masscan.nmap_help`
28
+ # * `--pcap-payloads` - `masscan.pcap_payloads`
29
+ # * `--nmap-payloads` - `masscan.nmap_payloads`
30
+ # * `--http-method` - `masscan.http_method`
31
+ # * `--http-url` - `masscan.http_url`
32
+ # * `--http-version` - `masscan.http_version`
33
+ # * `--http-host` - `masscan.http_host`
34
+ # * `--http-user-agent` - `masscan.http_user_agent`
35
+ # * `--http-field` - `masscan.http_field`
36
+ # * `--http-field-remove` - `masscan.http_field_remove`
37
+ # * `--http-cookie` - `masscan.http_cookie`
38
+ # * `--http-payload` - `masscan.http_payload`
39
+ # * `--show` - `masscan.show`
40
+ # * `--noshow` - `masscan.hide`
41
+ # * `--pcap` - `masscan.pcap`
42
+ # * `--packet-trace` - `masscan.packet_trace`
43
+ # * `--pfring` - `masscan.pfring`
44
+ # * `--resume-index` - `masscan.resume_index`
45
+ # * `--resume-count` - `masscan.resume_count`
46
+ # * `--shards` - `masscan.shards`
47
+ # * `--rotate` - `masscan.rotate`
48
+ # * `--rotate-offset` - `masscan.rotate_offset`
49
+ # * `--rotate-size` - `masscan.rotate_size`
50
+ # * `--rotate-dir` - `masscan.rotate_dir`
51
+ # * `--seed` - `masscan.seed`
52
+ # * `--regress` - `masscan.regress`
53
+ # * `--ttl` - `masscan.ttl`
54
+ # * `--wait` - `masscan.wait`
55
+ # * `--offline` - `masscan.offline`
56
+ # * `-sL` - `masscan.print_list`
57
+ # * `--interactive` - `masscan.interactive`
58
+ # * `--output-format` - `masscan.output_format`
59
+ # * `--output-filename` - `masscan.output_file`
60
+ # * `-oB` - `masscan.output_binary`
61
+ # * `-oX` - `masscan.output_xml`
62
+ # * `-oG` - `masscan.output_grepable`
63
+ # * ` -oJ` - `masscan.output_json`
64
+ # * `-oL` - `masscan.output_list`
65
+ # * `--readscan` - `masscan.read_scan`
66
+ # * `-V` - `masscan.version`
67
+ # * `-h` - `masscan.help`
68
+ #
69
+ # @see https://github.com/robertdavidgraham/masscan/blob/master/doc/masscan.8.markdown
70
+ #
71
+ class Task < RProgram::Task
72
+
73
+ long_option flag: '--range', name: :range, separator: ','
74
+ short_option flag: '-p', name: :ports do |opt,value|
75
+ unless value.empty?
76
+ [opt.flag, format_port_list(value)]
77
+ end
78
+ end
79
+ long_option flag: '--banners', name: :banners
80
+ long_option flag: '--rate', name: :rate
81
+ long_option flag: '--conf', name: :config_file
82
+ long_option flag: '--resume', name: :resume
83
+ long_option flag: '--echo', name: :echo
84
+ long_option flag: '--adapter', name: :adapter
85
+ long_option flag: '--adapter-ip', name: :adapter_ip
86
+ long_option flag: '--adapter-port', name: :adapter_port
87
+ long_option flag: '--adapter-mac', name: :adapter_mac
88
+ long_option flag: '--adapter-vlan', name: :adapter_vlan
89
+ long_option flag: '--router-mac', name: :router_mac
90
+ long_option flag: '--ping', name: :ping
91
+ long_option flag: '--exclude', name: :exclude, separator: ','
92
+ long_option flag: '--excludefile', name: :exclude_file
93
+ long_option flag: '--includefile', name: :include_file
94
+ long_option flag: '--append-output', name: :append_output
95
+ long_option flag: '--iflist', name: :list_interfaces
96
+ long_option flag: '--retries', name: :retries
97
+ long_option flag: '--nmap', name: :nmap_help
98
+ long_option flag: '--pcap-payloads', name: :pcap_payloads
99
+ long_option flag: '--nmap-payloads', name: :nmap_payloads
100
+
101
+ long_option flag: '--http-method', name: :http_method
102
+ long_option flag: '--http-url', name: :http_url
103
+ long_option flag: '--http-version', name: :http_version
104
+ long_option flag: '--http-host', name: :http_host
105
+ long_option flag: '--http-user-agent', name: :http_user_agent
106
+
107
+ long_option flag: '--http-field', multiple: true do |opt,value|
108
+ name, value = value.first
109
+
110
+ [opt.flag, "#{name}:#{value}"]
111
+ end
112
+
113
+ long_option flag: '--http-field-remove', name: :http_field_remove
114
+ long_option flag: '--http-cookie', name: :http_cookie
115
+ long_option flag: '--http-payload', name: :http_payload
116
+
117
+ long_option flag: '--show', name: :show
118
+ long_option flag: '--noshow', name: :hide
119
+ long_option flag: '--pcap', name: :pcap
120
+ long_option flag: '--packet-trace', name: :packet_trace
121
+ long_option flag: '--pfring', name: :pfring
122
+ long_option flag: '--resume-index', name: :resume_index
123
+ long_option flag: '--resume-count', name: :resume_count
124
+ long_option flag: '--shards', name: :shards do |opt,value|
125
+ case value.length
126
+ when 2 then [opt.flag, "#{value[0]}/#{value[1]}"]
127
+ when 1 then [opt.flag, "#{value[0]}"]
128
+ else
129
+ raise(ArgumentError,"#{self}#shards= does not accept more than two values")
130
+ end
131
+ end
132
+ long_option flag: '--rotate', name: :rotate
133
+ long_option flag: '--rotate-offset', name: :rotate_offset
134
+ long_option flag: '--rotate-size', name: :rotate_size
135
+ long_option flag: '--rotate-dir', name: :rotate_dir
136
+ long_option flag: '--seed', name: :seed
137
+ long_option flag: '--regress', name: :regress
138
+ long_option flag: '--ttl', name: :ttl
139
+ long_option flag: '--wait', name: :wait
140
+ long_option flag: '--offline', name: :offline
141
+ short_option flag: '-sL', name: :print_list
142
+ long_option flag: '--interactive', name: :interactive
143
+ long_option flag: '--output-format', name: :output_format
144
+ long_option flag: '--output-filename', name: :output_file
145
+ short_option flag: '-oB', name: :output_binary
146
+ short_option flag: '-oX', name: :output_xml
147
+ short_option flag: '-oG', name: :output_grepable
148
+ short_option flag:' -oJ', name: :output_json
149
+ short_option flag: '-oL', name: :output_list
150
+ long_option flag: '--readscan', name: :read_scan
151
+ short_option :flag => '-V', :name => :version
152
+ short_option :flag => '-h', :name => :help
153
+
154
+ non_option :tailing => true, :name => :ips
155
+
156
+ private
157
+
158
+ #
159
+ # Formats a port list.
160
+ #
161
+ # @param [Array<Integer,Range>] ports
162
+ # The port ranges.
163
+ #
164
+ # @return [String]
165
+ # Comma separated string.
166
+ #
167
+ def self.format_port_list(ports)
168
+ ports.map { |port|
169
+ case port
170
+ when Range
171
+ "#{port.first}-#{port.last}"
172
+ else
173
+ port.to_s
174
+ end
175
+ }.join(',')
176
+ end
177
+
178
+ end
179
+ end
@@ -0,0 +1,4 @@
1
+ module Masscan
2
+ # ruby-masscan version
3
+ VERSION = '0.1.0'
4
+ end
data/lib/masscan.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'masscan/program'
2
+ require 'masscan/output_file'
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'masscan/version'
14
+ Masscan::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = Array(gemspec['requirements'])
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
53
+ end
54
+ end
55
+
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
Binary file
@@ -0,0 +1,17 @@
1
+ [
2
+ { "ip": "93.184.216.34", "timestamp": "1629960621", "ports": [ {"port": 80, "proto": "tcp", "status": "open", "reason": "syn-ack", "ttl": 54} ] }
3
+ ,
4
+ { "ip": "93.184.216.34", "timestamp": "1629960621", "ports": [ {"port": 443, "proto": "tcp", "status": "open", "reason": "syn-ack", "ttl": 54} ] }
5
+ ,
6
+ { "ip": "93.184.216.34", "timestamp": "1629960622", "ports": [ {"port": 0, "proto": "icmp", "status": "open", "reason": "none", "ttl": 54} ] }
7
+ ,
8
+ { "ip": "93.184.216.34", "timestamp": "1629960624", "ports": [ {"port": 80, "proto": "tcp", "service": {"name": "http.server", "banner": "ECS (sec/974D)"} } ] }
9
+ ,
10
+ { "ip": "93.184.216.34", "timestamp": "1629960624", "ports": [ {"port": 80, "proto": "tcp", "service": {"name": "title", "banner": "404 - Not Found"} } ] }
11
+ ,
12
+ { "ip": "93.184.216.34", "timestamp": "1629960624", "ports": [ {"port": 80, "proto": "tcp", "service": {"name": "http", "banner": "HTTP/1.0 404 Not Found\u000d\u000aContent-Type: text/html\u000d\u000aDate: Thu, 26 Aug 2021 06:50:24 GMT\u000d\u000aServer: ECS (sec/974D)\u000d\u000aContent-Length: 345\u000d\u000aConnection: close\u000d\u000a\u000d"} } ] }
13
+ ,
14
+ { "ip": "93.184.216.34", "timestamp": "1629960633", "ports": [ {"port": 443, "proto": "tcp", "service": {"name": "ssl", "banner": "TLS/1.1 cipher:0xc013, www.example.org, www.example.org, example.com, example.edu, example.net, example.org, www.example.com, www.example.edu, www.example.net"} } ] }
15
+ ,
16
+ { "ip": "93.184.216.34", "timestamp": "1629960633", "ports": [ {"port": 443, "proto": "tcp", "service": {"name": "X509", "banner": "MIIG1TCCBb2gAwIBAgIQD74IsIVNBXOKsMzhya/uyTANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBEaWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMDExMjQwMDAwMDBaFw0yMTEyMjUyMzU5NTlaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxPDA6BgNVBAoTM0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEYMBYGA1UEAxMPd3d3LmV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuvzuzMoKCP8Okx2zvgucA5YinrFPEK5RQP1TX7PEYUAoBO6i5hIAsIKFmFxtW2sghERilU5rdnxQcF3fEx3sY4OtY6VSBPLPhLrbKozHLrQ8ZN/rYTb+hgNUeT7NA1mP78IEkxAj4qG5tli4Jq41aCbUlCt7equGXokImhC+UY5IpQEZS0tKD4vu2ksZ04Qetp0k8jWdAvMA27W3EwgHHNeVGWbJPC0Dn7RqPw13r7hFyS5TpleywjdY1nB7ad6kcZXZbEcaFZ7ZuerA6RkPGE+PsnZRb1oFJkYoXimsuvkVFhWeHQXCGC1cuDWSrM3cpQvOzKH2vS7d15+zGls4IwIDAQABo4IDaTCCA2UwHwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFCYa+OSxsHKEztqBBtInmPvtOj0XMIGBBgNVHREEejB4gg93d3cuZXhhbXBsZS5vcmeCC2V4YW1wbGUuY29tggtleGFtcGxlLmVkdYILZXhhbXBsZS5uZXSCC2V4YW1wbGUub3Jngg93d3cuZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmVkdYIPd3d3LmV4YW1wbGUubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgYsGA1UdHwSBgzCBgDA+oDygOoY4aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS5jcmwwPqA8oDqGOGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv"} } ] }
17
+ ]
@@ -0,0 +1,10 @@
1
+ #masscan
2
+ open tcp 443 93.184.216.34 1629960470
3
+ open tcp 80 93.184.216.34 1629960470
4
+ open icmp 0 93.184.216.34 1629960470
5
+ banner tcp 443 93.184.216.34 1629960472 ssl TLS/1.1 cipher:0xc013, www.example.org, www.example.org, example.com, example.edu, example.net, example.org, www.example.com, www.example.edu, www.example.net
6
+ banner tcp 443 93.184.216.34 1629960472 X509 MIIG1TCCBb2gAwIBAgIQD74IsIVNBXOKsMzhya/uyTANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBEaWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMDExMjQwMDAwMDBaFw0yMTEyMjUyMzU5NTlaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxPDA6BgNVBAoTM0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEYMBYGA1UEAxMPd3d3LmV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuvzuzMoKCP8Okx2zvgucA5YinrFPEK5RQP1TX7PEYUAoBO6i5hIAsIKFmFxtW2sghERilU5rdnxQcF3fEx3sY4OtY6VSBPLPhLrbKozHLrQ8ZN/rYTb+hgNUeT7NA1mP78IEkxAj4qG5tli4Jq41aCbUlCt7equGXokImhC+UY5IpQEZS0tKD4vu2ksZ04Qetp0k8jWdAvMA27W3EwgHHNeVGWbJPC0Dn7RqPw13r7hFyS5TpleywjdY1nB7ad6kcZXZbEcaFZ7ZuerA6RkPGE+PsnZRb1oFJkYoXimsuvkVFhWeHQXCGC1cuDWSrM3cpQvOzKH2vS7d15+zGls4IwIDAQABo4IDaTCCA2UwHwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFCYa+OSxsHKEztqBBtInmPvtOj0XMIGBBgNVHREEejB4gg93d3cuZXhhbXBsZS5vcmeCC2V4YW1wbGUuY29tggtleGFtcGxlLmVkdYILZXhhbXBsZS5uZXSCC2V4YW1wbGUub3Jngg93d3cuZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmVkdYIPd3d3LmV4YW1wbGUubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgYsGA1UdHwSBgzCBgDA+oDygOoY4aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS5jcmwwPqA8oDqGOGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv
7
+ banner tcp 80 93.184.216.34 1629960472 http.server ECS (sec/974D)
8
+ banner tcp 80 93.184.216.34 1629960472 title 404 - Not Found
9
+ banner tcp 80 93.184.216.34 1629960472 http HTTP/1.0 404 Not Found\x0d\x0aContent-Type: text/html\x0d\x0aDate: Thu, 26 Aug 2021 06:47:52 GMT\x0d\x0aServer: ECS (sec/974D)\x0d\x0aContent-Length: 345\x0d\x0aConnection: close\x0d\x0a\x0d
10
+ # end
@@ -0,0 +1,8 @@
1
+ {"ip":"93.184.216.34","timestamp":"1630156508","port":80,"proto":"tcp","rec_type":"status","data":{"status":"open","reason":"syn-ack","ttl":54}}
2
+ {"ip":"93.184.216.34","timestamp":"1630156508","port":0,"proto":"icmp","rec_type":"status","data":{"status":"open","reason":"none","ttl":54}}
3
+ {"ip":"93.184.216.34","timestamp":"1630156508","port":443,"proto":"tcp","rec_type":"status","data":{"status":"open","reason":"syn-ack","ttl":54}}
4
+ {"ip":"93.184.216.34","timestamp":"1630156512","port":443,"proto":"tcp","rec_type":"banner","data":{"service_name":"ssl","banner":"TLS/1.1 cipher:0xc013, www.example.org, www.example.org, example.com, example.edu, example.net, example.org, www.example.com, www.example.edu, www.example.net"}}
5
+ {"ip":"93.184.216.34","timestamp":"1630156512","port":443,"proto":"tcp","rec_type":"banner","data":{"service_name":"X509","banner":"MIIG1TCCBb2gAwIBAgIQD74IsIVNBXOKsMzhya/uyTANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBEaWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMDExMjQwMDAwMDBaFw0yMTEyMjUyMzU5NTlaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxPDA6BgNVBAoTM0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEYMBYGA1UEAxMPd3d3LmV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuvzuzMoKCP8Okx2zvgucA5YinrFPEK5RQP1TX7PEYUAoBO6i5hIAsIKFmFxtW2sghERilU5rdnxQcF3fEx3sY4OtY6VSBPLPhLrbKozHLrQ8ZN/rYTb+hgNUeT7NA1mP78IEkxAj4qG5tli4Jq41aCbUlCt7equGXokImhC+UY5IpQEZS0tKD4vu2ksZ04Qetp0k8jWdAvMA27W3EwgHHNeVGWbJPC0Dn7RqPw13r7hFyS5TpleywjdY1nB7ad6kcZXZbEcaFZ7ZuerA6RkPGE+PsnZRb1oFJkYoXimsuvkVFhWeHQXCGC1cuDWSrM3cpQvOzKH2vS7d15+zGls4IwIDAQABo4IDaTCCA2UwHwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFCYa+OSxsHKEztqBBtInmPvtOj0XMIGBBgNVHREEejB4gg93d3cuZXhhbXBsZS5vcmeCC2V4YW1wbGUuY29tggtleGFtcGxlLmVkdYILZXhhbXBsZS5uZXSCC2V4YW1wbGUub3Jngg93d3cuZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmVkdYIPd3d3LmV4YW1wbGUubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgYsGA1UdHwSBgzCBgDA+oDygOoY4aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS5jcmwwPqA8oDqGOGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv"}}
6
+ {"ip":"93.184.216.34","timestamp":"1630156512","port":80,"proto":"tcp","rec_type":"banner","data":{"service_name":"http.server","banner":"ECS (sec/96ED)"}}
7
+ {"ip":"93.184.216.34","timestamp":"1630156512","port":80,"proto":"tcp","rec_type":"banner","data":{"service_name":"title","banner":"404 - Not Found"}}
8
+ {"ip":"93.184.216.34","timestamp":"1630156512","port":80,"proto":"tcp","rec_type":"banner","data":{"service_name":"http","banner":"HTTP/1.0 404 Not Found\u000d\u000aContent-Type: text/html\u000d\u000aDate: Sat, 28 Aug 2021 13:15:12 GMT\u000d\u000aServer: ECS (sec/96ED)\u000d\u000aContent-Length: 345\u000d\u000aConnection: close\u000d\u000a\u000d"}}
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0"?>
2
+ <!-- masscan v1.0 scan -->
3
+ <nmaprun scanner="masscan" start="1629960654" version="1.0-BETA" xmloutputversion="1.03">
4
+ <scaninfo type="syn" protocol="tcp" />
5
+ <host endtime="1629960654"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="icmp" portid="0"><state state="open" reason="none" reason_ttl="54"/></port></ports></host>
6
+ <host endtime="1629960654"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="54"/></port></ports></host>
7
+ <host endtime="1629960654"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="54"/></port></ports></host>
8
+ <host endtime="1629960657"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="80"><state state="open" reason="response" reason_ttl="54" /><service name="http.server" banner="ECS (sec/973B)"></service></port></ports></host>
9
+ <host endtime="1629960657"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="80"><state state="open" reason="response" reason_ttl="54" /><service name="title" banner="404 - Not Found"></service></port></ports></host>
10
+ <host endtime="1629960657"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="80"><state state="open" reason="response" reason_ttl="54" /><service name="http" banner="HTTP/1.0 404 Not Found\x0d\x0aContent-Type: text/html\x0d\x0aDate: Thu, 26 Aug 2021 06:50:57 GMT\x0d\x0aServer: ECS (sec/973B)\x0d\x0aContent-Length: 345\x0d\x0aConnection: close\x0d\x0a\x0d"></service></port></ports></host>
11
+ <host endtime="1629960657"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="443"><state state="open" reason="response" reason_ttl="54" /><service name="ssl" banner="TLS/1.1 cipher:0xc013, www.example.org, www.example.org, example.com, example.edu, example.net, example.org, www.example.com, www.example.edu, www.example.net"></service></port></ports></host>
12
+ <host endtime="1629960657"><address addr="93.184.216.34" addrtype="ipv4"/><ports><port protocol="tcp" portid="443"><state state="open" reason="response" reason_ttl="54" /><service name="X509" banner="MIIG1TCCBb2gAwIBAgIQD74IsIVNBXOKsMzhya/uyTANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBEaWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMDExMjQwMDAwMDBaFw0yMTEyMjUyMzU5NTlaMIGQMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxPDA6BgNVBAoTM0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEYMBYGA1UEAxMPd3d3LmV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuvzuzMoKCP8Okx2zvgucA5YinrFPEK5RQP1TX7PEYUAoBO6i5hIAsIKFmFxtW2sghERilU5rdnxQcF3fEx3sY4OtY6VSBPLPhLrbKozHLrQ8ZN/rYTb+hgNUeT7NA1mP78IEkxAj4qG5tli4Jq41aCbUlCt7equGXokImhC+UY5IpQEZS0tKD4vu2ksZ04Qetp0k8jWdAvMA27W3EwgHHNeVGWbJPC0Dn7RqPw13r7hFyS5TpleywjdY1nB7ad6kcZXZbEcaFZ7ZuerA6RkPGE+PsnZRb1oFJkYoXimsuvkVFhWeHQXCGC1cuDWSrM3cpQvOzKH2vS7d15+zGls4IwIDAQABo4IDaTCCA2UwHwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFCYa+OSxsHKEztqBBtInmPvtOj0XMIGBBgNVHREEejB4gg93d3cuZXhhbXBsZS5vcmeCC2V4YW1wbGUuY29tggtleGFtcGxlLmVkdYILZXhhbXBsZS5uZXSCC2V4YW1wbGUub3Jngg93d3cuZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmVkdYIPd3d3LmV4YW1wbGUubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgYsGA1UdHwSBgzCBgDA+oDygOoY4aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS5jcmwwPqA8oDqGOGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv"></service></port></ports></host>
13
+ <runstats>
14
+ <finished time="1629960666" timestr="2021-08-25 23:51:06" elapsed="12" />
15
+ <hosts up="2" down="0" total="2" />
16
+ </runstats>
17
+ </nmaprun>
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+ require 'masscan/output_file'
3
+
4
+ describe Masscan::OutputFile do
5
+ describe ".infer_format" do
6
+ subject { described_class.infer_format(path) }
7
+
8
+ context "when the path ends in .json" do
9
+ let(:path) { '/path/to/file.json' }
10
+
11
+ it { expect(subject).to eq(:json) }
12
+ end
13
+
14
+ context "when the path ends in .ndjson" do
15
+ let(:path) { '/path/to/file.ndjson' }
16
+
17
+ it { expect(subject).to eq(:ndjson) }
18
+ end
19
+
20
+ context "when the path ends in .list" do
21
+ let(:path) { '/path/to/file.list' }
22
+
23
+ it { expect(subject).to eq(:list) }
24
+ end
25
+
26
+ context "when the path ends in .txt" do
27
+ let(:path) { '/path/to/file.txt' }
28
+
29
+ it { expect(subject).to eq(:list) }
30
+ end
31
+
32
+ context "when the path ends in .bin" do
33
+ let(:path) { '/path/to/file.bin' }
34
+
35
+ it { expect(subject).to eq(:binary) }
36
+ end
37
+
38
+ context "when the path ends in .dat" do
39
+ let(:path) { '/path/to/file.dat' }
40
+
41
+ it { expect(subject).to eq(:binary) }
42
+ end
43
+
44
+ context "when the path ends in .xml" do
45
+ let(:path) { '/path/to/file.xml' }
46
+
47
+ it { expect(subject).to eq(:xml) }
48
+ end
49
+ end
50
+
51
+ describe "PARSERS" do
52
+ subject { described_class::PARSERS }
53
+
54
+ describe ":binary" do
55
+ it { expect(subject[:binary]).to eq(Masscan::Parsers::Binary) }
56
+ end
57
+
58
+ describe ":list" do
59
+ it { expect(subject[:list]).to eq(Masscan::Parsers::List) }
60
+ end
61
+
62
+ describe ":json" do
63
+ it { expect(subject[:json]).to eq(Masscan::Parsers::JSON) }
64
+ end
65
+
66
+ describe ":ndjson" do
67
+ it { expect(subject[:ndjson]).to eq(Masscan::Parsers::JSON) }
68
+ end
69
+ end
70
+
71
+ describe "#initialize" do
72
+ let(:path) { "/path/to/file.json" }
73
+
74
+ subject { described_class.new(path) }
75
+
76
+ it "must set #path" do
77
+ expect(subject.path).to eq(path)
78
+ end
79
+
80
+ it "must infer the format from the file's extname" do
81
+ expect(subject.format).to eq(:json)
82
+ end
83
+
84
+ it "must set #parser based on #format" do
85
+ expect(subject.parser).to eq(described_class::PARSERS[subject.format])
86
+ end
87
+
88
+ context "when given an format: keyword" do
89
+ let(:format) { :list }
90
+
91
+ subject { described_class.new(path, format: format) }
92
+
93
+ it "must set #format" do
94
+ expect(subject.format).to be(format)
95
+ end
96
+
97
+ it "must set #parser based on the given format:" do
98
+ expect(subject.parser).to eq(described_class::PARSERS[format])
99
+ end
100
+ end
101
+ end
102
+
103
+ subject { described_class.new(Fixtures.join('masscan.list')) }
104
+
105
+ describe "#each" do
106
+ context "when given a block" do
107
+ it "must yield Masscan::Status and Masscan::Banner objects" do
108
+ yielded_record_classes = []
109
+
110
+ subject.each do |record|
111
+ yielded_record_classes << record.class
112
+ end
113
+
114
+ expect(yielded_record_classes.uniq).to eq([
115
+ Masscan::Status,
116
+ Masscan::Banner
117
+ ])
118
+ end
119
+ end
120
+
121
+ context "when given no block" do
122
+ let(:expected_records) do
123
+ [].tap do |yielded_records|
124
+ subject.each do |record|
125
+ yielded_records << record
126
+ end
127
+ end
128
+ end
129
+
130
+ it "must return an Enumerator" do
131
+ expect(subject.each.to_a).to eq(expected_records)
132
+ end
133
+ end
134
+ end
135
+ end