Class: PacketThief::Handlers::SSLTransparentProxy

Inherits:
SSLServer show all
Defined in:
lib/packetthief/handlers/ssl_transparent_proxy.rb

Overview

Provides a transparent proxy for any TCP connection.

Direct Known Subclasses

SSLSmartProxy

Defined Under Namespace

Classes: SSLProxyConnection

Instance Attribute Summary collapse

Attributes inherited from SSLServer

#server_handler

Attributes inherited from AbstractSSLHandler

#ctx, #sni_hostname, #sslsocket, #tcpsocket

Instance Method Summary collapse

Methods inherited from SSLServer

start, #stop_server

Methods inherited from AbstractSSLHandler

#close_connection, #close_connection_after_writing, #notify_readable, #notify_writable, #post_init, #send_data, #tls_begin, #tls_failed_handshake, #write_buffer, #write_buffer=

Methods included from Logging

log

Constructor Details

#initialize(tcpsocket) ⇒ SSLTransparentProxy

Returns a new instance of SSLTransparentProxy.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 86

def initialize(tcpsocket)
  super
  @closed = false

  @client = self
  @dest = nil

  @buffer = []
  @@activeconns ||= {}

  @client_port, @client_host = Socket.unpack_sockaddr_in(get_peername)
  @dest_port, @dest_host = PacketThief.original_dest(self)

  if @@activeconns.has_key? "#{client_host}:#{client_port}"
    logwarn "loop detected! Stopping the loop."
    close_connection
    return
  end

  @dest_ctx = OpenSSL::SSL::SSLContext.new
  @dest_ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE

end

Instance Attribute Details

#bufferObject

An internal buffer of packet data received from the client. It will grow until the destination connection connects.



70
71
72
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 70

def buffer
  @buffer
end

#clientObject

This holds a reference to the connection to the client. It is actually self.



61
62
63
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 61

def client
  @client
end

#client_hostObject (readonly)

Returns the value of attribute client_host.



63
64
65
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 63

def client_host
  @client_host
end

#client_portObject (readonly)

Returns the value of attribute client_port.



63
64
65
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 63

def client_port
  @client_port
end

#closedObject

Boolean that represents whether this handler has started to close/unbind. Used to ensure there is no unbind-loop between the two connections that make up the proxy.



75
76
77
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 75

def closed
  @closed
end

#destObject

This holds a reference to the connection to the destination. If it is null, it hasn’t been created yet.



57
58
59
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 57

def dest
  @dest
end

#dest_ctxObject

The SSLContext that will be used on the connection to the destination. Initially, its verify_mode is set to OpenSSL::SSL::VERIFY_NONE.



84
85
86
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 84

def dest_ctx
  @dest_ctx
end

#dest_hostObject

Override these before connecting to dest to change the dest connection.



66
67
68
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 66

def dest_host
  @dest_host
end

#dest_hostnameObject

If a client specifies a TLS hostname extension (SNI) as the hostname, then we can forward that fact on to the real server. We can also use it to choose a certificate to present.



80
81
82
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 80

def dest_hostname
  @dest_hostname
end

#dest_portObject

Override these before connecting to dest to change the dest connection.



66
67
68
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 66

def dest_port
  @dest_port
end

Instance Method Details

#_send_bufferObject



138
139
140
141
142
143
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 138

def _send_buffer
  @buffer.each do |pkt|
    @dest.send_data pkt
  end
  @buffer = []
end

#client_closedObject

Called when the client connection closes. At present, it only provides informational utility.



196
197
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 196

def client_closed
end

#client_connectedObject

This method is called when a client connects, and the TLS handhsake has completed. The default behavior is to begin initating the connection to the original destination. Override this method to change its behavior.



177
178
179
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 177

def client_connected
  connect_to_dest
end

#client_handshake_failedObject

This method is called when the TLS handshake between the client and the proxy fails. It does nothing by default.



183
184
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 183

def client_handshake_failed
end

#client_recv(data) ⇒ Object

This method is called when the proxy receives data from the client connection. The default behavior is to call send_to_dest(data) in order to foward the data on to the original destination. Override this method to analyze the data, or modify it before sending it on.



190
191
192
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 190

def client_recv(data)
  send_to_dest data
end

#connect_to_destObject

Initiate the connection to @dest_host:@dest_port.



130
131
132
133
134
135
136
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 130

def connect_to_dest
  return if @dest
  @dest = SSLProxyConnection.connect(@dest_host, @dest_port, self, @dest_ctx)
  newport, newhost = Socket::unpack_sockaddr_in(@dest.get_sockname)
  # Add the new connection to the list to prevent loops.
  @@activeconns["#{newhost}:#{newport}"] = "#{dest_host}:#{dest_port}"
end

#dest_cert_chainObject

Returns the certificate chain for the destination, or nil if the destination connection does not exist yet.



160
161
162
163
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 160

def dest_cert_chain
  return @dest.sslsocket.peer_cert_chain if @dest
  nil
end

#dest_closedObject

Called when the original destination connection closes. At present, it only provides informational utility.



219
220
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 219

def dest_closed
end

#dest_connectedObject

Called when the connection to and the TLS handshake between the proxy and the destination succeeds. The default behavior does nothing.



201
202
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 201

def dest_connected
end

#dest_handshake_failed(e) ⇒ Object

Called when the TLS handshake between the proxy and the destination fails.



206
207
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 206

def dest_handshake_failed(e)
end

#dest_recv(data) ⇒ Object

Called when the proxy receives data from the destination connection. The default behavior calls #dest_recv() to send the data to the client.

Override it to analyze or modify the data.



213
214
215
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 213

def dest_recv(data)
  send_to_client data
end

#receive_data(data) ⇒ Object



115
116
117
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 115

def receive_data(data)
  client_recv data
end

#send_to_client(data) ⇒ Object

Sends data back to the client



154
155
156
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 154

def send_to_client(data)
  send_data data
end

#send_to_dest(data) ⇒ Object

Queues up data to send to the remote host, only sending it if the connection to the remote host exists.



148
149
150
151
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 148

def send_to_dest(data)
  @buffer << data
  _send_buffer if @dest
end

#servername_cb(sslsock, hostname) ⇒ Object

Set dest_hostname in addition to the default behavior.



168
169
170
171
172
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 168

def servername_cb(sslsock, hostname)
  @dest_hostname = hostname

  super(sslsock, hostname)
end

#tls_successful_handshakeObject

Just calls client_connected to keep things straightforward.



111
112
113
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 111

def tls_successful_handshake
  client_connected
end

#unbindObject

Start the closing process and close the other connection if it is not already closing.



121
122
123
124
125
126
127
# File 'lib/packetthief/handlers/ssl_transparent_proxy.rb', line 121

def unbind
  client_closed
  @@activeconns.delete "#{client_host}:#{client_port}"
  self.closed = true
#        @dest.client = nil if @dest
  @dest.close_connection_after_writing if @dest and not @dest.closed
end