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.
- checksums.yaml +7 -0
 - data/.document +3 -0
 - data/.editorconfig +11 -0
 - data/.github/workflows/ruby.yml +29 -0
 - data/.gitignore +11 -0
 - data/.rspec +1 -0
 - data/.yardopts +1 -0
 - data/ChangeLog.md +6 -0
 - data/Gemfile +15 -0
 - data/LICENSE.txt +20 -0
 - data/README.md +139 -0
 - data/Rakefile +23 -0
 - data/gemspec.yml +28 -0
 - data/lib/masscan/banner.rb +11 -0
 - data/lib/masscan/output_file.rb +100 -0
 - data/lib/masscan/parsers/binary.rb +591 -0
 - data/lib/masscan/parsers/json.rb +106 -0
 - data/lib/masscan/parsers/list.rb +84 -0
 - data/lib/masscan/parsers/plain_text.rb +151 -0
 - data/lib/masscan/parsers.rb +3 -0
 - data/lib/masscan/program.rb +100 -0
 - data/lib/masscan/status.rb +7 -0
 - data/lib/masscan/task.rb +179 -0
 - data/lib/masscan/version.rb +4 -0
 - data/lib/masscan.rb +2 -0
 - data/ruby-masscan.gemspec +61 -0
 - data/spec/fixtures/masscan.bin +0 -0
 - data/spec/fixtures/masscan.json +17 -0
 - data/spec/fixtures/masscan.list +10 -0
 - data/spec/fixtures/masscan.ndjson +8 -0
 - data/spec/fixtures/masscan.xml +17 -0
 - data/spec/output_file_spec.rb +135 -0
 - data/spec/parsers/binary_spec.rb +224 -0
 - data/spec/parsers/json_spec.rb +157 -0
 - data/spec/parsers/list_spec.rb +109 -0
 - data/spec/parsers/parser_examples.rb +58 -0
 - data/spec/parsers/plain_text_spec.rb +116 -0
 - data/spec/spec_helper.rb +11 -0
 - data/spec/task_spec.rb +121 -0
 - metadata +117 -0
 
| 
         @@ -0,0 +1,106 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'masscan/parsers/plain_text'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'masscan/status'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'masscan/banner'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Masscan
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Parsers
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                # Parses the `masscan -oJ` and `masscan --output-format ndjson` output
         
     | 
| 
      
 11 
     | 
    
         
            +
                # formats.
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                # @api semipublic
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                module JSON
         
     | 
| 
      
 16 
     | 
    
         
            +
                  extend PlainText
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # Opens a JSON file for parsing.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @param [String] path
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   The path to the file.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # @yield [file]
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   If a block is given, it will be passed the opened file.
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   Once the block returns, the file will be closed.
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # @yieldparam [File] file
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #   The opened file.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # @return [File]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  #   If no block was given, the opened file will be returned.
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #
         
     | 
| 
      
 34 
     | 
    
         
            +
                  def self.open(path,&block)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    File.open(path,&block)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  #
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # Parses the masscan JSON or ndjson data.
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # @param [#each_line] io
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   The IO object to read from.
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # @yield [record]
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #   If a block is given, it will be passed each parsed record.
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # @yieldparam [Status, Banner] record
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   A parsed record, either a {Status} or a {Banner} object.
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #
         
     | 
| 
      
 50 
     | 
    
         
            +
                  # @return [Enumerator]
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #   If no block is given, it will return an Enumerator.
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #
         
     | 
| 
      
 53 
     | 
    
         
            +
                  def self.parse(io)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    return enum_for(__method__,io) unless block_given?
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    io.each_line do |line|
         
     | 
| 
      
 57 
     | 
    
         
            +
                      line.chomp!
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                      if line == "," || line == "[" || line == "]"
         
     | 
| 
      
 60 
     | 
    
         
            +
                        # skip
         
     | 
| 
      
 61 
     | 
    
         
            +
                      else
         
     | 
| 
      
 62 
     | 
    
         
            +
                        json = ::JSON.parse(line)
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                        ip        = parse_ip(json['ip'])
         
     | 
| 
      
 65 
     | 
    
         
            +
                        timestamp = parse_timestamp(json['timestamp'])
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                        if (ports_json = json['ports'])
         
     | 
| 
      
 68 
     | 
    
         
            +
                          if (port_json = ports_json.first)
         
     | 
| 
      
 69 
     | 
    
         
            +
                            proto  = parse_ip_protocol(port_json['proto'])
         
     | 
| 
      
 70 
     | 
    
         
            +
                            port   = port_json['port']
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                            if (service_json = port_json['service'])
         
     | 
| 
      
 73 
     | 
    
         
            +
                              service_name   = parse_app_protocol(service_json['name'])
         
     | 
| 
      
 74 
     | 
    
         
            +
                              service_banner = service_json['banner']
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                              yield Banner.new(
         
     | 
| 
      
 77 
     | 
    
         
            +
                                proto,
         
     | 
| 
      
 78 
     | 
    
         
            +
                                port,
         
     | 
| 
      
 79 
     | 
    
         
            +
                                ip,
         
     | 
| 
      
 80 
     | 
    
         
            +
                                timestamp,
         
     | 
| 
      
 81 
     | 
    
         
            +
                                service_name,
         
     | 
| 
      
 82 
     | 
    
         
            +
                                service_banner
         
     | 
| 
      
 83 
     | 
    
         
            +
                              )
         
     | 
| 
      
 84 
     | 
    
         
            +
                            else
         
     | 
| 
      
 85 
     | 
    
         
            +
                              status = parse_status(port_json['status'])
         
     | 
| 
      
 86 
     | 
    
         
            +
                              ttl    = port_json['ttl']
         
     | 
| 
      
 87 
     | 
    
         
            +
                              reason = parse_reason(port_json['reason'])
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                              yield Status.new(
         
     | 
| 
      
 90 
     | 
    
         
            +
                                status,
         
     | 
| 
      
 91 
     | 
    
         
            +
                                proto,
         
     | 
| 
      
 92 
     | 
    
         
            +
                                port,
         
     | 
| 
      
 93 
     | 
    
         
            +
                                reason,
         
     | 
| 
      
 94 
     | 
    
         
            +
                                ttl,
         
     | 
| 
      
 95 
     | 
    
         
            +
                                ip,
         
     | 
| 
      
 96 
     | 
    
         
            +
                                timestamp
         
     | 
| 
      
 97 
     | 
    
         
            +
                              )
         
     | 
| 
      
 98 
     | 
    
         
            +
                            end
         
     | 
| 
      
 99 
     | 
    
         
            +
                          end
         
     | 
| 
      
 100 
     | 
    
         
            +
                        end
         
     | 
| 
      
 101 
     | 
    
         
            +
                      end
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
              end
         
     | 
| 
      
 106 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,84 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'masscan/parsers/plain_text'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'masscan/status'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'masscan/banner'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Masscan
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Parsers
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # Parses the `masscan -oL` output format.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                # @api semipublic
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                module List
         
     | 
| 
      
 13 
     | 
    
         
            +
                  extend PlainText
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # Opens a list file for parsing.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @param [String] path
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   The path to the file.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @yield [file]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   If a block is given, it will be passed the opened file.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   Once the block returns, the file will be closed.
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # @yieldparam [File] file
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   The opened file.
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # @return [File]
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #   If no block was given, the opened file will be returned.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def self.open(path,&block)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    File.open(path,&block)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  #
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # Parses the masscan simple list data.
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # @param [#each_line] io
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #   The IO object to read from.
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # @yield [record]
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   If a block is given, it will be passed each parsed record.
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # @yieldparam [Status, Banner] record
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #   A parsed record, either a {Status} or a {Banner} object.
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # @return [Enumerator]
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   If no block is given, it will return an Enumerator.
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #
         
     | 
| 
      
 50 
     | 
    
         
            +
                  def self.parse(io)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    return enum_for(__method__,io) unless block_given?
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    io.each_line do |line|
         
     | 
| 
      
 54 
     | 
    
         
            +
                      line.chomp!
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                      if line.start_with?('open ') || line.start_with?('closed ')
         
     | 
| 
      
 57 
     | 
    
         
            +
                        type, ip_proto, port, ip, timestamp = line.split(' ',5)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                        yield Status.new(
         
     | 
| 
      
 60 
     | 
    
         
            +
                          parse_status(type),
         
     | 
| 
      
 61 
     | 
    
         
            +
                          parse_ip_protocol(ip_proto),
         
     | 
| 
      
 62 
     | 
    
         
            +
                          port.to_i,
         
     | 
| 
      
 63 
     | 
    
         
            +
                          nil,
         
     | 
| 
      
 64 
     | 
    
         
            +
                          nil,
         
     | 
| 
      
 65 
     | 
    
         
            +
                          parse_ip(ip),
         
     | 
| 
      
 66 
     | 
    
         
            +
                          parse_timestamp(timestamp)
         
     | 
| 
      
 67 
     | 
    
         
            +
                        )
         
     | 
| 
      
 68 
     | 
    
         
            +
                      elsif line.start_with?('banner ')
         
     | 
| 
      
 69 
     | 
    
         
            +
                        type, ip_proto, port, ip, timestamp, app_proto, banner = line.split(' ',7)
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                        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
         
     | 
| 
      
 78 
     | 
    
         
            +
                        )
         
     | 
| 
      
 79 
     | 
    
         
            +
                      end
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,151 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Masscan
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Parsers
         
     | 
| 
      
 3 
     | 
    
         
            +
                #
         
     | 
| 
      
 4 
     | 
    
         
            +
                # Common methods for parsing plain-text data.
         
     | 
| 
      
 5 
     | 
    
         
            +
                #
         
     | 
| 
      
 6 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                module PlainText
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # Mapping of status strings to their keywords.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  STATUSES = {
         
     | 
| 
      
 11 
     | 
    
         
            +
                    'open'   => :open,
         
     | 
| 
      
 12 
     | 
    
         
            +
                    'closed' => :closed
         
     | 
| 
      
 13 
     | 
    
         
            +
                  }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # Parses a status string.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @param [String] status
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   The status string to parse.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @return [:open, :closed, String]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   The status keyword or a String if the status wasn't in {STATUSES}.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def parse_status(status)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    STATUSES[status] || status
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  REASONS = {
         
     | 
| 
      
 29 
     | 
    
         
            +
                    'fin' => :fin,
         
     | 
| 
      
 30 
     | 
    
         
            +
                    'syn' => :syn,
         
     | 
| 
      
 31 
     | 
    
         
            +
                    'rst' => :rst,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    'psh' => :psh,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    'ack' => :ack,
         
     | 
| 
      
 34 
     | 
    
         
            +
                    'urg' => :urg,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    'ece' => :ece,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    'cwr' => :cwr
         
     | 
| 
      
 37 
     | 
    
         
            +
                  }
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # Parses a reason string.
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # @param [String] reason
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #   The reason string to parse.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @return [Array<:fin, :syn, :rst, :psh, :ack, :urg, :ece, :cwr>]
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #   The reason keywords or a String if the flag wasn't in {REASONS}.
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def parse_reason(reason)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    flags = reason.split('-')
         
     | 
| 
      
 50 
     | 
    
         
            +
                    flags.map! { |flag| REASONS[flag] || flag }
         
     | 
| 
      
 51 
     | 
    
         
            +
                    flags
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  # Mapping of IP protocol names to their keywords.
         
     | 
| 
      
 55 
     | 
    
         
            +
                  IP_PROTOCOLS = {
         
     | 
| 
      
 56 
     | 
    
         
            +
                    'tcp'  => :tcp,
         
     | 
| 
      
 57 
     | 
    
         
            +
                    'udp'  => :udp,
         
     | 
| 
      
 58 
     | 
    
         
            +
                    'icmp' => :icmp,
         
     | 
| 
      
 59 
     | 
    
         
            +
                    'sctp' => :sctp
         
     | 
| 
      
 60 
     | 
    
         
            +
                  }
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # Parses an IP protocol name.
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # @param [String] proto
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #   The IP protocol name.
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # @return [:tcp, :udp, :icmp, :sctp, String]
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   The IP protocol keyword or a String if the IP protocol wasn't in
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #   {IP_PROTOCOLS}.
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #
         
     | 
| 
      
 72 
     | 
    
         
            +
                  def parse_ip_protocol(proto)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    IP_PROTOCOLS[proto] || proto
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  # Mapping of application protocol names to their keywords.
         
     | 
| 
      
 77 
     | 
    
         
            +
                  APP_PROTOCOLS = {
         
     | 
| 
      
 78 
     | 
    
         
            +
                    "ssh1" => :ssh1,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    "ssh2" => :ssh2,
         
     | 
| 
      
 80 
     | 
    
         
            +
                    "ssh"  => :ssh,
         
     | 
| 
      
 81 
     | 
    
         
            +
                    "http" => :http,
         
     | 
| 
      
 82 
     | 
    
         
            +
                    "ftp"  => :ftp,
         
     | 
| 
      
 83 
     | 
    
         
            +
                    "dns-ver" => :dns_ver,
         
     | 
| 
      
 84 
     | 
    
         
            +
                    "snmp" => :smtp,
         
     | 
| 
      
 85 
     | 
    
         
            +
                    "nbtstat" => :nbtstat,
         
     | 
| 
      
 86 
     | 
    
         
            +
                    "ssl" => :ssl3,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    "smtp" => :smtp,
         
     | 
| 
      
 88 
     | 
    
         
            +
                    "smb" => :smb,
         
     | 
| 
      
 89 
     | 
    
         
            +
                    "pop" => :pop,
         
     | 
| 
      
 90 
     | 
    
         
            +
                    "imap" => :imap,
         
     | 
| 
      
 91 
     | 
    
         
            +
                    "X509" => :x509,
         
     | 
| 
      
 92 
     | 
    
         
            +
                    "zeroaccess" => :zeroaccess,
         
     | 
| 
      
 93 
     | 
    
         
            +
                    "title" => :html_title,
         
     | 
| 
      
 94 
     | 
    
         
            +
                    "html" => :html,
         
     | 
| 
      
 95 
     | 
    
         
            +
                    "ntp" => :ntp,
         
     | 
| 
      
 96 
     | 
    
         
            +
                    "vuln" => :vuln,
         
     | 
| 
      
 97 
     | 
    
         
            +
                    "heartbleed" => :heartbleed,
         
     | 
| 
      
 98 
     | 
    
         
            +
                    "ticketbleed" => :ticketbleed,
         
     | 
| 
      
 99 
     | 
    
         
            +
                    "vnc" => :vnc,
         
     | 
| 
      
 100 
     | 
    
         
            +
                    "safe" => :safe,
         
     | 
| 
      
 101 
     | 
    
         
            +
                    "memcached" => :memcached,
         
     | 
| 
      
 102 
     | 
    
         
            +
                    "scripting" => :scripting,
         
     | 
| 
      
 103 
     | 
    
         
            +
                    "versioning" => :versioning,
         
     | 
| 
      
 104 
     | 
    
         
            +
                    "coap"        => :coap,
         
     | 
| 
      
 105 
     | 
    
         
            +
                    "telnet"      => :telnet,
         
     | 
| 
      
 106 
     | 
    
         
            +
                    "rdp"         => :rdp,
         
     | 
| 
      
 107 
     | 
    
         
            +
                    "http.server" => :http_server
         
     | 
| 
      
 108 
     | 
    
         
            +
                  }
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  #
         
     | 
| 
      
 111 
     | 
    
         
            +
                  # Parses an application protocol name.
         
     | 
| 
      
 112 
     | 
    
         
            +
                  #
         
     | 
| 
      
 113 
     | 
    
         
            +
                  # @param [String] proto
         
     | 
| 
      
 114 
     | 
    
         
            +
                  #   The application protocol name.
         
     | 
| 
      
 115 
     | 
    
         
            +
                  #
         
     | 
| 
      
 116 
     | 
    
         
            +
                  # @return [Symbol, String]
         
     | 
| 
      
 117 
     | 
    
         
            +
                  #   The IP protocol keyword or a String if the application protocol wasn't
         
     | 
| 
      
 118 
     | 
    
         
            +
                  #   in {APP_PROTOCOLS}.
         
     | 
| 
      
 119 
     | 
    
         
            +
                  #
         
     | 
| 
      
 120 
     | 
    
         
            +
                  def parse_app_protocol(proto)
         
     | 
| 
      
 121 
     | 
    
         
            +
                    APP_PROTOCOLS[proto] || proto
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  #
         
     | 
| 
      
 125 
     | 
    
         
            +
                  # Parses a timestamp.
         
     | 
| 
      
 126 
     | 
    
         
            +
                  #
         
     | 
| 
      
 127 
     | 
    
         
            +
                  # @param [String] timestamp
         
     | 
| 
      
 128 
     | 
    
         
            +
                  #   The numeric timestamp value.
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #
         
     | 
| 
      
 130 
     | 
    
         
            +
                  # @return [Time]
         
     | 
| 
      
 131 
     | 
    
         
            +
                  #   The parsed timestamp value.
         
     | 
| 
      
 132 
     | 
    
         
            +
                  #
         
     | 
| 
      
 133 
     | 
    
         
            +
                  def parse_timestamp(timestamp)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    Time.at(timestamp.to_i)
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  #
         
     | 
| 
      
 138 
     | 
    
         
            +
                  # Parses an IP address.
         
     | 
| 
      
 139 
     | 
    
         
            +
                  #
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # @param [String] ip
         
     | 
| 
      
 141 
     | 
    
         
            +
                  #   The string representation of the IP address.
         
     | 
| 
      
 142 
     | 
    
         
            +
                  #
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # @return [IPAddr]
         
     | 
| 
      
 144 
     | 
    
         
            +
                  #   The parsed IP address.
         
     | 
| 
      
 145 
     | 
    
         
            +
                  #
         
     | 
| 
      
 146 
     | 
    
         
            +
                  def parse_ip(ip)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    IPAddr.new(ip)
         
     | 
| 
      
 148 
     | 
    
         
            +
                  end
         
     | 
| 
      
 149 
     | 
    
         
            +
                end
         
     | 
| 
      
 150 
     | 
    
         
            +
              end
         
     | 
| 
      
 151 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,100 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'masscan/task'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rprogram/program'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Masscan
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              # Represents the `masscan` program.
         
     | 
| 
      
 8 
     | 
    
         
            +
              #
         
     | 
| 
      
 9 
     | 
    
         
            +
              class Program < RProgram::Program
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                name_program 'masscan'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                #
         
     | 
| 
      
 14 
     | 
    
         
            +
                # Finds the `masscan` program and performs a scan.
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                # @param [Hash{Symbol => Object}] options
         
     | 
| 
      
 17 
     | 
    
         
            +
                #   Additional options for masscan.
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @param [Hash{Symbol => Object}] exec_options
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   Additional exec-options.
         
     | 
| 
      
 21 
     | 
    
         
            +
                #
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @yield [task]
         
     | 
| 
      
 23 
     | 
    
         
            +
                #   If a block is given, it will be passed a task object
         
     | 
| 
      
 24 
     | 
    
         
            +
                #   used to specify options for masscan.
         
     | 
| 
      
 25 
     | 
    
         
            +
                #
         
     | 
| 
      
 26 
     | 
    
         
            +
                # @yieldparam [Task] task
         
     | 
| 
      
 27 
     | 
    
         
            +
                #   The masscan task object.
         
     | 
| 
      
 28 
     | 
    
         
            +
                #
         
     | 
| 
      
 29 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 30 
     | 
    
         
            +
                #   Specifies whether the command exited normally.
         
     | 
| 
      
 31 
     | 
    
         
            +
                #
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @example Specifying `masscan` options via a Hash.
         
     | 
| 
      
 33 
     | 
    
         
            +
                #   Masscan::Program.scan(
         
     | 
| 
      
 34 
     | 
    
         
            +
                #     ips: '192.168.1.1/24',
         
     | 
| 
      
 35 
     | 
    
         
            +
                #     ports: [22, 80, 443],
         
     | 
| 
      
 36 
     | 
    
         
            +
                #   )
         
     | 
| 
      
 37 
     | 
    
         
            +
                #
         
     | 
| 
      
 38 
     | 
    
         
            +
                # @example Specifying `masscan` options via a {Task} object.
         
     | 
| 
      
 39 
     | 
    
         
            +
                #   Masscan::Program.scan do |masscan|
         
     | 
| 
      
 40 
     | 
    
         
            +
                #     masscan.ips = '192.168.1.1/24'
         
     | 
| 
      
 41 
     | 
    
         
            +
                #     masscan.ports = [22, 80, 443]
         
     | 
| 
      
 42 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 43 
     | 
    
         
            +
                #
         
     | 
| 
      
 44 
     | 
    
         
            +
                # @see #scan
         
     | 
| 
      
 45 
     | 
    
         
            +
                #
         
     | 
| 
      
 46 
     | 
    
         
            +
                def self.scan(options={},exec_options={},&block)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  find.scan(options,exec_options,&block)
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                #
         
     | 
| 
      
 51 
     | 
    
         
            +
                # Finds the `masscan` program and performs a scan, but runs `masscan` under
         
     | 
| 
      
 52 
     | 
    
         
            +
                # `sudo`.
         
     | 
| 
      
 53 
     | 
    
         
            +
                #
         
     | 
| 
      
 54 
     | 
    
         
            +
                # @see scan
         
     | 
| 
      
 55 
     | 
    
         
            +
                #
         
     | 
| 
      
 56 
     | 
    
         
            +
                # @since 0.8.0
         
     | 
| 
      
 57 
     | 
    
         
            +
                #
         
     | 
| 
      
 58 
     | 
    
         
            +
                def self.sudo_scan(options={},exec_options={},&block)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  find.sudo_scan(options,exec_options,&block)
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                #
         
     | 
| 
      
 63 
     | 
    
         
            +
                # Performs a scan.
         
     | 
| 
      
 64 
     | 
    
         
            +
                #
         
     | 
| 
      
 65 
     | 
    
         
            +
                # @param [Hash{Symbol => Object}] options
         
     | 
| 
      
 66 
     | 
    
         
            +
                #   Additional options for masscan.
         
     | 
| 
      
 67 
     | 
    
         
            +
                #
         
     | 
| 
      
 68 
     | 
    
         
            +
                # @param [Hash{Symbol => Object}] exec_options
         
     | 
| 
      
 69 
     | 
    
         
            +
                #   Additional exec-options.
         
     | 
| 
      
 70 
     | 
    
         
            +
                #
         
     | 
| 
      
 71 
     | 
    
         
            +
                # @yield [task]
         
     | 
| 
      
 72 
     | 
    
         
            +
                #   If a block is given, it will be passed a task object
         
     | 
| 
      
 73 
     | 
    
         
            +
                #   used to specify options for masscan.
         
     | 
| 
      
 74 
     | 
    
         
            +
                #
         
     | 
| 
      
 75 
     | 
    
         
            +
                # @yieldparam [Task] task
         
     | 
| 
      
 76 
     | 
    
         
            +
                #   The masscan task object.
         
     | 
| 
      
 77 
     | 
    
         
            +
                #
         
     | 
| 
      
 78 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 79 
     | 
    
         
            +
                #   Specifies whether the command exited normally.
         
     | 
| 
      
 80 
     | 
    
         
            +
                #
         
     | 
| 
      
 81 
     | 
    
         
            +
                # @see http://rubydoc.info/gems/rprogram/0.3.0/RProgram/Program#run-instance_method
         
     | 
| 
      
 82 
     | 
    
         
            +
                #   For additional exec-options.
         
     | 
| 
      
 83 
     | 
    
         
            +
                #
         
     | 
| 
      
 84 
     | 
    
         
            +
                def scan(options={},exec_options={},&block)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  run_task(Task.new(options,&block),exec_options)
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                #
         
     | 
| 
      
 89 
     | 
    
         
            +
                # Performs a scan and runs `masscan` under `sudo`.
         
     | 
| 
      
 90 
     | 
    
         
            +
                #
         
     | 
| 
      
 91 
     | 
    
         
            +
                # @see #scan
         
     | 
| 
      
 92 
     | 
    
         
            +
                #
         
     | 
| 
      
 93 
     | 
    
         
            +
                # @since 0.8.0
         
     | 
| 
      
 94 
     | 
    
         
            +
                #
         
     | 
| 
      
 95 
     | 
    
         
            +
                def sudo_scan(options={},exec_options={},&block)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  sudo_task(Task.new(options,&block),exec_options)
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
              end
         
     | 
| 
      
 100 
     | 
    
         
            +
            end
         
     |