import asyncio
import json
import socket
import dns.resolver # To handle DNS resolution using custom DNS server
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
import uvicorn
app = FastAPI()
# Function to resolve DNS with a custom DNS server (4.2.2.4)
def resolve_with_custom_dns(domain: str, dns_server: str = "4.2.2.4"):
try:
resolver = dns.resolver.Resolver()
resolver.nameservers = [dns_server] # Set the custom DNS server
answers = resolver.resolve(domain)
for answer in answers:
print(f"Resolved {domain} to {answer.to_text()}")
return [answer.to_text() for answer in answers]
except Exception as e:
print(f"[!] Error resolving {domain}: {e}")
return None
@app.get("/")
async def root():
html_content = """
WebSocket Proxy Server
Proxy Server Node
This server is running and ready to accept WebSocket tunnel connections.
System Online
"""
return HTMLResponse(content=html_content, status_code=200)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
# 1. Receive the target destination from the proxy
init_data = await websocket.receive_text()
target = json.loads(init_data)
host = target.get("host")
port = target.get("port")
# 2. Resolve DNS using custom DNS server (4.2.2.4)
#print(f"[*] Resolving DNS for {host} using 4.2.2.4")
resolved_ips = resolve_with_custom_dns(host, dns_server="4.2.2.4")
if resolved_ips is None:
await websocket.send_text(json.dumps({"status": "error", "message": "DNS resolution failed"}))
await websocket.close()
return
# Pick the first resolved IP address
ip = resolved_ips[0]
#print(f"[*] Resolved {host} to {ip}")
# 3. Open TCP connection to the resolved IP
#print(f"[*] Connecting to remote {ip}:{port}")
remote_reader, remote_writer = await asyncio.open_connection(ip, port)
await websocket.send_text(json.dumps({"status": "success"}))
# 4. Forwarding Loops
async def ws_to_tcp():
try:
while True:
data = await websocket.receive_bytes()
remote_writer.write(data)
await remote_writer.drain()
except Exception:
pass
finally:
remote_writer.close()
async def tcp_to_ws():
try:
while True:
data = await remote_reader.read(4096)
if not data:
break
await websocket.send_bytes(data)
except Exception:
pass
finally:
await websocket.close()
await asyncio.gather(ws_to_tcp(), tcp_to_ws())
except Exception as e:
print(f"[!] Server Error: {e}")
try:
await websocket.send_text(json.dumps({"status": "error", "message": str(e)}))
await websocket.close()
except:
pass
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)