Class: Arachni::HTTP::ProxyServer

Inherits:
WEBrick::HTTPProxyServer
  • Object
show all
Defined in:
lib/arachni/http/proxy_server.rb

Overview

We add our own type of WEBrick::HTTPProxyServer class that does not restrict header exchange and supports SSL interception.

SSL interception is achieved by redirecting traffic via a 2nd (SSL enabled) instance of this server by hijacking the browser’s CONNECT request.

Author:

Constant Summary collapse

INTERCEPTOR_CERTIFICATE =
File.dirname( __FILE__ ) + '/proxy_server/ssl-interceptor-cert.pem'
INTERCEPTOR_PRIVATE_KEY =
File.dirname( __FILE__ ) + '/proxy_server/ssl-interceptor-pkey.pem'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ ProxyServer

Returns a new instance of ProxyServer.

Options Hash (options):

  • :address (String) — default: '0.0.0.0'

    Address to bind to.

  • :port (Integer)

    Port number to listen on – defaults to a random port.

  • :timeout (Integer)

    HTTP time-out for each request in milliseconds.

  • :concurrency (Integer) — default: OptionGroups::HTTP#request_concurrency

    Maximum number of concurrent connections.

  • :response_handler (Block)

    Block to be called to handle each response as it arrives – will be passed the request and response.

  • :request_handler (Block)

    Block to be called to handle each request as it arrives – will be passed the request and response.

  • :ssl_certificate (String)

    SSL certificate.

  • :ssl_private_key (String)

    SSL private key.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/arachni/http/proxy_server.rb', line 49

def initialize( options = {} )
    @options = {
        address:              '0.0.0.0',
        port:                 Utilities.available_port,
        ssl_certificate_name: [ [ 'CN', 'Arachni' ] ]
    }.merge( options )

    @logger = WEBrick::Log.new( Arachni.null_device, 7 )
    # Will force the proxy to stfu.
    @logger.close

    super(
        BindAddress:        @options[:address],
        Port:               @options[:port],
        MaxClients:         @options[:concurrency] || Options.http.request_concurrency,
        ProxyVia:           false,
        DoNotReverseLookup: true,
        AccessLog:          [],
        Logger:             @logger,
        Timeout:            @options[:timeout],
        SSLEnable:          @options.include?( :ssl_certificate ) &&
                                @options.include?( :ssl_private_key ),
        SSLCertName:        @options[:ssl_certificate_name],
        SSLCertificate:     @options[:ssl_certificate],
        SSLPrivateKey:      @options[:ssl_private_key]
    )
end

Class Method Details

.service(request, response) ⇒ Object



213
214
215
# File 'lib/arachni/http/proxy_server.rb', line 213

def @interceptor.service( request, response )
    @options[:service_handler].call( request, response )
end

Instance Method Details

#active_connectionsInteger



104
105
106
# File 'lib/arachni/http/proxy_server.rb', line 104

def active_connections
    @tokens.max - @tokens.size
end

#addressString



92
93
94
# File 'lib/arachni/http/proxy_server.rb', line 92

def address
    "#{@options[:address]}:#{@options[:port]}"
end

#has_connections?Bool



98
99
100
# File 'lib/arachni/http/proxy_server.rb', line 98

def has_connections?
    active_connections != 0
end

#running?Bool



87
88
89
# File 'lib/arachni/http/proxy_server.rb', line 87

def running?
    @status == :Running
end

#start_asyncObject

Starts the server without blocking, it’ll only block until the server is up and running and ready to accept connections.



79
80
81
82
83
# File 'lib/arachni/http/proxy_server.rb', line 79

def start_async
    Thread.new { start }
    sleep 0.1 while !running?
    nil
end