Module: Arachni::RPC::Server::Framework::MultiInstance

Includes:
Distributor, Master, Slave
Included in:
Arachni::RPC::Server::Framework
Defined in:
lib/arachni/rpc/server/framework/multi_instance.rb

Overview

Holds multi-Instance methods for the Arachni::RPC::Server::Framework.

Author:

Constant Summary

Constants included from Distributor

Distributor::MAX_CONCURRENCY, Distributor::MIN_PAGES_PER_INSTANCE

Instance Method Summary collapse

Methods included from Master

#enslave, #master?, #set_as_master, #slave_done, #slave_sitrep, #update_element_ids_per_url, #update_issues

Methods included from Slave

#set_master, #slave?

Methods included from Distributor

#connect_to_instance

Instance Method Details

#errors(starting_line = 0, &block) ⇒ Array<String>

Parameters:

  • starting_line (Integer) (defaults to: 0)

    Sets the starting line for the range of errors to return.

Returns:



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/arachni/rpc/server/framework/multi_instance.rb', line 56

def errors( starting_line = 0, &block )
    return [] if !File.exists? error_logfile

    error_strings = IO.read( error_logfile ).split( "\n" )

    if starting_line != 0
        error_strings = error_strings[starting_line..-1]
    end

    return error_strings if !block_given?

    if !has_slaves?
        block.call( error_strings )
        return
    end

    foreach = proc do |instance, iter|
        instance.framework.errors( starting_line ) { |errs| iter.return( errs ) }
    end
    after = proc { |out| block.call( (error_strings | errs).flatten ) }
    map_slaves( foreach, after )
end

#multi_self_urlObject



245
246
247
# File 'lib/arachni/rpc/server/framework/multi_instance.rb', line 245

def multi_self_url
    @opts.rpc_socket || self_url
end

#progress(opts = {}, &block) ⇒ Hash Also known as: progress_data

Returns aggregated progress data and helps to limit the amount of calls required in order to get an accurate depiction of a scan’s progress and includes:

  • output messages

  • discovered issues

  • overall statistics

  • overall scan status

  • statistics of all instances individually

Parameters:

  • opts (Hash) (defaults to: {})

    Options about what data to include:

Options Hash (opts):

  • :messages (Bool) — default: true

    Output messages.

  • :slaves (Bool) — default: true

    Slave statistics.

  • :issues (Bool) — default: true

    Issue summaries.

  • :stats (Bool) — default: true

    Master/merged statistics.

  • :errors (Integer) — default: false

    Logged errors.

  • :as_hash (Bool) — default: false

    If set to ‘true`, will convert issues to hashes before returning them.

Returns:

  • (Hash)

    Progress data.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/arachni/rpc/server/framework/multi_instance.rb', line 100

def progress( opts = {}, &block )
    opts = opts.symbolize_keys

    include_stats    = opts[:stats].nil? ? true : opts[:stats]
    include_messages = opts[:messages].nil? ? true : opts[:messages]
    include_slaves   = opts[:slaves].nil? ? true : opts[:slaves]
    include_issues   = opts[:issues].nil? ? true : opts[:issues]
    include_errors   = opts.include?( :errors ) ? (opts[:errors] || 0) : false

    as_hash = opts[:as_hash] ? true : opts[:as_hash]

    data = {
        'stats'  => {},
        'status' => status,
        'busy'   => running?
    }

    data['messages']  = flush_buffer if include_messages

    if include_errors
        data['errors'] = errors( include_errors.is_a?( Integer ) ? include_errors : 0 )
    end

    if include_issues
        data['issues'] = as_hash ? issues_as_hash : issues
    end

    data['instances'] = {} if include_slaves

    stats = []
    stat_hash = {}
    stats( true, true ).each { |k, v| stat_hash[k.to_s] = v } if include_stats

    if master? && include_slaves
        data['instances'][self_url] = stat_hash.dup
        data['instances'][self_url]['url'] = self_url
        data['instances'][self_url]['status'] = status
    end

    stats << stat_hash

    if !has_slaves? || !include_slaves
        if include_stats
            data['stats'] = merge_stats( stats )
        else
            data.delete( 'stats' )
        end
        data['instances'] = data['instances'].values if include_slaves
        block.call( data )
        return
    end

    foreach = proc do |instance, iter|
        instance.framework.progress_data( opts ) do |tmp|
            if !tmp.rpc_exception?
                tmp['url'] = instance.url
                iter.return( tmp )
            else
                iter.return( nil )
            end
        end
    end

    after = proc do |slave_data|
        slave_data.compact!
        slave_data.each do |slave|
            data['messages'] |= slave['messages'] if include_messages

            if include_errors && slave['errors']
                data['errors'] ||= []
                data['errors']  |= slave['errors']
            end

            if include_slaves
                url = slave['url']
                data['instances'][url]           = slave['stats'] || {}
                data['instances'][url]['url']    = url
                data['instances'][url]['status'] = slave['status']
            end

            stats << slave['stats']
        end

        if include_slaves
            sorted_data_instances = {}
            data['instances'].keys.sort.each do |url|
                sorted_data_instances[url] = data['instances'][url]
            end
            data['instances'] = sorted_data_instances.values
        end

        if include_stats
            data['stats'] = merge_stats( stats )
        else
            data.delete( 'stats' )
        end

        data['busy']  = slave_data.map { |d| d['busy'] }.include?( true )

        block.call( data )
    end

    map_slaves( foreach, after )
end

#restrict_to_elements(elements, token = nil) ⇒ Bool

Restricts the scope of the audit to individual elements.

Parameters:

  • elements (Array<String>)

    List of element IDs (as created by Element::Capabilities::Auditable#scope_audit_id).

  • token (String) (defaults to: nil)

    Privileged token, prevents this method from being called by 3rd parties when this instance is a master. If this instance is not a master one the token needn’t be provided.

Returns:

  • (Bool)

    ‘true` on success, `false` on invalid `token`.



222
223
224
225
226
# File 'lib/arachni/rpc/server/framework/multi_instance.rb', line 222

def restrict_to_elements( elements, token = nil )
    return false if master? && !valid_token?( token )
    Element::Capabilities::Auditable.restrict_to_elements( elements )
    true
end

#solo?Bool

Returns ‘true` if this instance is running solo (i.e. not a member of a multi-Instance operation), `false` otherwise.

Returns:

  • (Bool)

    ‘true` if this instance is running solo (i.e. not a member of a multi-Instance operation), `false` otherwise.



46
47
48
# File 'lib/arachni/rpc/server/framework/multi_instance.rb', line 46

def solo?
    !master? && !slave?
end

#update_page_queue(pages, token = nil) ⇒ Bool

Updates the page queue with the provided pages.

Parameters:

  • pages (Array<Arachni::Page>)

    List of pages.

  • token (String) (defaults to: nil)

    Privileged token, prevents this method from being called by 3rd parties when this instance is a master. If this instance is not a master one the token needn’t be provided.

Returns:

  • (Bool)

    ‘true` on success, `false` on invalid `token`.



239
240
241
242
243
# File 'lib/arachni/rpc/server/framework/multi_instance.rb', line 239

def update_page_queue( pages, token = nil )
    return false if master? && !valid_token?( token )
    [pages].flatten.each { |page| push_to_page_queue( page )}
    true
end