Skip to content

Instantly share code, notes, and snippets.

@sfan5
Last active December 16, 2015 22:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfan5/5510472 to your computer and use it in GitHub Desktop.
Save sfan5/5510472 to your computer and use it in GitHub Desktop.
A SOCKS 5 proxy server
#!/usr/bin/env python2
# SOCKS 5 server
# -*- coding: utf-8 -*-
import socket, struct, time, select, os
from thread import start_new_thread, allocate_lock
# Address to listen on
HOST = ""
# Port to listen on
PORT = 12345
# Buffer size
BUFSIZE = 128 * 1024
# Logfile
LOGFILE = ""
# Domain blacklist
# Note that most clients only send the IP Address they are connecting to
# which means that this blacklist is likely not effective
DOMAIN_BLACKLIST = []
# IP blacklist
IP_BLACKLIST = []
# Port blacklist
PORT_BLACKLIST = []
# Authentication method (none or password)
AUTHMETHOD = "none"
# User and password for "password" authentication method:
AM_PSW_USER = ""
AM_PSW_PASS = ""
client_cnt = 0
connections = []
lock = allocate_lock()
class MyError():
pass
def log(st, c=-1):
cstr = ""
if c != -1:
cstr = " [Connection %d]" % c
lock.acquire()
if LOGFILE != '':
LOGFILE.write(time.strftime("[%c]") + cstr + " " + st + "\n")
print(time.strftime("[%c]") + cstr + " " + st)
lock.release()
def hcwrapper(sock, addr):
log("INFO: Client from %s connected" % addr[0])
handleconnect(sock, addr)
sock.close()
def socketpipe(si, so, cid):
global lock, connections
while True:
try:
select.select([si.fileno()], [], [])
buf = si.recv(BUFSIZE)
if not buf:
raise MyError
so.sendall(buf)
except MyError:
lock.acquire()
connections[cid]["open"] = False
si.close()
so.close()
lock.release()
log("INFO: Client closed connection", cid)
break
except socket.error:
break
def handleconnect(sock, addr):
global client_cnt, lock, connections
lock.acquire()
cid = client_cnt
connections.append({"open": False, "src_addr": addr[0]})
client_cnt += 1
lock.release()
version = ord(sock.recv(1))
if version != 5:
log("ERR: Unknown version %d" % version, cid)
return sock.close()
numauthmethods = ord(sock.recv(1))
if numauthmethods <= 0:
log("ERR: Invalid number of authentication methods", cid)
return sock.close()
authsuccess = False
for i in range(0, numauthmethods):
authmet = ord(sock.recv(1))
print(authmet)
if authmet == 0 and AUTHMETHOD == "none":
authsuccess = True
elif authmet == 2 and AUTHMETHOD == "password":
authsuccess = True
if not authsuccess:
log("ERR: No suitable auth method found", cid)
sock.sendall(chr(5) + chr(0xFF))
return sock.close()
if AUTHMETHOD == "password":
authversion = ord(sock.recv(1))
if authversion != 1:
log("ERR: Unknown password authentication version %d" % version, cid)
return sock.close()
unamelen = ord(sock.recv(1))
uname = sock.recv(unamelen)
pswlen = ord(sock.recv(1))
psw = sock.recv(pswlen)
if uname == AM_PSW_USER and psw == AM_PSW_PASS:
sock.sendall(chr(1) + chr(0))
connections[cid]["auth_user"] = uname
else:
sock.sendall(chr(1) + chr(255))
log("WARN: Tried to authenticate with wrong username/password %r/%r" % uname, psw, cid)
return sock.close()
connections[cid]["authmethod"] = AUTHMETHOD
log("INFO: Authentication succeeded", cid)
sock.sendall(chr(5) + chr(0))
version = ord(sock.recv(1))
if version != 5:
log("ERR: Unknown version %d" % version, cid)
return sock.close()
cmd = ord(sock.recv(1))
if cmd != 1:
log("ERR: Unknown command %d" % version, cid)
sock.sendall(chr(5) + chr(7))
return sock.close()
dummy_pf = chr(0) + chr(1) + chr(255) + chr(255) + chr(255) + chr(255) + chr(0) + chr(0)
sock.recv(1)
atype = ord(sock.recv(1))
remote_addr = ""
if atype == 1:
remote_addr = "%d.%d.%d.%d" % (ord(sock.recv(1)), ord(sock.recv(1)), ord(sock.recv(1)), ord(sock.recv(1)))
if remote_addr in IP_BLACKLIST:
log("WARN: Tried to connect to blacklisted IP: %s" % remote_addr, cid)
sock.sendall(chr(5) + chr(2) + dummy_pf)
return sock.close()
hname = ""
elif atype == 3:
l = ord(sock.recv(1))
hname = sock.recv(l)
if hname in DOMAIN_BLACKLIST:
log("WARN: Tried to connect to blacklisted domain: %s" % hname, cid)
sock.sendall(chr(5) + chr(2) + dummy_pf)
return sock.close()
try:
remote_addr = socket.getaddrinfo(hname, 80)[0][4][0]
if remote_addr in IP_BLACKLIST:
log("WARN: Tried to connect to blacklisted IP: %s" % remote_addr, cid)
sock.sendall(chr(5) + chr(2) + dummy_pf)
return sock.close()
except:
log("ERR: Could not resolve '%s'" % hname, cid)
sock.sendall(chr(5) + chr(4) + dummy_pf)
return sock.close()
else:
log("ERR: Unknown address type", cid)
sock.sendall(chr(5) + chr(8) + dummy_pf)
return sock.close()
connections[cid]["remote_addr"] = remote_addr
remote_port = struct.unpack("!H", sock.recv(2))[0]
if remote_port == 0:
log("ERR: Requested connection to port 0", cid)
sock.sendall(chr(5) + chr(1) + dummy_pf)
return sock.close()
if remote_port in PORT_BLACKLIST:
log("WARN: Tried to connect to blacklisted port: %d" % remote_port, cid)
sock.sendall(chr(5) + chr(2) + dummy_pf)
return sock.close()
connections[cid]["remote_port"] = remote_port
remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_sock.connect((remote_addr, remote_port))
if not remote_sock:
log("ERR: Connection to remote failed", cid)
sock.sendall(chr(5) + chr(4) + dummy_pf)
return sock.close()
sock.sendall(chr(5) + chr(0) + dummy_pf)
if hname != "":
hname = " (" + hname + ")"
log("INFO: Successfully connected to %s:%d%s" % (remote_addr, remote_port, hname), cid)
connections[cid]["open"] = True
start_new_thread(socketpipe, (remote_sock, sock, cid))
start_new_thread(socketpipe, (sock, remote_sock, cid))
while True:
time.sleep(30)
if AUTHMETHOD != "none" and AUTHMETHOD != "password":
log("ERR: AUTHMETHOD must be either 'none' or 'password'")
if LOGFILE.strip() != '':
LOGFILE = open(logfile, 'w')
else:
LOGFILE = ''
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
log("SOCKS5 server ready.")
while True:
try:
conn, addr = s.accept()
except KeyboardInterrupt:
break
start_new_thread(hcwrapper, (conn, addr,))
s.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment