CodeNewbie Community 🌱

swiftproxy
swiftproxy

Posted on

Step-by-Step Guide to Building a Simple and Secure Socks5 Proxy in Python

Socks5 proxy is a network protocol that allows clients to forward network connection requests through a proxy server. Compared with Socks4, Socks5 provides a wider range of authentication methods and address type support, including IPv6 and domain name resolution. Creating a simple and secure Socks5 proxy in Python requires support for authentication and correct protocol handling. Here is a step-by-step guide and code examples:

Step 1: Install necessary libraries

Use the standard library socketserver and struct, no additional installation is required.

Step 2: Write Socks5 proxy server code

import socket
import struct
import select
from socketserver import ThreadingTCPServer, BaseRequestHandler

class Socks5ProxyHandler(BaseRequestHandler):
    username = 'admin'  # Change to a safe username
    password = 'password'  # Change to a strong password

    def handle_auth(self):
        data = self.request.recv(1024)
        if not data or data[0] != 0x05:
            self.request.close()
            return False

        # Check whether username and password authentication is supported
        nmethods = data[1]
        methods = data[2:2 + nmethods]
        if 0x02 not in methods:
            self.request.sendall(struct.pack('!BB', 0x05, 0xFF))
            return False

        # Select Username/Password Authentication
        self.request.sendall(struct.pack('!BB', 0x05, 0x02))

        # Handling Authentication
        auth_data = self.request.recv(1024)
        if not auth_data or auth_data[0] != 0x01:
            return False

        ulen = auth_data[1]
        uname = auth_data[2:2 + ulen].decode('utf-8')
        plen = auth_data[2 + ulen]
        passwd = auth_data[3 + ulen:3 + ulen + plen].decode('utf-8')

        if uname == self.username and passwd == self.password:
            self.request.sendall(struct.pack('!BB', 0x01, 0x00))
            return True
        else:
            self.request.sendall(struct.pack('!BB', 0x01, 0x01))
            return False

    def handle_request(self):
        # Receiving client requests
        data = self.request.recv(1024)
        if not data or len(data) < 4:
            return False

        ver, cmd, _, atyp = struct.unpack('!4B', data[:4])
        if ver != 0x05 or cmd != 0x01:  # Only handle CONNECT requests
            self.request.sendall(struct.pack('!8B', 0x05, 0x07, 0x00, 0x01, 0, 0, 0, 0))
            return False

        # Resolve the target address and port
        if atyp == 0x01:  # IPv4
            target_addr = socket.inet_ntop(socket.AF_INET, data[4:8])
            port = struct.unpack('!H', data[8:10])[0]
        elif atyp == 0x03:  # domain name
            domain_len = data[4]
            target_addr = data[5:5 + domain_len].decode('utf-8')
            port = struct.unpack('!H', data[5 + domain_len:5 + domain_len + 2])[0]
        else:
            self.request.sendall(struct.pack('!8B', 0x05, 0x08, 0x00, 0x01, 0, 0, 0, 0))
            return False

        # Connect to the target server
        remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            remote.connect((target_addr, port))
        except Exception as e:
            self.request.sendall(struct.pack('!8B', 0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0))
            return False

        # Response to client connection success
        bind_addr = remote.getsockname()
        response = struct.pack('!4B', 0x05, 0x00, 0x00, 0x01)
        response += socket.inet_aton(bind_addr[0]) + struct.pack('!H', bind_addr[1])
        self.request.sendall(response)

        # Data forwarding
        try:
            while True:
                r, _, _ = select.select([self.request, remote], [], [])
                if self.request in r:
                    data = self.request.recv(4096)
                    if not data:
                        break
                    remote.sendall(data)
                if remote in r:
                    data = remote.recv(4096)
                    if not data:
                        break
                    self.request.sendall(data)
        except:
            pass
        finally:
            remote.close()
            return True

    def handle(self):
        if not self.handle_auth():
            return
        self.handle_request()

if __name__ == '__main__':
    # Start the proxy server on local port 1080
    with ThreadingTCPServer(('0.0.0.0', 1080), Socks5ProxyHandler) as server:
        print("Socks5 proxy server started, listening on port 1080...")
        server.serve_forever()
Enter fullscreen mode Exit fullscreen mode

Step 3: Security Enhancements

  • Strong Password Policy: Modify the default username and password in the example to a complex combination.
  • Restrict Access: Bind to a specific IP (such as 127.0.0.1) instead of 0.0.0.0 to avoid exposure to the public network.
  • Log Monitoring: Add logging capabilities to track connection attempts.
  • Use TLS Tunnel: Wrap proxy traffic with tools such as stunnel to achieve encrypted transmission.

Step 4: Test the Proxy

Use curl to test whether the proxy is working:

curl --socks5 admin:password@127.0.0.1:1080 https://example.com
Enter fullscreen mode Exit fullscreen mode

Notes

  • Protocol support: The example only handles TCP CONNECT requests and is applicable to HTTP/HTTPS.
  • Performance optimization: For high-concurrency scenarios, it is recommended to use asynchronous libraries such as asyncio.
  • Production environment: It is recommended to use mature libraries (such as python-socks) or dedicated proxy software.

Conclusion

This article introduces the need to support authentication and correctly handle protocols to create a simple and secure Socks5 proxy in Python. However, to create a simple and secure Socks5 proxy, you also need to consider the security of authentication mechanisms, encrypted communications, logging, and monitoring.

Top comments (1)

Collapse
 
ericwalter3 profile image
Eric Walter

Great guide on building a simple and secure Socks5 proxy in Python! It covers the essential steps and offers great insights into authentication, protocol handling, and security measures. If you’re looking to take your project further or need expert assistance with Python development, consider hiring freelance Python developers who can help fine-tune your code and add advanced features.