{"id":3323,"date":"2023-01-29T16:04:13","date_gmt":"2023-01-29T21:04:13","guid":{"rendered":"https:\/\/dft.wiki\/?p=3323"},"modified":"2026-06-08T17:07:09","modified_gmt":"2026-06-08T21:07:09","slug":"building-custom-socks5-proxy-and-http-proxy","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=3323","title":{"rendered":"Building Custom SOCKS5 Proxy and HTTP Proxy"},"content":{"rendered":"<p><strong>SOCKS5<\/strong> is a widely used proxy protocol for facilitating secure and efficient communication between clients and servers.<\/p>\n<p>Compared to SOCKS4, SOCKS5 adds the following capabilities:<\/p>\n<ul>\n<li>Authentication<\/li>\n<li>IPv6<\/li>\n<li>Domain name resolution (DNS)<\/li>\n<li>UDP association<\/li>\n<\/ul>\n<p>HTTP proxies are even more limited &#8212; they handle HTTP(S) traffic exclusively.<\/p>\n<p><strong>Note:<\/strong> proxy technologies are not encrypted by default, and most are not capable of encryption at all. Proxying a connection is primarily used to evade censorship or bypass geofencing (IP-based blocking).<\/p>\n<ul>\n<li>Why use a private proxy instead of a private VPN?\n<ul>\n<li>When encryption is not required, a SOCKS5 proxy has much lower overhead than a VPN. A single-core VM or container can saturate its network interfaces with minimal latency. A proxy is also easier to scope to a single application (e.g. a secondary browser) rather than routing all traffic from the entire OS or network.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3383 size-medium aligncenter\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2023\/01\/Screenshot-from-2023-01-29-10-02-09-300x137.png\" alt=\"\" width=\"300\" height=\"137\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2023\/01\/Screenshot-from-2023-01-29-10-02-09-300x137.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2023\/01\/Screenshot-from-2023-01-29-10-02-09.png 738w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Note:<\/strong> my internet connection was the bottleneck during the speed test.<\/p>\n<p>It is worth noting that multiple sources online offer frequently updated lists of open proxy servers [<a href=\"https:\/\/github.com\/TheSpeedX\/PROXY-List\">Link<\/a>].<\/p>\n<p>Proxies can also be used to cache static web content and reduce traffic on metered or impaired links [<a href=\"https:\/\/dft.wiki\/?p=2961\">Link<\/a>], though that is outside the scope of this post.<\/p>\n<p>The following examples show how to proxy through another server to access the internet while hiding the real source of the request.<\/p>\n<hr \/>\n<p><strong>GOLANG<\/strong> &#8212; A high-performance proxy written in Go using a third-party module [<a href=\"http:\/\/github.com\/things-go\/go-socks5\">Link<\/a>]:<\/p>\n<p>Create a new file called <code>main.go<\/code> and add the following content:<\/p>\n<pre>package main\r\n\r\nimport (\r\n        \"fmt\"\r\n        \"syscall\"\r\n        \"github.com\/things-go\/go-socks5\"\r\n)\r\n\r\nfunc main() {\r\n        if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &amp;syscall.Rlimit{Max: 65536, Cur: 65536}); err != nil {\r\n                fmt.Println(\"Error setting rlimit:\", err)\r\n        }\r\n\r\n        server := socks5.NewServer()\r\n\r\n        if err := server.ListenAndServe(\"tcp\", \":1080\"); err != nil {\r\n                panic(err)\r\n        }\r\n}\r\n<\/pre>\n<pre>go run main.go<\/pre>\n<p><strong>Note:<\/strong> <code>syscall<\/code> is used here to raise the open file descriptor (connection) limit for the process. The same result can be achieved from the console with <code>ulimit -n 65536<\/code>.<\/p>\n<hr \/>\n<p><strong>PYTHON<\/strong> &#8212; This example requires a username and password for authentication. It is a fork of the code available at [<a href=\"https:\/\/github.com\/rushter\/socks5\">Link<\/a>].<\/p>\n<pre>import select\r\nimport socket\r\nimport struct\r\nfrom socketserver import ForkingTCPServer, TCPServer, StreamRequestHandler\r\n\r\nclass ThreadingTCPServer(ForkingTCPServer, TCPServer):\r\n    pass\r\n\r\n\r\nclass SocksProxy(StreamRequestHandler):\r\n    username = 'username'\r\n    password = 'password'\r\n\r\n    def handle(self):\r\n        # greeting header - read and unpack 2 bytes from a client\r\n        header = self.connection.recv(2)\r\n        version, nmethods = struct.unpack(\"!BB\", header)\r\n\r\n        # socks 5\r\n        assert version == 5\r\n        assert nmethods &gt;= 0\r\n\r\n        # get available methods\r\n        methods = self.get_available_methods(nmethods)\r\n\r\n        # accept only USERNAME\/PASSWORD auth\r\n        if 2 not in set(methods):\r\n            # close connection\r\n            self.server.close_request(self.request)\r\n            return\r\n\r\n        # send welcome message\r\n        self.connection.sendall(struct.pack(\"!BB\", 5, 2))\r\n\r\n        if not self.verify_credentials():\r\n            return\r\n\r\n        # parsing the request\r\n        version, cmd, _, address_type = struct.unpack(\"!BBBB\", self.connection.recv(4))\r\n        assert version == 5\r\n\r\n        if address_type == 1:  # IPv4\r\n            address = socket.inet_ntoa(self.connection.recv(4))\r\n        elif address_type == 3:  # DNS\r\n            try:\r\n                domain_length = self.connection.recv(1)[0]\r\n                address = self.connection.recv(domain_length)\r\n                address = socket.gethostbyname(address)\r\n            except:\r\n                address = '0.0.0.0'\r\n\r\n        port = struct.unpack('!H', self.connection.recv(2))[0]\r\n\r\n        # replying to the request\r\n        try:\r\n            if cmd == 1:\r\n                remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n                remote.connect((address, port))\r\n                bind_address = remote.getsockname()\r\n            else:\r\n                self.server.close_request(self.request)\r\n\r\n            addr = struct.unpack(\"!I\", socket.inet_aton(bind_address[0]))[0]\r\n            port = bind_address[1]\r\n            reply = struct.pack(\"!BBBBIH\", 5, 0, 0, 1,\r\n                                addr, port)\r\n\r\n        except Exception as err:\r\n            reply = self.generate_failed_reply(address_type, 5)\r\n\r\n        self.connection.sendall(reply)\r\n\r\n        # establish data exchange\r\n        if reply[1] == 0 and cmd == 1:\r\n            self.exchange_loop(self.connection, remote)\r\n\r\n        self.server.close_request(self.request)\r\n\r\n    def get_available_methods(self, n):\r\n        methods = []\r\n        for i in range(n):\r\n            methods.append(ord(self.connection.recv(1)))\r\n        return methods\r\n\r\n    def verify_credentials(self):\r\n        piece_of_data = self.connection.recv(1)\r\n        if len(piece_of_data) == 0:\r\n            return\r\n        version = ord(piece_of_data)\r\n        assert version == 1\r\n\r\n        username_len = ord(self.connection.recv(1))\r\n        username = self.connection.recv(username_len).decode('utf-8')\r\n\r\n        password_len = ord(self.connection.recv(1))\r\n        password = self.connection.recv(password_len).decode('utf-8')\r\n\r\n        # set the following flag to True to skip credential checks\r\n        accept_any_creds = False\r\n        if (username == self.username and password == self.password) or accept_any_creds:\r\n            response = struct.pack(\"!BB\", version, 0)\r\n            self.connection.sendall(response)\r\n            return True\r\n\r\n        response = struct.pack(\"!BB\", version, 0xFF)\r\n        self.connection.sendall(response)\r\n        self.server.close_request(self.request)\r\n        return False\r\n\r\n    def generate_failed_reply(self, address_type, error_number):\r\n        return struct.pack(\"!BBBBIH\", 5, error_number, 0, address_type, 0, 0)\r\n\r\n    def exchange_loop(self, client, remote):\r\n\r\n        while True:\r\n\r\n            try:\r\n                # wait until client or remote is available for read\r\n                r, w, e = select.select([client, remote], [], [])\r\n\r\n                if client in r:\r\n                    data = client.recv(4096)\r\n                    if remote.send(data) &lt;= 0:\r\n                        break\r\n\r\n                if remote in r:\r\n                    data = remote.recv(4096)\r\n                    if client.send(data) &lt;= 0:\r\n                        break\r\n            except KeyboardInterrupt:\r\n                self.server.close_request(self.request)\r\n                exit()\r\n            except Exception as err:\r\n                print(err)\r\n\r\nif __name__ == '__main__':\r\n    with ThreadingTCPServer(('0.0.0.0', 1080), SocksProxy) as server:\r\n        try:\r\n            server.serve_forever()\r\n        except:\r\n            pass<\/pre>\n<hr \/>\n<p><strong>BONUS<\/strong><\/p>\n<p>The following PHP script can be dropped onto an existing web server to provide a simple single-request proxy:<\/p>\n<pre>&lt;?php\r\nif ($_SERVER['REQUEST_METHOD'] == 'GET') {\r\n  $url = $_GET['url'];\r\n\r\n  $ch = curl_init();\r\n  curl_setopt($ch, CURLOPT_URL, $url);\r\n  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\r\n  curl_setopt($ch, CURLOPT_HEADER, true);\r\n  curl_setopt($ch, CURLOPT_HTTPHEADER, getallheaders());\r\n\r\n  $response = curl_exec($ch);\r\n  $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);\r\n  $header = substr($response, 0, $header_size);\r\n  $body = substr($response, $header_size);\r\n\r\n  curl_close($ch);\r\n  foreach (explode(\"\\r\\n\", $header) as $header_line) {\r\n    header($header_line);\r\n  }\r\n\r\n  echo $body;\r\n} else {\r\n  die('Invalid request method');\r\n}\r\n?&gt;<\/pre>\n<p>It requires the PHP cURL module:<\/p>\n<pre>sudo apt-get install php-curl -y\r\nsudo systemctl restart apache2<\/pre>\n<p>Usage (file size is limited by the PHP memory limit set in the server configuration):<\/p>\n<pre>curl \"http:\/\/200.200.200.200\/path\/proxy.php?url=https:\/\/7-zip.org\/a\/7z2201-x64.exe\" &gt; 7zip.exe<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>SOCKS5 is a widely used proxy protocol for facilitating secure and efficient communication between clients [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,5],"tags":[],"class_list":["post-3323","post","type-post","status-publish","format-standard","hentry","category-ccna","category-programming"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/3323","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3323"}],"version-history":[{"count":10,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/3323\/revisions"}],"predecessor-version":[{"id":5654,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/3323\/revisions\/5654"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}