Created
January 21, 2018 20:36
-
-
Save gkbrk/fcd6ada16505e74bb678fd1a073a76eb to your computer and use it in GitHub Desktop.
A SOCKS-over-HTTP tunnel for evading censorship/network filters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import socket | |
import threading | |
import random | |
import time | |
class EvadereSocket: | |
def __init__(self): | |
self.conn = None | |
self.last_activity = time.time() | |
self.id = random.randint(99999, 99999999) | |
self.should_clean = False | |
def connect(self, host, port): | |
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
self.conn.connect((host, port)) | |
def update_timestamp(self): | |
self.last_activity = time.time() | |
class VpnServer: | |
def __init__(self): | |
self.proxy_sockets = [] | |
self.vpn_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
def bind(self, ip="0.0.0.0", port=80): | |
self.vpn_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
self.vpn_socket.bind((ip, port)) | |
self.vpn_socket.listen(15) | |
def handle_connection(self, conn): | |
conn.settimeout(15) | |
conn_file = conn.makefile("rwb") | |
headers = {} | |
method, url, version = conn_file.readline().decode("utf-8").strip().split() | |
print(method, url, version) | |
if method.upper() == "GET" and version.startswith("HTTP/1"): | |
command, *args = url.split("/")[1:] | |
while True: | |
line = conn_file.readline().decode("utf-8").strip() | |
if line == "": | |
break | |
name, value = line.split(":", 1) | |
headers[name.strip()] = value.strip() | |
if command == "connect" and len(args) == 2: | |
# TODO: Exclude local ip addresses | |
print("Creating connection to {}:{}...".format(args[0], args[1])) | |
s = EvadereSocket() | |
s.connect(args[0], int(args[1])) | |
self.proxy_sockets.append(s) | |
conn_file.write(b"HTTP/1.1 200 OK\n") | |
conn_file.write(b"Content-Type: text/html\n") | |
conn_file.write("Content-Length: {}\n\n".format(len(str(s.id))).encode("utf-8")) | |
conn_file.write("{}".format(s.id).encode("utf-8")) | |
conn_file.flush() | |
elif command == "send" and len(args) == 1: | |
for s in self.proxy_sockets: | |
if s.id == int(args[0]): | |
data = conn_file.read(int(headers["Content-Length"])) | |
s.conn.sendall(data) | |
s.update_timestamp() | |
conn_file.write(b"HTTP/1.1 200 OK\n") | |
conn_file.write(b"Content-Type: text/html\n") | |
conn_file.write(b"Content-Length: 4\n\n") | |
conn_file.write(b"DONE") | |
conn_file.flush() | |
elif command == "recv" and len(args) == 1: | |
for s in self.proxy_sockets: | |
if s.id == int(args[0]): | |
data = s.conn.recv(16384) | |
if len(data) == 0: | |
s.should_clean = True | |
s.update_timestamp() | |
conn_file.write(b"HTTP/1.1 200 OK\n") | |
conn_file.write(b"Content-Type: text/html\n") | |
conn_file.write("Content-Length: {}\n\n".format(len(data)).encode("utf-8")) | |
conn_file.write(data) | |
conn_file.flush() | |
elif command == "stats": | |
conn_file.write(b"HTTP/1.1 200 OK\n") | |
conn_file.write("X-Socket-Count: {}\n\n".format(len(self.proxy_sockets)).encode("utf-8")) | |
conn_file.flush() | |
conn.close() | |
def run_threaded(self): | |
while True: | |
try: | |
sock, addr = self.vpn_socket.accept() | |
self.clean_connections() | |
threading.Thread(target=self.handle_connection, args=(sock,)).start() | |
except socket.error as e: | |
print("Socket error: {}".format(e)) | |
except KeyboardInterrupt: | |
break | |
except Exception as e: | |
print("Error: {}".format(e)) | |
def clean_connections(self): | |
current_time = time.time() | |
for s in list(self.proxy_sockets): | |
if current_time - s.last_activity > 2*60: | |
print("Closing EvadereSocket id {} (TIMEOUT)".format(s.id)) | |
s.conn.close() | |
self.proxy_sockets.remove(s) | |
for s in list(self.proxy_sockets): | |
if s.should_clean: | |
s.conn.close() | |
self.proxy_sockets.remove(s) | |
if __name__ == "__main__": | |
server = VpnServer() | |
server.bind(port=1235) | |
server.run_threaded() | |
print("Goodbye!") | |
server.vpn_socket.shutdown(socket.SHUT_RDWR) | |
server.vpn_socket.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import socket | |
import threading | |
import struct | |
import requests | |
headers = {"Host": "www.meb.gov.tr", "User-Agent": "Firefox"} | |
class EvadereClient: | |
def __init__(self, vpn): | |
self.vpn = vpn | |
self.sock_id = None | |
def connect(self, host, port): | |
self.sock_id = int(requests.get("http://{}/connect/{}/{}".format(self.vpn, host, port), headers=headers).text) | |
def send(self, data): | |
requests.get("http://{}/send/{}".format(self.vpn, self.sock_id), data=data, headers=headers).text | |
def recv(self): | |
return requests.get("http://{}/recv/{}".format(self.vpn, self.sock_id), headers=headers).content | |
def handle_connection(conn): | |
socks_version = conn.recv(1)[0] | |
if socks_version == 0x04: | |
command = conn.recv(1)[0] | |
if command == 0x01: | |
port = struct.unpack(">H", conn.recv(2))[0] | |
ip = conn.recv(4) | |
if ip[0] + ip[1] + ip[2] == 0 and ip[3] != 0: | |
b = None | |
while b != 0x00: | |
b = conn.recv(1)[0] | |
hostname = "" | |
while True: | |
b = conn.recv(1) | |
if b[0] == 0x00: | |
break | |
hostname += b.decode("utf-8") | |
conn.sendall(b"\x00\x5A\x00\x60\x01\x01\x01\x01") | |
print("{}:{}".format(hostname, port)) | |
vpn = EvadereClient("gkbrk.com:80") | |
vpn.connect(hostname, port) | |
print(vpn.sock_id) | |
def recv_thread(): | |
while True: | |
data = vpn.recv() | |
if len(data) == 0: | |
break | |
conn.sendall(data) | |
def send_thread(): | |
while True: | |
data = conn.recv(16384) | |
if len(data) == 0: | |
break | |
vpn.send(data) | |
threading.Thread(target=recv_thread).start() | |
threading.Thread(target=send_thread).start() | |
else: | |
ip = "{}.{}.{}.{}".format(*conn.recv(4)) | |
print(ip) | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
s.bind(("0.0.0.0", 1080)) | |
s.listen(15) | |
while True: | |
try: | |
conn, addr = s.accept() | |
threading.Thread(target=handle_connection, args=(conn,)).start() | |
except KeyboardInterrupt: | |
break | |
except Exception as e: | |
print("Error: {}".format(e)) | |
print("Goodbye!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment