Add TCP ping fallback for servers that block ICMP (XRay, VLESS, Reality)

Made-with: Cursor
This commit is contained in:
anten-ka
2026-03-07 15:08:58 +03:00
parent ee13a9e512
commit f4dc06b09c
3 changed files with 119 additions and 7 deletions

23
_ssh_debug.py Normal file
View File

@@ -0,0 +1,23 @@
import paramiko, sys
host = "185.250.47.205"
user = "root"
pwd = "0i1sbf9NM36FkG5dFH"
def run(cmd, timeout=30):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=user, password=pwd, timeout=10)
stdin, stdout, stderr = ssh.exec_command(cmd, timeout=timeout)
out = stdout.read().decode(errors="replace")
err = stderr.read().decode(errors="replace")
rc = stdout.channel.recv_exit_status()
ssh.close()
return rc, out, err
if __name__ == "__main__":
cmd = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "echo ok"
rc, out, err = run(cmd)
if out: print(out, end="")
if err: print("STDERR:", err, end="")
print(f"\n[exit {rc}]")

58
_test_tcp_ping.py Normal file
View File

@@ -0,0 +1,58 @@
import paramiko
host = "185.250.47.205"
user = "root"
pwd = "0i1sbf9NM36FkG5dFH"
test_script = """#!/bin/bash
tcp_ping() {
local ip="$1" port="$2" tout="${3:-3}"
local raw
raw=$(curl -so /dev/null -w '%{time_connect}' --max-time "$tout" --connect-timeout "$tout" "http://${ip}:${port}/" 2>/dev/null)
[ -z "$raw" ] && return 1
local ms
ms=$(awk "BEGIN {v=$raw*1000; if(v<0.5) exit 1; printf \\"%.2f\\", v}" 2>/dev/null) || return 1
echo "$ms"
}
smart_ping() {
local ip="$1" tout="${2:-3}" port="${3:-}"
local ms
ms=$(ping -c 1 -W "$tout" "$ip" 2>/dev/null | sed -n 's/.*time=\\([0-9.]*\\).*/\\1/p')
if [ -n "$ms" ]; then echo "ICMP: ${ms}ms"; return 0; fi
[ -z "$port" ] && { echo "NO_PORT"; return 1; }
ms=$(tcp_ping "$ip" "$port" "$tout")
if [ -n "$ms" ]; then echo "TCP: ${ms}ms"; return 0; fi
echo "TIMEOUT"
return 1
}
echo "=== Test 1: ICMP to 8.8.8.8 ==="
smart_ping "8.8.8.8" 3
echo "=== Test 2: ICMP to 193.124.225.26 (no port) ==="
smart_ping "193.124.225.26" 3
echo "=== Test 3: smart_ping 193.124.225.26 TCP:443 ==="
smart_ping "193.124.225.26" 3 "443"
echo "=== Test 4: tcp_ping raw ==="
result=$(tcp_ping "193.124.225.26" "443" 3)
echo "result=$result rc=$?"
"""
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=user, password=pwd, timeout=10)
sftp = ssh.open_sftp()
with sftp.file("/tmp/_kaskad_test.sh", "w") as f:
f.write(test_script)
sftp.close()
stdin, stdout, stderr = ssh.exec_command("bash /tmp/_kaskad_test.sh", timeout=30)
print(stdout.read().decode(errors="replace"))
err = stderr.read().decode(errors="replace")
if err:
print("STDERR:", err)
ssh.close()

View File

@@ -261,7 +261,9 @@ probe_server_cli() {
[ -n "$_RET_NOTE" ] && set_alias_note "$ip" "$_RET_NOTE" [ -n "$_RET_NOTE" ] && set_alias_note "$ip" "$_RET_NOTE"
if [ ${#pings[@]} -eq 0 ]; then if [ ${#pings[@]} -eq 0 ]; then
echo -e "${YELLOW}[WARN] Сервер не отвечает на ping.${NC}" echo -e "${YELLOW}[WARN] Сервер не отвечает на ICMP ping.${NC}"
echo -e "${WHITE}(Это нормально для VLESS/XRay — ICMP часто заблокирован)${NC}"
echo -e "${WHITE}TCP-проверка будет доступна после добавления правила.${NC}"
read -p "Продолжить? (y/n): " ans read -p "Продолжить? (y/n): " ans
[[ "$ans" != "y" ]] && return 1 [[ "$ans" != "y" ]] && return 1
fi fi
@@ -403,6 +405,31 @@ get_target_ips() {
get_rules_list | awk -F'|' '{split($3,a,":"); print a[1]}' | sort -u get_rules_list | awk -F'|' '{split($3,a,":"); print a[1]}' | sort -u
} }
get_port_for_ip() {
local ip="$1"
get_rules_list | awk -F'|' -v ip="$ip" '{split($3,a,":"); if(a[1]==ip){print a[2]; exit}}'
}
tcp_ping() {
local ip="$1" port="$2" tout="${3:-3}"
local raw
raw=$(curl -so /dev/null -w '%{time_connect}' --max-time "$tout" --connect-timeout "$tout" "http://${ip}:${port}/" 2>/dev/null)
[ -z "$raw" ] && return 1
local ms
ms=$(awk "BEGIN {v=$raw*1000; if(v<0.5) exit 1; printf \"%.2f\", v}" 2>/dev/null) || return 1
echo "$ms"
}
smart_ping() {
local ip="$1" tout="${2:-3}" port="${3:-}"
local ms
ms=$(ping -c 1 -W "$tout" "$ip" 2>/dev/null | sed -n 's/.*time=\([0-9.]*\).*/\1/p')
if [ -n "$ms" ]; then echo "$ms"; return 0; fi
[ -z "$port" ] && port=$(get_port_for_ip "$ip")
[ -z "$port" ] && return 1
tcp_ping "$ip" "$port" "$tout"
}
remove_rules_for_port() { remove_rules_for_port() {
local proto="$1" in_port="$2" local proto="$1" in_port="$2"
iptables -t nat -S PREROUTING 2>/dev/null | grep "DNAT" | grep -- "--dport ${in_port} " | grep -- "-p ${proto} " | while read -r rule; do iptables -t nat -S PREROUTING 2>/dev/null | grep "DNAT" | grep -- "--dport ${in_port} " | grep -- "-p ${proto} " | while read -r rule; do
@@ -717,14 +744,18 @@ ping_live() {
trap 'running=0' INT trap 'running=0' INT
local _port; _port=$(get_port_for_ip "$ip")
local _mode="ICMP"
[ -n "$_port" ] && _mode="ICMP/TCP:${_port}"
while [ "$running" -eq 1 ]; do while [ "$running" -eq 1 ]; do
local ms local ms
ms=$(ping -c 1 -W 3 "$ip" 2>/dev/null | sed -n 's/.*time=\([0-9.]*\).*/\1/p') ms=$(smart_ping "$ip" 3 "${_port:-}")
((count++)) ((count++))
clear clear
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} Live Ping: ${WHITE}$label${CYAN} [Ctrl+C — стоп]${NC}" echo -e "${CYAN} Live Ping: ${WHITE}$label${CYAN} (${_mode}) [Ctrl+C — стоп]${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
if [ -n "$ms" ]; then if [ -n "$ms" ]; then
@@ -885,7 +916,7 @@ monitor_daemon() {
[ -f "$ckf" ] && lc=$(cat "$ckf") [ -f "$ckf" ] && lc=$(cat "$ckf")
if (( now - lc >= MON_INTERVAL )); then if (( now - lc >= MON_INTERVAL )); then
echo "$now" > "$ckf" echo "$now" > "$ckf"
local pr; pr=$(ping -c 1 -W 3 "$MON_IP" 2>/dev/null | sed -n 's/.*time=\([0-9.]*\).*/\1/p') local pr; pr=$(smart_ping "$MON_IP" 3)
if [ -z "$pr" ]; then if [ -z "$pr" ]; then
monitor_alert "$MON_IP" "TIMEOUT" "$MON_THRESHOLD" "$MON_COOLDOWN" monitor_alert "$MON_IP" "TIMEOUT" "$MON_THRESHOLD" "$MON_COOLDOWN"
else else
@@ -1204,7 +1235,7 @@ bot_handle_callback() {
ps:*) local ip="${data#ps:}"; local lb; lb=$(fmt_ip_short "$ip") ps:*) local ip="${data#ps:}"; local lb; lb=$(fmt_ip_short "$ip")
tg_edit "$chat_id" "$msg_id" "🏓 <b>$lb</b>\nРежим:" "$(kbd_ping_opts "$ip")" ;; tg_edit "$chat_id" "$msg_id" "🏓 <b>$lb</b>\nРежим:" "$(kbd_ping_opts "$ip")" ;;
po:*) local ip="${data#po:}"; local lb; lb=$(fmt_ip_short "$ip") po:*) local ip="${data#po:}"; local lb; lb=$(fmt_ip_short "$ip")
( local ms; ms=$(ping -c 1 -W 3 "$ip" 2>/dev/null | sed -n 's/.*time=\([0-9.]*\).*/\1/p') ( local ms; ms=$(smart_ping "$ip" 3)
[ -n "$ms" ] && tg_send "$chat_id" "🏓 <b>$lb</b>\n<code>${ms} ms</code>" "$(kbd_back)" > /dev/null \ [ -n "$ms" ] && tg_send "$chat_id" "🏓 <b>$lb</b>\n<code>${ms} ms</code>" "$(kbd_back)" > /dev/null \
|| tg_send "$chat_id" "🏓 <b>$lb</b>\n<code>timeout</code>" "$(kbd_back)" > /dev/null ) & ;; || tg_send "$chat_id" "🏓 <b>$lb</b>\n<code>timeout</code>" "$(kbd_back)" > /dev/null ) & ;;
p10:*) local ip="${data#p10:}"; local lb; lb=$(fmt_ip_short "$ip") p10:*) local ip="${data#p10:}"; local lb; lb=$(fmt_ip_short "$ip")
@@ -1212,7 +1243,7 @@ bot_handle_callback() {
local mid; mid=$(echo "$resp" | jq -r '.result.message_id // empty') local mid; mid=$(echo "$resp" | jq -r '.result.message_id // empty')
local -a res=(); local lost=0 txt="" local -a res=(); local lost=0 txt=""
for n in $(seq 1 10); do for n in $(seq 1 10); do
local ms; ms=$(ping -c 1 -W 3 "$ip" 2>/dev/null | sed -n 's/.*time=\([0-9.]*\).*/\1/p') local ms; ms=$(smart_ping "$ip" 3)
[ -n "$ms" ] && res+=("$ms") && txt+="#$n: ${ms}ms\n" || { ((lost++)); txt+="#$n: timeout\n"; } [ -n "$ms" ] && res+=("$ms") && txt+="#$n: ${ms}ms\n" || { ((lost++)); txt+="#$n: timeout\n"; }
sleep 1 sleep 1
done done
@@ -1226,7 +1257,7 @@ bot_handle_callback() {
local mid; mid=$(echo "$resp" | jq -r '.result.message_id // empty') local mid; mid=$(echo "$resp" | jq -r '.result.message_id // empty')
local -a res=(); local lost=0 local -a res=(); local lost=0
for n in $(seq 1 60); do for n in $(seq 1 60); do
local ms; ms=$(ping -c 1 -W 3 "$ip" 2>/dev/null | sed -n 's/.*time=\([0-9.]*\).*/\1/p') local ms; ms=$(smart_ping "$ip" 3)
[ -n "$ms" ] && res+=("$ms") || ((lost++)) [ -n "$ms" ] && res+=("$ms") || ((lost++))
if (( n % 10 == 0 )) && [ -n "$mid" ]; then if (( n % 10 == 0 )) && [ -n "$mid" ]; then
local p="🏓 <b>$lb</b>: ${n}/60с\nОК: ${#res[@]} | Lost: $lost" local p="🏓 <b>$lb</b>: ${n}/60с\nОК: ${#res[@]} | Lost: $lost"