Class: Ronin::Recon::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/ronin/recon/engine.rb

Overview

The recon engine which enqueues and dequeues values from workers.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(values, ignore: [], max_depth: nil, config: nil, config_file: nil, workers: nil, logger: Console.logger) {|self| ... } ⇒ Engine

Initializes the recon engine.

Parameters:

  • values (Array<Value>)

    The values to start performing recon on.

  • ignore (Array<Value>) (defaults to: [])

    The values to ignore while performing recon.

  • max_depth (Integer, nil) (defaults to: nil)

    The maximum depth to limit recon to. If not specified recon will continue until there are no more new values discovered.

  • config_file (String, nil) (defaults to: nil)

    The path to the configuration file.

  • config (Config, nil) (defaults to: nil)

    The configuration for the engine. If specified, it will override config_file:.

  • workers (Workers, Array<Class<Worker>>, nil) (defaults to: nil)

    The worker classes to use. If specified, it will override the workers specified in config.workers.

  • logger (Console::Logger) (defaults to: Console.logger)

    The common logger for the recon engine.

Yields:

  • (self)

    If a block is given it will be passed the newly created engine.

Yield Parameters:

  • self (Engine)

    The newly initialized engine.

  • parent (Value)

    The parent value which is associated to the discovered value.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/ronin/recon/engine.rb', line 126

def initialize(values, ignore:      [],
                       max_depth:   nil,
                       config:      nil,
                       config_file: nil,
                       workers:     nil,
                       logger:      Console.logger)
  @config  = if    config      then config
             elsif config_file then Config.load(config_file)
             else                   Config.default
             end
  @workers = workers || Workers.load(@config.workers)
  @logger  = logger

  @scope     = Scope.new(values, ignore: ignore)
  @max_depth = max_depth

  @on_value_callbacks         = []
  @on_connection_callbacks    = []
  @on_job_started_callbacks   = []
  @on_job_completed_callbacks = []
  @on_job_failed_callbacks    = []

  @value_status = ValueStatus.new
  @graph        = Graph.new

  yield self if block_given?

  @worker_classes    = {}
  @worker_pools      = {}
  @worker_pool_count = 0
  @output_queue      = Async::Queue.new

  @workers.each do |worker_class|
    add_worker(worker_class)
  end
end

Instance Attribute Details

#configConfig (readonly)

The configuration for the engine.

Returns:



50
51
52
# File 'lib/ronin/recon/engine.rb', line 50

def config
  @config
end

#graphGraph (readonly)

The recon engine graph of discovered values.

Returns:



79
80
81
# File 'lib/ronin/recon/engine.rb', line 79

def graph
  @graph
end

#loggerConsole::Logger (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The common logger for the engine.

Returns:

  • (Console::Logger)


86
87
88
# File 'lib/ronin/recon/engine.rb', line 86

def logger
  @logger
end

#max_depthInteger? (readonly)

The maximum depth to recon.

Returns:

  • (Integer, nil)


67
68
69
# File 'lib/ronin/recon/engine.rb', line 67

def max_depth
  @max_depth
end

#scopeScope (readonly)

The scope to constrain recon to.

Returns:



60
61
62
# File 'lib/ronin/recon/engine.rb', line 60

def scope
  @scope
end

#value_statusValueStatus (readonly)

The status of all values in the queue.

Returns:



72
73
74
# File 'lib/ronin/recon/engine.rb', line 72

def value_status
  @value_status
end

#workersWorkers (readonly)

The workers to use.

Returns:



55
56
57
# File 'lib/ronin/recon/engine.rb', line 55

def workers
  @workers
end

Class Method Details

.run(values, **kwargs) {|value, (value, parent)| ... } ⇒ Engine

Runs the recon engine with the given initial values.

Parameters:

  • values (Array<Value>)

    The initial values to start the recon engine with.

  • kwargs (Hash{Symbol => Object})

    Additional keyword arguments for #initialize.

Yields:

  • (value, (value, parent))

    The given block will be passed each discovered value during recon. If the block accepts two arguments the value and it's parent value will be passed to the block.

Yield Parameters:

  • value (Value)

    A value discovered by one of the recon workers.

  • parent (Value)

    The parent value which is associated to the discovered value.

Returns:

  • (Engine)

    The engine instance.



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/ronin/recon/engine.rb', line 200

def self.run(values,**kwargs,&block)
  engine = new(values,**kwargs,&block)

  # start the engine in it's own Async task
  Async do |task|
    # start the engine
    engine.run(task)
  end

  return engine
end

Instance Method Details

#add_worker(worker_class, params: nil, concurrency: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Adds a worker class to the engine.

Parameters:

  • worker_class (Class<Worker>)

    The worker class.

  • params (Hash{Symbol => Object}, nil) (defaults to: nil)

    Additional params for Worker#initialize.



256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/ronin/recon/engine.rb', line 256

def add_worker(worker_class, params: nil, concurrency: nil)
  params      ||= @config.params[worker_class.id]
  concurrency ||= @config.concurrency[worker_class.id]

  worker      = worker_class.new(params: params)
  worker_pool = WorkerPool.new(worker, concurrency:  concurrency,
                                       output_queue: @output_queue,
                                       logger:       @logger)

  worker_class.accepts.each do |value_class|
    (@worker_classes[value_class] ||= []) << worker_class
    (@worker_pools[value_class]   ||= []) << worker_pool
  end
end

#on(event) {|value, (value, parent), (worker_class, value, parent)| ... } ⇒ Object

Registers a callback for the given event.

Parameters:

  • event (:value, :connection, :job_started, :job_completed, :job_failed)

    The event type to register the callback for.

Yields:

  • (value, (value, parent), (worker_class, value, parent))

    If :value is given, then the given block will be passed each new value.

  • ((value, parent), (worker_class, value, parent))

    If :connection is given, then the given block will be passed the discovered value and it's parent value.

  • (worker_class, value)

    If :job_started is given, then the given block will be passed the worker class and the input value.

  • (worker_class, value)

    If :job_completed is given, then the given block will be passed the worker class and the input value.

  • (worker_class, value, exception)

    If :job_failed is given, then any exception raised by a worker will be passed to the given block.

Yield Parameters:

  • value (Value)

    A discovered value value.

  • parent (Value)

    The parent value of the value.

  • worker_class (Class<Worker>)

    The worker class.

  • exception (RuntimeError)

    An exception that was raised by a worker.



310
311
312
313
314
315
316
317
318
319
320
# File 'lib/ronin/recon/engine.rb', line 310

def on(event,&block)
  case event
  when :value         then @on_value_callbacks         << block
  when :connection    then @on_connection_callbacks    << block
  when :job_started   then @on_job_started_callbacks   << block
  when :job_completed then @on_job_completed_callbacks << block
  when :job_failed    then @on_job_failed_callbacks    << block
  else
    raise(ArgumentError,"unsupported event type: #{event.inspect}")
  end
end

#run(task = Async::Task.current) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The main recon engine event loop.

Parameters:

  • task (Async::Task) (defaults to: Async::Task.current)

    The parent async task.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/ronin/recon/engine.rb', line 220

def run(task=Async::Task.current)
  # enqueue the scope values for processing
  # rubocop:disable Style/HashEachMethods
  @scope.values.each do |value|
    enqueue_value(value)
  end
  # rubocop:enable Style/HashEachMethods

  # output consumer task
  task.async do
    until (@value_status.empty? && @output_queue.empty?)
      process(@output_queue.dequeue)
    end

    shutdown!
  end

  # start all work groups
  @worker_pools.each_value do |worker_pools|
    worker_pools.each do |worker_pool|
      worker_pool.start(task)
    end
  end
end

#valuesSet<Value>

The discovered recon values.

Returns:

  • (Set<Value>)

    The set of discovered recon values.



171
172
173
# File 'lib/ronin/recon/engine.rb', line 171

def values
  @graph.nodes
end