diff --git a/_ssh_debug.py b/_ssh_debug.py
new file mode 100644
index 0000000..10c2070
--- /dev/null
+++ b/_ssh_debug.py
@@ -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}]")
diff --git a/_test_tcp_ping.py b/_test_tcp_ping.py
new file mode 100644
index 0000000..f266ff7
--- /dev/null
+++ b/_test_tcp_ping.py
@@ -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()
diff --git a/install.sh b/install.sh
index 965c9ad..67f7709 100644
--- a/install.sh
+++ b/install.sh
@@ -261,7 +261,9 @@ probe_server_cli() {
[ -n "$_RET_NOTE" ] && set_alias_note "$ip" "$_RET_NOTE"
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
[[ "$ans" != "y" ]] && return 1
fi
@@ -403,6 +405,31 @@ get_target_ips() {
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() {
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
@@ -717,14 +744,18 @@ ping_live() {
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
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++))
clear
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}"
if [ -n "$ms" ]; then
@@ -885,7 +916,7 @@ monitor_daemon() {
[ -f "$ckf" ] && lc=$(cat "$ckf")
if (( now - lc >= MON_INTERVAL )); then
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
monitor_alert "$MON_IP" "TIMEOUT" "$MON_THRESHOLD" "$MON_COOLDOWN"
else
@@ -1204,7 +1235,7 @@ bot_handle_callback() {
ps:*) local ip="${data#ps:}"; local lb; lb=$(fmt_ip_short "$ip")
tg_edit "$chat_id" "$msg_id" "🏓 $lb\nРежим:" "$(kbd_ping_opts "$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" "🏓 $lb\n${ms} ms" "$(kbd_back)" > /dev/null \
|| tg_send "$chat_id" "🏓 $lb\ntimeout" "$(kbd_back)" > /dev/null ) & ;;
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 -a res=(); local lost=0 txt=""
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"; }
sleep 1
done
@@ -1226,7 +1257,7 @@ bot_handle_callback() {
local mid; mid=$(echo "$resp" | jq -r '.result.message_id // empty')
local -a res=(); local lost=0
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++))
if (( n % 10 == 0 )) && [ -n "$mid" ]; then
local p="🏓 $lb: ${n}/60с\nОК: ${#res[@]} | Lost: $lost"