User Tools

Site Tools


python:socksv4_proxy

This is a simple SOCKSv4 proxy written in pure python. Suitable for use with browsers.

#!/usr/bin/python
import sys
import socket
import struct
import thread
from optparse import OptionParser
 
# Very simple multi-threaded SOCKSv4(a) proxy
# by Tyler Bletsch (Tyler.Bletsch at gmail dot com)
 
parser = OptionParser("Usage: %prog [options]")
 
parser.add_option("-p", "--port", dest="listen_port", help="Port on which to listen (default: %default).", metavar="PORT", type="int", default=1080)
parser.add_option("-l", "--listen-interface", dest="listen_interface", help="IP address of the interface to listen on (default: all of them).", metavar="IP", default='0.0.0.0')
parser.add_option("-c", "--connect-interface", dest="connect_interface", help="IP address of the interface to connect out with (default: default route).", metavar="IP", default=None)
parser.add_option("-b", "--buffer-size", dest="buffer_size", help="Size of the forwarding buffer (default: %default).", metavar="N", type="int", default=4096)
 
(options, args) = parser.parse_args()
 
buffer_size = options.buffer_size
listen_port = options.listen_port
listen_interface = options.listen_interface
connect_interface = options.connect_interface
 
def readstr(s):
	r=''
	while 1:
		c = s.recv(1)
		if not c: return None
		if c == '\0': break
		r += c
	return r
 
def tunnel(src,dest):
	while 1:
		try:
			r = src.recv(buffer_size)
		except Exception as e:
			print "Recv error: %s" % e
			src.close()
			dest.close()
			break
 
		if not r:
			src.close()
			dest.close()
			break
 
		try:
			dest.send(r)
		except Exception as e:
			print "Send error: %s" % e
			src.close()
			dest.close()
			break
 
 
svr = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
svr.bind((listen_interface, listen_port))
svr.listen(32)
 
SOCKS4_REQUEST_FORMAT = '!BBH4s' # byte (socks_ver), byte (command), short (port), 4-char string (IP addr)
SOCKS4_RESPONSE_OKAY = struct.pack('!BBHI',0,0x5a,0,0)
SOCKS4_RESPONSE_FAIL = struct.pack('!BBHI',0,0x5b,0,0)
 
print "Listening on %s:%d..." % (listen_interface,listen_port)
 
while 1:
	initiator, initiator_addr = svr.accept()
	sys.stdout.write('%16s:%-5d ' % (initiator_addr))
 
	data = initiator.recv(struct.calcsize(SOCKS4_REQUEST_FORMAT))
 
	if not data: 
		print "Connection dropped."
		break
 
	(socks_ver,command,target_port,target_addr) = struct.unpack(SOCKS4_REQUEST_FORMAT,data)
	(target_addr_int,) = struct.unpack('!I',target_addr)
	target_addr = socket.inet_ntoa(target_addr)
	username = readstr(initiator)
 
	if socks_ver!=4:
		print "Dropping non-SOCKSv4 request."
		initiator.send(SOCKS4_RESPONSE_FAIL)
		initiator.close()
		continue
 
	if command!=1:
		print "Dropping non-connect request."
		initiator.send(SOCKS4_RESPONSE_FAIL)
		initiator.close()
		continue
 
	is_socks4a = target_addr_int>0 and target_addr_int<256 # check for 0.0.0.x, i.e. SOCKS4a domain mode
	if is_socks4a: 
		target_addr = readstr(initiator)
 
	sys.stdout.write("SOCKSv4%s => %s:%d  " % ('a' if is_socks4a else ' ', target_addr, target_port))
 
	target = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	if connect_interface: target.bind((connect_interface, 0))
	try:
		target.connect((target_addr, target_port))
	except Exception as e:
		initiator.send(SOCKS4_RESPONSE_FAIL)
		initiator.close()
		print "FAIL: %s" % e
		continue
	if not target:
		initiator.send(SOCKS4_RESPONSE_FAIL)
		initiator.close()
		print "FAIL"
		continue
 
	print "OK"
	initiator.send(SOCKS4_RESPONSE_OKAY)
	thread.start_new_thread(tunnel,(initiator,target))
	thread.start_new_thread(tunnel,(target,initiator))
python/socksv4_proxy.txt · Last modified: 2011/05/20 13:50 by tkbletsc