Simple and easy to set up SOCKS4/5 proxy server
This project requires Sockslib
pip3 install sockslib
To start, clone the repo, and run sockserver.py
By default, this file will bind to 127.0.0.1:1080
, to change this, go into config.json and change bind_addr.
git clone https://github.com/woo200/pysocksserver;
cd pysocksserver;
python3 sockserver.py;
To set the address the server binds to, find the bind_address
parameter and change it to whatever you want. Ex: "bind_address": ["1.2.3.4", 1234]
File authentication is authentication that is defined by a file with each sign-in separated by newlines, and the username and password separated by a :
. Example: username:password
config.json
"authfile": {
"enabled": true,
"file": "logins.auth"
}
logins.auth
username:password
foo:bar
To enable MySQL authentication, you must first have the mysql connector installed.
pip3 install mysql-connector-python
Once installed, enter the username, password, host, and database name into the config. The program will automatically create a users table that consists of Username (TEXT), and Password (TEXT). Note: the password is stored in plaintext, and is NOT secured. DO NOT USE IN PRODUCTION. If you would like to hash the password you may edit dbauth.py or create your own authentication method. See Implementing Custom Authentication.
"mysql": {
"enabled": false,
"host": "127.0.0.1:3306",
"username": "proxy",
"password": "bopper",
"database": "proxy"
}
The socksserver.SocksServer
class can take up to 4 arguments
- bind - Tuple containing address and port to bind server to
[ REQUIRED ]
- auth - Array of acceptable authentication methods
[ Default: [NoAuth()] ]
- allow_private - Allow proxy access to private IP ranges? (127.0.0.1, 192.168.0.x, 10.0.0.x, etc)
[ Default: False ]
- secure - WIP, Most likely will break server if enabled
[ Default: False ]
- start_server() - Start the proxy server threads [ Note: This function does NOT block ]
Note: Username / Password authentication is only supported by SOCKS5, See ID Authentication for SOCKS4
To enable username / password authentication, you must pass an array of acceptable authentication methods into the server object when you create it. The class that is used for this type of authentication is socksserver.UserPassAuth
. This class takes a dictionary containing username and passwords as such: socksserver.UserPassAuth({"username": "password"})
.
import socksserver
import time
auth = [ # Array of acceptable authentication methods
socksserver.UserPassAuth({ # Username / Password authentication method.
"Username": "password"
})
]
server = socksserver.SocksServer(('127.0.0.1', 1080), auth) # Create the server, and pass in the auth array as the second argument
server.start_server()
while True: # Block
time.sleep(1)
To enable ID authentication, you will use the socksserver.IDAuth
class. This class takes an array of ID's that it will authenticate against.
Following the example above, we can change the auth array to this:
auth = [ # Array of acceptable authentication methods
socksserver.IDAuth([ # ID authentication method. (Socks4)
"Username"
])
]
Note: Custom authentication methods are only supported by SOCKS5.
To implement a custom authetication method, you will create a class that is derived from socksserver.ServerAuthenticationMethod
. This class must contain at least two methods: getId(self) -> int
and authenticate(self, socket) -> bool
The getId
function returns the ID that the server will add to the acceptable auth list. The client will chose an authentication method and the server will check if it can authenticate with that.
def getId(self):
return 0x02 # Example ID
the authenticate
function is called when the client and server agree on an authentication method, and then the authentication is initialized. This function will handle checking whether or not the client should be allowed to continue, or the connection should be terminated. You will be given the direct socket to the client, and will handle authentication yourself. This function returns a boolean, True meaning the server will establish the connection, False meaning it will terminate the connection.
# This is an example taken directly from socksserver.UserPassAuth
def authenticate(self, socket):
ver, idlen = socket.recv(2)
id = socket.recv(idlen)
pwlen, = socket.recv(1)
pw = socket.recv(pwlen)
try:
if id.decode() not in self.user_db:
socket.sendall(b"\x01\x01")
return False
if self.user_db[id.decode()] != pw.decode():
socket.sendall(b"\x01\x01")
return False
except Exception as e:
socket.sendall(b"\x01\x01")
return False
socket.sendall(b"\x01\x00")
return True
This is an example of a class that allows anyone to use the proxy server
import socksserver
class NoAuth(socksserver.ServerAuthenticationMethod):
def getId(self):
return 0x00
def authenticate(self, socket): # Always allow connection
return True
Hooks are used as callbacks to certain events that happen when a client connects or sends a packet. Currently only 3 hooks exist
- connect - Called as soon as a connection is established between client and the server. [ Arguments: sock, addr ]
- handshake_finish - Called when the client and server have finished handshaking and authentication. [ Arguments: requestedConnectionAddr, sock, addr ]
- packet - Called when a packet is sent between client and server [ Arguments: data, sock, origin_addr, socket_type ]
import socksserver
import time
def connect_hook(sock, addr):
print(f"{addr} connected!")
def handshake_finish_hook(requestedConnectionAddr, sock, addr):
print(f"{addr} finished handshaking")
def packet_hook(data, sock, origin_addr, socket_type):
if socket_type == socksserver.SocketType.CLIENT:
print(f"Client sent data: {data}")
elif socket_type == socksserver.SocketType.SERVER:
print(f"Server sent data: {data}")
server = socksserver.SocksServer(('127.0.0.1', 1080)) # Create the server
server.set_hook("connect", connect_hook)
server.set_hook("handshake_finish", handshake_finish_hook)
server.set_hook("packet", packet_hook)
server.start_server()
while True:
time.sleep(1)
If you configure the server with UserPassAuth, due to the fact that socks4 does not support this, the socks4 part of the server will essentially be disabled. To combat this, you may add IDAuth along with UserPassAuth.