Class: Rex::Proto::Proxy::Socks4a::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/proto/proxy/socks4a.rb

Overview

A client connected to the Socks4a server.

Defined Under Namespace

Modules: Relay Classes: Packet

Constant Summary collapse

REQUEST_VERSION =
4
REPLY_VERSION =
0
COMMAND_CONNECT =
1
COMMAND_BIND =
2
REQUEST_GRANTED =
90
REQUEST_REJECT_FAILED =
91
REQUEST_REJECT_CONNECT =
92
REQUEST_REJECT_USERID =
93
HOST =
1
PORT =
2

Instance Method Summary collapse

Constructor Details

#initialize(server, sock) ⇒ Client

Create a new client connected to the server.



223
224
225
226
227
228
229
# File 'lib/rex/proto/proxy/socks4a.rb', line 223

def initialize( server, sock )
	@server        = server
	@lsock         = sock
	@rsock         = nil
	@client_thread = nil
	@mutex         = ::Mutex.new
end

Instance Method Details

#startObject

Start handling the client connection.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/rex/proto/proxy/socks4a.rb', line 234

def start
	# create a thread to handle this client request so as to not block the socks4a server
	@client_thread = Rex::ThreadFactory.spawn("SOCKS4AProxyClient", false) do
		begin
			@server.add_client( self )
			# get the initial client request packet
			request = Packet.recv( @lsock )
			raise "Invalid Socks4 request packet received." if not request
			# handle the request
			begin
				# handle socks4a conenct requests
				if( request.is_connect? )
					# perform the connection request
					params = {
						'PeerHost' => request.dest_ip,
						'PeerPort' => request.dest_port,
					}
					params['Context'] = @server.opts['Context'] if @server.opts.has_key?('Context')

					@rsock = Rex::Socket::Tcp.create( params )
					# and send back success to the client
					response         = Packet.new
					response.version = REPLY_VERSION
					response.command = REQUEST_GRANTED
					@lsock.put( response.to_r )
				# handle socks4a bind requests
				elsif( request.is_bind? )
					# create a server socket for this request
					params = {
						'LocalHost' => '0.0.0.0',
						'LocalPort' => 0,
					}
					params['Context'] = @server.opts['Context'] if @server.opts.has_key?('Context')
					bsock = Rex::Socket::TcpServer.create( params )
					# send back the bind success to the client
					response           = Packet.new
					response.version   = REPLY_VERSION
					response.command   = REQUEST_GRANTED
					response.dest_ip   = '0.0.0.0'
					response.dest_port = bsock.getlocalname()[PORT]
					@lsock.put( response.to_r )
					# accept a client connection (2 minute timeout as per spec)
					begin
						::Timeout.timeout( 120 ) do
							@rsock = bsock.accept
						end
					rescue ::Timeout::Error
						raise "Timeout reached on accept request."
					end
					# close the listening socket
					bsock.close
					# verify the connection is from the dest_ip origionally specified by the client
					rpeer = @rsock.getpeername
					raise "Got connection from an invalid peer." if( rpeer[HOST] != request.dest_ip )
					# send back the client connect success to the client
					#
					# sf: according to the spec we send this response back to the client, however
					#     I have seen some clients who bawk if they get this second response.
					#
					response           = Packet.new
					response.version   = REPLY_VERSION
					response.command   = REQUEST_GRANTED
					response.dest_ip   = rpeer[HOST]
					response.dest_port = rpeer[PORT]
					@lsock.put( response.to_r )
				else
					raise "Unknown request command received #{request.command} received."
				end
			rescue
				# send back failure to the client
				response         = Packet.new
				response.version = REPLY_VERSION
				response.command = REQUEST_REJECT_FAILED
				@lsock.put( response.to_r )
				# raise an exception to close this client connection
				raise "Failed to handle the clients request."
			end
			# setup the two way relay for full duplex io
			@lsock.extend( Relay )
			@rsock.extend( Relay )
			# start the socket relays...
			@lsock.relay( self, @rsock )
			@rsock.relay( self, @lsock )
		rescue
			wlog( "Client.start - #{$!}" )
			self.stop
		end
	end
end

#stopObject

Stop handling the client connection.



327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/rex/proto/proxy/socks4a.rb', line 327

def stop
	@mutex.synchronize do
		if( not @closed )

			begin
				@lsock.close if @lsock
			rescue
			end

			begin
				@rsock.close if @rsock
			rescue
			end

			@client_thread.kill if( @client_thread and @client_thread.alive? )

			@server.remove_client( self )

			@closed = true
		end
	end
end