Spaces:
Runtime error
Runtime error
Deploy Gradio app with multiple files
Browse files
app.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import threading
|
| 3 |
+
import socket
|
| 4 |
+
import time
|
| 5 |
+
import json
|
| 6 |
+
import requests
|
| 7 |
+
from datetime import datetime
|
| 8 |
+
from typing import Dict, List, Optional
|
| 9 |
+
import logging
|
| 10 |
+
from utils import SOCKS5ProxyServer, ProxyManager
|
| 11 |
+
from config import *
|
| 12 |
+
|
| 13 |
+
# สร้างตัวจัดการ proxy
|
| 14 |
+
proxy_manager = ProxyManager()
|
| 15 |
+
|
| 16 |
+
def start_proxy_server():
|
| 17 |
+
"""เริ่มต้น proxy server"""
|
| 18 |
+
success = proxy_manager.start_server()
|
| 19 |
+
if success:
|
| 20 |
+
return "✅ เริ่มต้น Proxy Server สำเร็จ"
|
| 21 |
+
else:
|
| 22 |
+
return "❌ ไม่สามารถเริ่มต้น Proxy Server ได้"
|
| 23 |
+
|
| 24 |
+
def stop_proxy_server():
|
| 25 |
+
"""หยุด proxy server"""
|
| 26 |
+
proxy_manager.stop_server()
|
| 27 |
+
return "🛑 หยุด Proxy Server แล้ว"
|
| 28 |
+
|
| 29 |
+
def restart_proxy_server():
|
| 30 |
+
"""รีสตาร์ท proxy server"""
|
| 31 |
+
proxy_manager.stop_server()
|
| 32 |
+
time.sleep(1)
|
| 33 |
+
success = proxy_manager.start_server()
|
| 34 |
+
if success:
|
| 35 |
+
return "🔄 รีสตาร์ท Proxy Server สำเร็จ"
|
| 36 |
+
else:
|
| 37 |
+
return "❌ ไม่สามารถรีสตาร์ท Proxy Server ได้"
|
| 38 |
+
|
| 39 |
+
def get_current_proxy_url():
|
| 40 |
+
"""ดึง URL proxy ปัจจุบัน"""
|
| 41 |
+
if proxy_manager.is_running():
|
| 42 |
+
return f"socks5://localhost:{PROXY_PORT}"
|
| 43 |
+
return "ไม่ได้เชื่อมต่อ"
|
| 44 |
+
|
| 45 |
+
def get_server_info():
|
| 46 |
+
"""ดึงข้อมูล server"""
|
| 47 |
+
return json.dumps(proxy_manager.get_server_info(), indent=2, ensure_ascii=False)
|
| 48 |
+
|
| 49 |
+
def get_usage_stats():
|
| 50 |
+
"""ดึงสถิติการใช้งาน"""
|
| 51 |
+
return json.dumps(proxy_manager.get_usage_stats(), indent=2, ensure_ascii=False)
|
| 52 |
+
|
| 53 |
+
def get_user_stats():
|
| 54 |
+
"""ดึงข้อมูลผู้ใช้"""
|
| 55 |
+
return json.dumps(proxy_manager.get_user_stats(), indent=2, ensure_ascii=False)
|
| 56 |
+
|
| 57 |
+
def get_connection_logs():
|
| 58 |
+
"""ดึง log การเชื่อมต่อ"""
|
| 59 |
+
return json.dumps(proxy_manager.get_recent_logs(), indent=2, ensure_ascii=False)
|
| 60 |
+
|
| 61 |
+
def refresh_all():
|
| 62 |
+
"""รีเฟรชข้อมูลทั้งหมด"""
|
| 63 |
+
return (
|
| 64 |
+
get_current_proxy_url(),
|
| 65 |
+
get_server_info(),
|
| 66 |
+
get_usage_stats(),
|
| 67 |
+
get_user_stats(),
|
| 68 |
+
get_connection_logs()
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
def setup_interface():
|
| 72 |
+
"""สร้าง Gradio interface"""
|
| 73 |
+
|
| 74 |
+
# Custom CSS สำหรับ styling
|
| 75 |
+
css = """
|
| 76 |
+
.main-container {
|
| 77 |
+
max-width: 1200px;
|
| 78 |
+
margin: auto;
|
| 79 |
+
padding: 20px;
|
| 80 |
+
}
|
| 81 |
+
.status-indicator {
|
| 82 |
+
padding: 10px;
|
| 83 |
+
border-radius: 5px;
|
| 84 |
+
margin: 5px 0;
|
| 85 |
+
}
|
| 86 |
+
.status-running {
|
| 87 |
+
background-color: #d4edda;
|
| 88 |
+
color: #155724;
|
| 89 |
+
border: 1px solid #c3e6cb;
|
| 90 |
+
}
|
| 91 |
+
.status-stopped {
|
| 92 |
+
background-color: #f8d7da;
|
| 93 |
+
color: #721c24;
|
| 94 |
+
border: 1px solid #f5c6cb;
|
| 95 |
+
}
|
| 96 |
+
.info-box {
|
| 97 |
+
background-color: #e9ecef;
|
| 98 |
+
padding: 15px;
|
| 99 |
+
border-radius: 5px;
|
| 100 |
+
margin: 10px 0;
|
| 101 |
+
border-left: 4px solid #007bff;
|
| 102 |
+
}
|
| 103 |
+
.stats-grid {
|
| 104 |
+
display: grid;
|
| 105 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 106 |
+
gap: 15px;
|
| 107 |
+
margin: 20px 0;
|
| 108 |
+
}
|
| 109 |
+
.stat-card {
|
| 110 |
+
background: white;
|
| 111 |
+
padding: 15px;
|
| 112 |
+
border-radius: 8px;
|
| 113 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| 114 |
+
border: 1px solid #dee2e6;
|
| 115 |
+
}
|
| 116 |
+
.stat-number {
|
| 117 |
+
font-size: 24px;
|
| 118 |
+
font-weight: bold;
|
| 119 |
+
color: #007bff;
|
| 120 |
+
}
|
| 121 |
+
.stat-label {
|
| 122 |
+
color: #6c757d;
|
| 123 |
+
font-size: 14px;
|
| 124 |
+
}
|
| 125 |
+
"""
|
| 126 |
+
|
| 127 |
+
with gr.Blocks(css=css, title="SOCKS5 Proxy Dashboard") as demo:
|
| 128 |
+
gr.HTML("""
|
| 129 |
+
<div class="main-container">
|
| 130 |
+
<div style="text-align: center; margin-bottom: 30px;">
|
| 131 |
+
<h1>🔒 SOCKS5 Proxy Server Dashboard</h1>
|
| 132 |
+
<p style="color: #6c757d;">ระบบจัดการ SOCKS5 Proxy Server พร้อมการติดตามการใช้งาน</p>
|
| 133 |
+
<div style="margin-top: 10px;">
|
| 134 |
+
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="text-decoration: none; color: #007bff; font-weight: bold;">Built with anycoder</a>
|
| 135 |
+
</div>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
""")
|
| 139 |
+
|
| 140 |
+
# สถานะปัจจุบัน
|
| 141 |
+
with gr.Row():
|
| 142 |
+
with gr.Column(scale=1):
|
| 143 |
+
gr.HTML('<h3>🎮 การควบคุม</h3>')
|
| 144 |
+
with gr.Row():
|
| 145 |
+
start_btn = gr.Button("▶️ เริ่มต้น", variant="primary", size="lg")
|
| 146 |
+
stop_btn = gr.Button("⏹️ หยุด", variant="stop", size="lg")
|
| 147 |
+
restart_btn = gr.Button("🔄 รีสตาร์ท", variant="secondary", size="lg")
|
| 148 |
+
|
| 149 |
+
status_html = gr.HTML()
|
| 150 |
+
proxy_url_output = gr.Textbox(
|
| 151 |
+
label="🌐 Proxy URL ปัจจุบัน",
|
| 152 |
+
value=get_current_proxy_url,
|
| 153 |
+
interactive=False,
|
| 154 |
+
elem_classes=["info-box"]
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
with gr.Column(scale=2):
|
| 158 |
+
gr.HTML('<h3>📊 สถิติการใช้งาน</h3>')
|
| 159 |
+
with gr.Row():
|
| 160 |
+
total_connections = gr.Number(label="📈 การเชื่อมต่อทั้งหมด", value=0)
|
| 161 |
+
active_connections = gr.Number(label="🔗 การเชื่อมต่อที่กำลังใช้งาน", value=0)
|
| 162 |
+
bandwidth_used = gr.Number(label="📊 Bandwidth ใช้งาน (MB)", value=0)
|
| 163 |
+
|
| 164 |
+
uptime_output = gr.Textbox(
|
| 165 |
+
label="⏱️ เวลาทำงาน",
|
| 166 |
+
interactive=False,
|
| 167 |
+
value="00:00:00"
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
# ข้อมูลผู้ใช้
|
| 171 |
+
with gr.Tab("👥 ผู้ใช้งาน"):
|
| 172 |
+
user_stats = gr.JSON(
|
| 173 |
+
label="ข้อมูลผู้ใช้ทั้งหมด",
|
| 174 |
+
value=get_user_stats
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
# ข้อมูล Server
|
| 178 |
+
with gr.Tab("🖥️ ข้อมูล Server"):
|
| 179 |
+
server_info = gr.JSON(
|
| 180 |
+
label="ข้อมูล Server",
|
| 181 |
+
value=get_server_info
|
| 182 |
+
)
|
| 183 |
+
|
| 184 |
+
# สถิติการใช้งาน
|
| 185 |
+
with gr.Tab("📊 สถิติ"):
|
| 186 |
+
usage_stats = gr.JSON(
|
| 187 |
+
label="สถิติการใช้งาน",
|
| 188 |
+
value=get_usage_stats
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
# ล็อก
|
| 192 |
+
with gr.Tab("📝 ล็อก"):
|
| 193 |
+
logs = gr.JSON(
|
| 194 |
+
label="ล็อกการเชื่อมต่อล่าสุด",
|
| 195 |
+
value=get_connection_logs
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
# ปุ่มรีเฟรช
|
| 199 |
+
with gr.Row():
|
| 200 |
+
refresh_btn = gr.Button("🔄 รีเฟรชข้อมูลทั้งหมด", variant="primary")
|
| 201 |
+
|
| 202 |
+
# ผูก events
|
| 203 |
+
start_btn.click(start_proxy_server, outputs=proxy_url_output)
|
| 204 |
+
stop_btn.click(stop_proxy_server, outputs=proxy_url_output)
|
| 205 |
+
restart_btn.click(restart_proxy_server, outputs=proxy_url_output)
|
| 206 |
+
refresh_btn.click(
|
| 207 |
+
refresh_all,
|
| 208 |
+
outputs=[
|
| 209 |
+
proxy_url_output,
|
| 210 |
+
server_info,
|
| 211 |
+
usage_stats,
|
| 212 |
+
user_stats,
|
| 213 |
+
logs
|
| 214 |
+
]
|
| 215 |
+
)
|
| 216 |
+
|
| 217 |
+
# อัปเดตข้อมูลอัตโนมัติ
|
| 218 |
+
demo.load(
|
| 219 |
+
refresh_all,
|
| 220 |
+
outputs=[
|
| 221 |
+
proxy_url_output,
|
| 222 |
+
server_info,
|
| 223 |
+
usage_stats,
|
| 224 |
+
user_stats,
|
| 225 |
+
logs
|
| 226 |
+
]
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
return demo
|
| 230 |
+
|
| 231 |
+
if __name__ == "__main__":
|
| 232 |
+
# สร้าง interface
|
| 233 |
+
demo = setup_interface()
|
| 234 |
+
|
| 235 |
+
# เริ่มต้น proxy server อัตโนมัติ
|
| 236 |
+
proxy_manager.start_server()
|
| 237 |
+
|
| 238 |
+
# เริ่ม UI
|
| 239 |
+
demo.launch(
|
| 240 |
+
server_name="0.0.0.0",
|
| 241 |
+
server_port=8080,
|
| 242 |
+
show_api=False,
|
| 243 |
+
title="SOCKS5 Proxy Dashboard"
|
| 244 |
+
)
|
config.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# การตั้งค่า SOCKS5 Proxy Server
|
| 2 |
+
PROXY_HOST = "0.0.0.0"
|
| 3 |
+
PROXY_PORT = 1080
|
| 4 |
+
|
| 5 |
+
# การตั้งค่า Web Interface
|
| 6 |
+
WEB_HOST = "0.0.0.0"
|
| 7 |
+
WEB_PORT = 8080
|
| 8 |
+
|
| 9 |
+
# การตั้งค่า Logging
|
| 10 |
+
LOG_LEVEL = "INFO"
|
| 11 |
+
LOG_FILE = "proxy.log"
|
| 12 |
+
|
| 13 |
+
# การตั้งค่าอื่นๆ
|
| 14 |
+
MAX_CONNECTIONS = 100
|
| 15 |
+
CONNECTION_TIMEOUT = 300 # วินาที
|
| 16 |
+
BUFFER_SIZE = 4096 # bytes
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
requests
|
utils.py
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import socket
|
| 2 |
+
import threading
|
| 3 |
+
import time
|
| 4 |
+
import json
|
| 5 |
+
import logging
|
| 6 |
+
from datetime import datetime, timedelta
|
| 7 |
+
from typing import Dict, List, Optional
|
| 8 |
+
from dataclasses import dataclass
|
| 9 |
+
import struct
|
| 10 |
+
|
| 11 |
+
@dataclass
|
| 12 |
+
class ConnectionInfo:
|
| 13 |
+
ip: str
|
| 14 |
+
port: int
|
| 15 |
+
start_time: datetime
|
| 16 |
+
bytes_sent: int = 0
|
| 17 |
+
bytes_received: int = 0
|
| 18 |
+
is_active: bool = True
|
| 19 |
+
|
| 20 |
+
class SOCKS5ProxyServer:
|
| 21 |
+
def __init__(self, host='0.0.0.0', port=1080):
|
| 22 |
+
self.host = host
|
| 23 |
+
self.port = port
|
| 24 |
+
self.server_socket = None
|
| 25 |
+
self.running = False
|
| 26 |
+
self.connections: Dict[str, ConnectionInfo] = {}
|
| 27 |
+
self.total_connections = 0
|
| 28 |
+
self.start_time = None
|
| 29 |
+
self._lock = threading.Lock()
|
| 30 |
+
|
| 31 |
+
def start(self):
|
| 32 |
+
"""เริ่มต้น SOCKS5 proxy server"""
|
| 33 |
+
try:
|
| 34 |
+
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 35 |
+
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
| 36 |
+
self.server_socket.bind((self.host, self.port))
|
| 37 |
+
self.server_socket.listen(50)
|
| 38 |
+
self.running = True
|
| 39 |
+
self.start_time = datetime.now()
|
| 40 |
+
|
| 41 |
+
logging.info(f"SOCKS5 Proxy Server เริ่มต้นที่ {self.host}:{self.port}")
|
| 42 |
+
|
| 43 |
+
# เริ่ม thread สำหรับ accept connections
|
| 44 |
+
threading.Thread(target=self._accept_connections, daemon=True).start()
|
| 45 |
+
|
| 46 |
+
return True
|
| 47 |
+
except Exception as e:
|
| 48 |
+
logging.error(f"เริ่มต้น proxy server ผิดพลาด: {e}")
|
| 49 |
+
return False
|
| 50 |
+
|
| 51 |
+
def stop(self):
|
| 52 |
+
"""หยุด SOCKS5 proxy server"""
|
| 53 |
+
self.running = False
|
| 54 |
+
if self.server_socket:
|
| 55 |
+
try:
|
| 56 |
+
self.server_socket.close()
|
| 57 |
+
except:
|
| 58 |
+
pass
|
| 59 |
+
logging.info("SOCKS5 Proxy Server หยุดทำงาน")
|
| 60 |
+
|
| 61 |
+
def _accept_connections(self):
|
| 62 |
+
"""รับการเชื่อมต่อใหม่"""
|
| 63 |
+
while self.running:
|
| 64 |
+
try:
|
| 65 |
+
client_socket, client_address = self.server_socket.accept()
|
| 66 |
+
client_ip, client_port = client_address
|
| 67 |
+
|
| 68 |
+
# บันทึกการเชื่อมต่อ
|
| 69 |
+
with self._lock:
|
| 70 |
+
self.connections[f"{client_ip}:{client_port}"] = ConnectionInfo(
|
| 71 |
+
ip=client_ip,
|
| 72 |
+
port=client_port,
|
| 73 |
+
start_time=datetime.now()
|
| 74 |
+
)
|
| 75 |
+
self.total_connections += 1
|
| 76 |
+
|
| 77 |
+
# สร้าง thread สำหรับจัดการการเชื่อมต่อ
|
| 78 |
+
threading.Thread(
|
| 79 |
+
target=self._handle_client,
|
| 80 |
+
args=(client_socket, client_ip, client_port),
|
| 81 |
+
daemon=True
|
| 82 |
+
).start()
|
| 83 |
+
|
| 84 |
+
except socket.error:
|
| 85 |
+
if self.running:
|
| 86 |
+
logging.error("Error ในการรับการเชื่อมต่อ")
|
| 87 |
+
break
|
| 88 |
+
|
| 89 |
+
def _handle_client(self, client_socket, client_ip, client_port):
|
| 90 |
+
"""จัดการการเชื่อมต่อจาก client"""
|
| 91 |
+
try:
|
| 92 |
+
# SOCKS5 handshake
|
| 93 |
+
if not self._handle_socks5_handshake(client_socket):
|
| 94 |
+
return
|
| 95 |
+
|
| 96 |
+
# รับคำขอจาก client
|
| 97 |
+
request = client_socket.recv(1024)
|
| 98 |
+
if len(request) < 10:
|
| 99 |
+
return
|
| 100 |
+
|
| 101 |
+
# แยกคำขอ SOCKS5
|
| 102 |
+
if request[0] != 0x05: # Version 5
|
| 103 |
+
return
|
| 104 |
+
|
| 105 |
+
cmd = request[1] # Command
|
| 106 |
+
addr_type = request[3] # Address type
|
| 107 |
+
|
| 108 |
+
if cmd == 0x01: # CONNECT
|
| 109 |
+
self._handle_connect(client_socket, request, client_ip, client_port)
|
| 110 |
+
elif cmd == 0x02: # BIND
|
| 111 |
+
self._handle_bind(client_socket, client_ip, client_port)
|
| 112 |
+
elif cmd == 0x03: # UDP ASSOCIATE
|
| 113 |
+
self._handle_udp_associate(client_socket, client_ip, client_port)
|
| 114 |
+
|
| 115 |
+
except Exception as e:
|
| 116 |
+
logging.error(f"Error ในการจัดการ client {client_ip}:{client_port}: {e}")
|
| 117 |
+
finally:
|
| 118 |
+
# ปิดการเชื่อมต่อ
|
| 119 |
+
try:
|
| 120 |
+
client_socket.close()
|
| 121 |
+
except:
|
| 122 |
+
pass
|
| 123 |
+
|
| 124 |
+
# อัปเดตสถานะ
|
| 125 |
+
with self._lock:
|
| 126 |
+
if f"{client_ip}:{client_port}" in self.connections:
|
| 127 |
+
self.connections[f"{client_ip}:{client_port}"].is_active = False
|
| 128 |
+
|
| 129 |
+
def _handle_socks5_handshake(self, client_socket):
|
| 130 |
+
"""จัดการ SOCKS5 handshake"""
|
| 131 |
+
try:
|
| 132 |
+
# ��ับ client hello
|
| 133 |
+
data = client_socket.recv(1024)
|
| 134 |
+
if len(data) < 2:
|
| 135 |
+
return False
|
| 136 |
+
|
| 137 |
+
version = data[0]
|
| 138 |
+
nmethods = data[1]
|
| 139 |
+
|
| 140 |
+
if version != 0x05: # Version 5
|
| 141 |
+
return False
|
| 142 |
+
|
| 143 |
+
# ตอบกลับว่าใช้ no authentication
|
| 144 |
+
response = b'\x05\x00'
|
| 145 |
+
client_socket.send(response)
|
| 146 |
+
return True
|
| 147 |
+
|
| 148 |
+
except Exception as e:
|
| 149 |
+
logging.error(f"Handshake error: {e}")
|
| 150 |
+
return False
|
| 151 |
+
|
| 152 |
+
def _handle_connect(self, client_socket, request, client_ip, client_port):
|
| 153 |
+
"""จัดการ SOCKS5 CONNECT command"""
|
| 154 |
+
try:
|
| 155 |
+
addr_type = request[3]
|
| 156 |
+
dest_addr = ""
|
| 157 |
+
dest_port = 0
|
| 158 |
+
|
| 159 |
+
if addr_type == 0x01: # IPv4
|
| 160 |
+
dest_ip = socket.inet_ntoa(request[4:8])
|
| 161 |
+
dest_port = struct.unpack('!H', request[8:10])[0]
|
| 162 |
+
dest_addr = dest_ip
|
| 163 |
+
elif addr_type == 0x03: # Domain name
|
| 164 |
+
domain_length = request[4]
|
| 165 |
+
dest_addr = request[5:5+domain_length].decode('utf-8')
|
| 166 |
+
dest_port = struct.unpack('!H', request[5+domain_length:7+domain_length])[0]
|
| 167 |
+
elif addr_type == 0x04: # IPv6
|
| 168 |
+
dest_ip = socket.inet_ntop(socket.AF_INET6, request[4:20])
|
| 169 |
+
dest_port = struct.unpack('!H', request[20:22])[0]
|
| 170 |
+
dest_addr = dest_ip
|
| 171 |
+
|
| 172 |
+
# เชื่อมต่อไปยังเป้าหมาย
|
| 173 |
+
target_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 174 |
+
target_socket.connect((dest_addr, dest_port))
|
| 175 |
+
|
| 176 |
+
# ตอบกลับว่าสำเร็จ
|
| 177 |
+
reply = b'\x05\x00\x00\x01' + socket.inet_aton('0.0.0.0') + b'\x00\x00'
|
| 178 |
+
client_socket.send(reply)
|
| 179 |
+
|
| 180 |
+
# เริ่มตัวกลางข้อมูล
|
| 181 |
+
threading.Thread(
|
| 182 |
+
target=self._relay_data,
|
| 183 |
+
args=(client_socket, target_socket, client_ip, client_port),
|
| 184 |
+
daemon=True
|
| 185 |
+
).start()
|
| 186 |
+
|
| 187 |
+
logging.info(f"CONNECT: {client_ip}:{client_port} -> {dest_addr}:{dest_port}")
|
| 188 |
+
|
| 189 |
+
except Exception as e:
|
| 190 |
+
# ส่ง error response
|
| 191 |
+
reply = b'\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'
|
| 192 |
+
try:
|
| 193 |
+
client_socket.send(reply)
|
| 194 |
+
except:
|
| 195 |
+
pass
|
| 196 |
+
logging.error(f"CONNECT error: {e}")
|
| 197 |
+
|
| 198 |
+
def _handle_bind(self, client_socket, client_ip, client_port):
|
| 199 |
+
"""จัดการ SOCKS5 BIND command"""
|
| 200 |
+
# BIND command implementation (สำหรับ incoming connections)
|
| 201 |
+
reply = b'\x05\x07\x00\x01\x00\x00\x00\x00\x00\x00' # Command not supported
|
| 202 |
+
try:
|
| 203 |
+
client_socket.send(reply)
|
| 204 |
+
except:
|
| 205 |
+
pass
|
| 206 |
+
|
| 207 |
+
def _handle_udp_associate(self, client_socket, client_ip, client_port):
|
| 208 |
+
"""จัดการ SOCKS5 UDP ASSOCIATE command"""
|
| 209 |
+
# UDP ASSOCIATE implementation
|
| 210 |
+
reply = b'\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00'
|
| 211 |
+
try:
|
| 212 |
+
client_socket.send(reply)
|
| 213 |
+
except:
|
| 214 |
+
pass
|
| 215 |
+
|
| 216 |
+
def _relay_data(self, client_socket, target_socket, client_ip, client_port):
|
| 217 |
+
"""ส่งข้อมูลระหว่าง client และ target"""
|
| 218 |
+
try:
|
| 219 |
+
while True:
|
| 220 |
+
try:
|
| 221 |
+
data = client_socket.recv(4096)
|
| 222 |
+
if not data:
|
| 223 |
+
break
|
| 224 |
+
|
| 225 |
+
# ส่งต่อไปยัง target
|
| 226 |
+
target_socket.send(data)
|
| 227 |
+
|
| 228 |
+
# อัปเดตสถิติ
|
| 229 |
+
with self._lock:
|
| 230 |
+
if f"{client_ip}:{client_port}" in self.connections:
|
| 231 |
+
conn = self.connections[f"{client_ip}:{client_port}"]
|
| 232 |
+
conn.bytes_sent += len(data)
|
| 233 |
+
|
| 234 |
+
except socket.error:
|
| 235 |
+
break
|
| 236 |
+
|
| 237 |
+
try:
|
| 238 |
+
data = target_socket.recv(4096)
|
| 239 |
+
if not data:
|
| 240 |
+
break
|
| 241 |
+
|
| 242 |
+
# ส่งต่อกลับไปยัง client
|
| 243 |
+
client_socket.send(data)
|
| 244 |
+
|
| 245 |
+
# อัปเดตสถิติ
|
| 246 |
+
with self._lock:
|
| 247 |
+
if f"{client_ip}:{client_port}" in self.connections:
|
| 248 |
+
conn = self.connections[f"{client_ip}:{client_port}"]
|
| 249 |
+
conn.bytes_received += len(data)
|
| 250 |
+
|
| 251 |
+
except socket.error:
|
| 252 |
+
break
|
| 253 |
+
|
| 254 |
+
except Exception as e:
|
| 255 |
+
logging.error(f"Relay error: {e}")
|
| 256 |
+
finally:
|
| 257 |
+
try:
|
| 258 |
+
client_socket.close()
|
| 259 |
+
target_socket.close()
|
| 260 |
+
except:
|
| 261 |
+
pass
|
| 262 |
+
|
| 263 |
+
class ProxyManager:
|
| 264 |
+
def __init__(self, host='0.0.0.0', port=1080):
|
| 265 |
+
self.proxy_server = SOCKS5ProxyServer(host, port)
|
| 266 |
+
self.host = host
|
| 267 |
+
self.port = port
|
| 268 |
+
|
| 269 |
+
def start_server(self):
|
| 270 |
+
"""เริ่มต้น proxy server"""
|
| 271 |
+
return self.proxy_server.start()
|
| 272 |
+
|
| 273 |
+
def stop_server(self):
|
| 274 |
+
"""หยุด proxy server"""
|
| 275 |
+
self.proxy_server.stop()
|
| 276 |
+
|
| 277 |
+
def is_running(self):
|
| 278 |
+
"""ตรวจสอบว่า server กำลังทำงานอยู่หรือไม่"""
|
| 279 |
+
return self.proxy_server.running
|
| 280 |
+
|
| 281 |
+
def get_server_info(self):
|
| 282 |
+
"""ดึงข้อมูล server"""
|
| 283 |
+
info = {
|
| 284 |
+
"server_status": "รันอยู่" if self.proxy_server.running else "หยุดทำงาน",
|
| 285 |
+
"host": self.proxy_server.host,
|
| 286 |
+
"port": self.proxy_server.port,
|
| 287 |
+
"version": "SOCKS5",
|
| 288 |
+
"authentication": "ไม่ต้องยืนยันตัวตน",
|
| 289 |
+
"start_time": self.proxy_server.start_time.isoformat() if self.proxy_server.start_time else None,
|
| 290 |
+
"uptime": str(datetime.now() - self.proxy_server.start_time) if self.proxy_server.start_time else "00:00:00"
|
| 291 |
+
}
|
| 292 |
+
return info
|
| 293 |
+
|
| 294 |
+
def get_usage_stats(self):
|
| 295 |
+
"""ดึงสถิติการใช้งาน"""
|
| 296 |
+
total_connections = len([c for c in self.proxy_server.connections.values() if not c.is_active])
|
| 297 |
+
active_connections = len([c for c in self.proxy_server.connections.values() if c.is_active])
|
| 298 |
+
|
| 299 |
+
total_bytes = sum(c.bytes_sent + c.bytes_received for c in self.proxy_server.connections.values())
|
| 300 |
+
|
| 301 |
+
stats = {
|
| 302 |
+
"total_connections": total_connections,
|
| 303 |
+
"active_connections": active_connections,
|
| 304 |
+
"total_bandwidth_bytes": total_bytes,
|
| 305 |
+
"total_bandwidth_mb": round(total_bytes / (1024 * 1024), 2),
|
| 306 |
+
"peak_concurrent": max(active_connections, 0),
|
| 307 |
+
"average_session_duration": "ไม่มีข้อมูล"
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
return stats
|
| 311 |
+
|
| 312 |
+
def get_user_stats(self):
|
| 313 |
+
"""ดึงข้อมูลผู้ใช้"""
|
| 314 |
+
users = []
|
| 315 |
+
for conn_id, conn in self.proxy_server.connections.items():
|
| 316 |
+
users.append({
|
| 317 |
+
"id": conn_id,
|
| 318 |
+
"ip": conn.ip,
|
| 319 |
+
"port": conn.port,
|
| 320 |
+
"connected_since": conn.start_time.isoformat(),
|
| 321 |
+
"is_active": conn.is_active,
|
| 322 |
+
"bytes_sent": conn.bytes_sent,
|
| 323 |
+
"bytes_received": conn.bytes_received,
|
| 324 |
+
"total_bytes": conn.bytes_sent + conn.bytes_received,
|
| 325 |
+
"session_duration": str(datetime.now() - conn.start_time)
|
| 326 |
+
})
|
| 327 |
+
|
| 328 |
+
return {
|
| 329 |
+
"total_users": len(users),
|
| 330 |
+
"active_users": len([u for u in users if u["is_active"]]),
|
| 331 |
+
"users": users
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
def get_recent_logs(self):
|
| 335 |
+
"""ดึงล็อกการเชื่อมต่อล่าสุด"""
|
| 336 |
+
logs = []
|
| 337 |
+
for conn_id, conn in self.proxy_server.connections.items():
|
| 338 |
+
logs.append({
|
| 339 |
+
"timestamp": conn.start_time.isoformat(),
|
| 340 |
+
"client": f"{conn.ip}:{conn.port}",
|
| 341 |
+
"status": "เชื่อมต่ออยู่" if conn.is_active else "เสร็จสิ้น",
|
| 342 |
+
"bytes_transferred": conn.bytes_sent + conn.bytes_received,
|
| 343 |
+
"session_duration": str(datetime.now() - conn.start_time)
|
| 344 |
+
})
|
| 345 |
+
|
| 346 |
+
# เรียงตามเวลาใหม่สุดก่อน
|
| 347 |
+
logs.sort(key=lambda x: x["timestamp"], reverse=True)
|
| 348 |
+
|
| 349 |
+
return {
|
| 350 |
+
"recent_connections": logs[:50], # แสดง 50 รายการล่าสุด
|
| 351 |
+
"total_log_entries": len(logs)
|
| 352 |
+
}
|