Fix cascade silent dead internet with per-step settings and handshake checks.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-26 06:46:02 +03:00
co-authored by Cursor
parent 8fa7f27223
commit 7230697b7f
5 changed files with 434 additions and 54 deletions
+39 -4
View File
@@ -46,7 +46,7 @@ from managers.awg_manager import AWGManager
from managers.xray_manager import XrayManager
from managers.wireguard_manager import WireGuardManager
from managers.backup_manager import BackupManager
from managers.cascade_manager import CascadeManager
from managers.cascade_manager import CascadeManager, normalize_settings, DEFAULT_SETTINGS as CASCADE_DEFAULT_SETTINGS
import telegram_bot as tg_bot
# Configure logging
@@ -1449,6 +1449,18 @@ class CascadeSetupRequest(BaseModel):
exit_server_id: Optional[int] = None
exit_protocol: str = 'awg2'
enabled: bool = True
# Per-step cascade tuning
pin_exit_route: Optional[bool] = True
remove_eth_masquerade: Optional[bool] = True
force_forward: Optional[bool] = True
mss_clamp: Optional[bool] = True
wait_handshake: Optional[bool] = True
handshake_timeout_sec: Optional[int] = 25
allowed_ips: Optional[str] = '0.0.0.0/0, ::/0'
keep_exit_dns: Optional[bool] = False
vpn_subnet_override: Optional[str] = ''
table_id: Optional[int] = 200
rule_priority: Optional[int] = 100
class ContainerLogsRequest(BaseModel):
@@ -2792,6 +2804,7 @@ async def api_cascade_get(request: Request, server_id: int):
return {
'cascade': cascade,
'live': live,
'defaults': CASCADE_DEFAULT_SETTINGS,
'servers': [
{
'id': i,
@@ -2822,12 +2835,28 @@ async def api_cascade_setup(request: Request, server_id: int, req: CascadeSetupR
if server_id >= len(data['servers']):
return JSONResponse({'error': 'Server not found'}, status_code=404)
entry = data['servers'][server_id]
settings = normalize_settings({
'pin_exit_route': req.pin_exit_route,
'remove_eth_masquerade': req.remove_eth_masquerade,
'force_forward': req.force_forward,
'mss_clamp': req.mss_clamp,
'wait_handshake': req.wait_handshake,
'handshake_timeout_sec': req.handshake_timeout_sec,
'allowed_ips': req.allowed_ips,
'keep_exit_dns': req.keep_exit_dns,
'vpn_subnet_override': req.vpn_subnet_override,
'table_id': req.table_id,
'rule_priority': req.rule_priority,
})
if not req.enabled:
def _disable():
ssh = get_ssh(entry)
ssh.connect()
try:
return CascadeManager(ssh).disable(req.entry_protocol)
return CascadeManager(ssh).disable(
req.entry_protocol,
settings=dict((entry.get('cascade') or {}).get('settings') or settings),
)
finally:
ssh.disconnect()
@@ -2840,6 +2869,7 @@ async def api_cascade_setup(request: Request, server_id: int, req: CascadeSetupR
'entry_protocol': req.entry_protocol or prev.get('entry_protocol'),
'exit_server_id': prev.get('exit_server_id'),
'exit_protocol': prev.get('exit_protocol') or req.exit_protocol,
'settings': settings,
'updated_at': datetime.now().isoformat(timespec='seconds'),
}
await save_data_async(data)
@@ -2914,6 +2944,7 @@ async def api_cascade_setup(request: Request, server_id: int, req: CascadeSetupR
req.entry_protocol,
conf,
exit_srv.get('host') or '',
settings=settings,
)
finally:
entry_ssh.disconnect()
@@ -2928,6 +2959,7 @@ async def api_cascade_setup(request: Request, server_id: int, req: CascadeSetupR
}
info = await asyncio.to_thread(_enable)
applied = info.get('applied') or {}
entry['cascade'] = {
'enabled': True,
'entry_protocol': req.entry_protocol,
@@ -2935,12 +2967,15 @@ async def api_cascade_setup(request: Request, server_id: int, req: CascadeSetupR
'exit_protocol': req.exit_protocol,
'exit_client_id': info['client_id'],
'exit_client_name': info['client_name'],
'up': bool((info.get('applied') or {}).get('up')),
'settings': settings,
'up': bool(applied.get('up')),
'handshake': bool(applied.get('handshake')),
'updated_at': datetime.now().isoformat(timespec='seconds'),
'last_error': None,
'diagnostics': applied.get('diagnostics') or '',
}
await save_data_async(data)
return {'status': 'success', 'cascade': entry['cascade'], 'applied': info.get('applied')}
return {'status': 'success', 'cascade': entry['cascade'], 'applied': applied}
except Exception as e:
logger.exception("Error setting up cascade")
return JSONResponse({'error': str(e)}, status_code=500)