ruby-masscan 0.1.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.
@@ -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