File size: 4,747 Bytes
54b7647
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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 = """
    <!DOCTYPE html>
    <html>
        <head>
            <title>WebSocket Proxy Server</title>
            <style>
                body {
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                    background-color: #f4f4f9;
                    color: #333;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    height: 100vh;
                    margin: 0;
                }
                .container {
                    background: white;
                    padding: 40px;
                    border-radius: 10px;
                    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                    text-align: center;
                }
                h1 {
                    color: #2c3e50;
                }
                p {
                    font-size: 1.1em;
                    color: #555;
                }
                .status {
                    display: inline-block;
                    margin-top: 20px;
                    padding: 10px 20px;
                    background-color: #2ecc71;
                    color: white;
                    border-radius: 5px;
                    font-weight: bold;
                }
            </style>
        </head>
        <body>
            <div class="container">
                <h1>Proxy Server Node</h1>
                <p>This server is running and ready to accept WebSocket tunnel connections.</p>
                <div class="status">System Online</div>
            </div>
        </body>
    </html>
    """
    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)