diff --git a/install.sh b/install.sh index 2335741..963df8e 100644 --- a/install.sh +++ b/install.sh @@ -199,7 +199,7 @@ geoip_lookup() { } probe_server_cli() { - local ip="$1" + local ip="$1" port="${2:-}" echo -e "\n${CYAN}━━━ Проверка сервера $ip ━━━${NC}" echo -e "${YELLOW}[*] GeoIP...${NC}" @@ -228,13 +228,13 @@ probe_server_cli() { local plost=0 for n in 1 2 3; 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") if [ -n "$ms" ]; then pings+=("$ms") - echo -e " #$n: ${GREEN}${ms}ms${NC}" + echo -e " #$n: ${GREEN}${ms}ms${NC} ${CYAN}[${_PING_METHOD}]${NC}" else ((plost++)) - echo -e " #$n: ${RED}timeout${NC}" + echo -e " #$n: ${RED}timeout${NC} ${WHITE}[ICMP fail$([ -n "$port" ] && echo ", TCP:$port fail")]${NC}" fi [ "$n" -lt 3 ] && sleep 1 done @@ -261,14 +261,14 @@ probe_server_cli() { [ -n "$_RET_NOTE" ] && set_alias_note "$ip" "$_RET_NOTE" if [ ${#pings[@]} -eq 0 ]; then - echo -e "${YELLOW}━━━ Сервер не ответил на ICMP ping ━━━${NC}" - echo -e "${WHITE}Это нормально для VLESS / XRay / Reality — они часто блокируют ICMP.${NC}" - echo -e "${WHITE}После добавления правила ping будет работать через TCP.${NC}" + echo -e "\n${YELLOW}━━━ Сервер не ответил ━━━${NC}" + echo -e "${WHITE}ICMP заблокирован$([ -n "$port" ] && echo " и TCP:$port не удался").${NC}" echo "" - echo -e "${CYAN}Если хотите включить ICMP на удалённом сервере:${NC}" + echo -e "${CYAN}Чтобы включить ping на удалённом сервере:${NC}" echo -e " ${WHITE}ssh root@${ip}${NC}" echo -e " ${GREEN}sysctl -w net.ipv4.icmp_echo_ignore_all=0${NC}" echo -e " ${GREEN}echo 'net.ipv4.icmp_echo_ignore_all=0' >> /etc/sysctl.conf${NC}" + echo -e " ${GREEN}iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT${NC}" echo "" read -p "Продолжить добавление? (y/n): " ans [[ "$ans" != "y" ]] && return 1 @@ -277,7 +277,7 @@ probe_server_cli() { } probe_server_tg() { - local ip="$1" + local ip="$1" port="${2:-}" local result="" local geo geo=$(geoip_lookup "$ip") @@ -298,10 +298,10 @@ probe_server_tg() { local plost=0 for n in 1 2 3; 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") if [ -n "$ms" ]; then pings+=("$ms") - result+=" #$n: ${ms}ms\n" + result+=" #$n: ${ms}ms [${_PING_METHOD}]\n" else ((plost++)) result+=" #$n: timeout\n" @@ -313,9 +313,9 @@ probe_server_tg() { pavg=$(printf '%s\n' "${pings[@]}" | awk '{s+=$1} END {printf "%.2f", s/NR}') result+="Среднее: ${pavg}ms | Потеряно: $plost/3\n" else - result+="Сервер не отвечает на ICMP\n" - result+="(Нормально для XRay/VLESS)\n" - result+="TCP-ping заработает после добавления.\n" + result+="Сервер не ответил\n" + result+="Включите ping:\nsysctl -w net.ipv4.icmp_echo_ignore_all=0\n" + result+="iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT\n" fi echo "$result" } @@ -428,14 +428,19 @@ tcp_ping() { echo "$ms" } +_PING_METHOD="" + smart_ping() { local ip="$1" tout="${2:-3}" port="${3:-}" + _PING_METHOD="" 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 + if [ -n "$ms" ]; then _PING_METHOD="ICMP"; echo "$ms"; return 0; fi [ -z "$port" ] && port=$(get_port_for_ip "$ip") [ -z "$port" ] && return 1 - tcp_ping "$ip" "$port" "$tout" + ms=$(tcp_ping "$ip" "$port" "$tout") + if [ -n "$ms" ]; then _PING_METHOD="TCP:${port}"; echo "$ms"; return 0; fi + return 1 } remove_rules_for_port() { @@ -480,10 +485,9 @@ configure_rule() { echo -e "\n${CYAN}--- Настройка $name ($proto) ---${NC}" read_validated_ip "Введите IP адрес назначения:" local target_ip="$_RET_IP" - probe_server_cli "$target_ip" || return - read_validated_port "Введите Порт (одинаковый для входа и выхода):" local port="$_RET_PORT" + probe_server_cli "$target_ip" "$port" || return echo -e "\n${YELLOW}Будет создано правило:${NC}" echo -e " $proto: ${MY_IP:-*}:$port -> $(fmt_ip_short "$target_ip"):$port" read -p "Применить? (y/n): " confirm @@ -503,12 +507,11 @@ configure_custom_rule() { done read_validated_ip "Введите IP адрес назначения:" local target_ip="$_RET_IP" - probe_server_cli "$target_ip" || return - read_validated_port "Введите ${YELLOW}ВХОДЯЩИЙ Порт${NC} (на этом сервере):" local in_port="$_RET_PORT" read_validated_port "Введите ${YELLOW}ИСХОДЯЩИЙ Порт${NC} (на конечном сервере):" local out_port="$_RET_PORT" + probe_server_cli "$target_ip" "$out_port" || return echo -e "\n${YELLOW}Будет создано правило:${NC}" echo -e " $proto: ${MY_IP:-*}:$in_port -> $(fmt_ip_short "$target_ip"):$out_port" read -p "Применить? (y/n): " confirm @@ -794,7 +797,7 @@ ping_live() { results+=("$ms") local bar bar=$(make_ping_bar "$ms") - printf " ${GREEN}#%-4d %7sms${NC} %b\n" "$count" "$ms" "$bar" + printf " ${GREEN}#%-4d %7sms${NC} ${CYAN}[%s]${NC} %b\n" "$count" "$ms" "$_PING_METHOD" "$bar" else ((lost++)) printf " ${RED}#%-4d ------${NC} " "$count" @@ -1376,45 +1379,52 @@ bot_handle_message() { fi local proto name custom proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME"); custom=$(bot_get_state "$chat_id" "CUSTOM") - - local probe_msg; probe_msg=$(tg_send "$chat_id" "🔍 Проверяю $text..." "") - local probe_mid; probe_mid=$(echo "$probe_msg" | jq -r '.result.message_id // empty') - local probe_result; probe_result=$(probe_server_tg "$text") - local info_text="IP: $text ✅\n${probe_result}\nВведите имя сервера (или - — пропустить):" - if [ -n "$probe_mid" ]; then - tg_edit "$chat_id" "$probe_mid" "$info_text" "$(kbd_back)" > /dev/null - else - tg_send "$chat_id" "$info_text" "$(kbd_back)" > /dev/null - fi - bot_set_state "$chat_id" "STATE=awaiting_name" "PROTO=$proto" "NAME=$name" "CUSTOM=$custom" "TARGET_IP=$text" - ;; - awaiting_name) - local proto name custom target_ip - proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME") - custom=$(bot_get_state "$chat_id" "CUSTOM"); target_ip=$(bot_get_state "$chat_id" "TARGET_IP") - if [ "$text" != "-" ] && [ -n "$text" ]; then set_alias "$target_ip" "$text"; fi - bot_set_state "$chat_id" "STATE=awaiting_note" "PROTO=$proto" "NAME=$name" "CUSTOM=$custom" "TARGET_IP=$target_ip" - tg_send "$chat_id" "Примечание (или - — пропустить):" "$(kbd_back)" > /dev/null - ;; - awaiting_note) - local proto name custom target_ip - proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME") - custom=$(bot_get_state "$chat_id" "CUSTOM"); target_ip=$(bot_get_state "$chat_id" "TARGET_IP") - if [ "$text" != "-" ] && [ -n "$text" ]; then set_alias_note "$target_ip" "$text"; fi if [ "$custom" = "1" ]; then - bot_set_state "$chat_id" "STATE=awaiting_in_port" "PROTO=$proto" "NAME=$name" "CUSTOM=1" "TARGET_IP=$target_ip" - tg_send "$chat_id" "Сервер: $(fmt_ip_short "$target_ip")\n\nВХОДЯЩИЙ порт:" "$(kbd_back)" > /dev/null + bot_set_state "$chat_id" "STATE=awaiting_in_port" "PROTO=$proto" "NAME=$name" "CUSTOM=1" "TARGET_IP=$text" + tg_send "$chat_id" "IP: $text ✅\n\nВХОДЯЩИЙ порт:" "$(kbd_back)" > /dev/null else - bot_set_state "$chat_id" "STATE=awaiting_port" "PROTO=$proto" "NAME=$name" "CUSTOM=0" "TARGET_IP=$target_ip" - tg_send "$chat_id" "Сервер: $(fmt_ip_short "$target_ip")\n\nВведите порт:" "$(kbd_back)" > /dev/null + bot_set_state "$chat_id" "STATE=awaiting_port" "PROTO=$proto" "NAME=$name" "CUSTOM=0" "TARGET_IP=$text" + tg_send "$chat_id" "IP: $text ✅\n\nВведите порт:" "$(kbd_back)" > /dev/null fi ;; awaiting_port) if ! validate_port "$text"; then tg_send "$chat_id" "❌ Порт (1-65535)." "" > /dev/null; return; fi local proto name target_ip proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME"); target_ip=$(bot_get_state "$chat_id" "TARGET_IP") - bot_clear_state "$chat_id" - apply_iptables_rules "$proto" "$text" "$text" "$target_ip" "$name" - tg_send "$chat_id" "✅ $name\n$proto ${MY_IP:-*}:$text → $target_ip:$text\n$(fmt_ip_tg "$target_ip")" "$(kbd_back)" > /dev/null ;; + local port="$text" + local probe_msg; probe_msg=$(tg_send "$chat_id" "🔍 Проверяю $target_ip:$port..." "") + local probe_mid; probe_mid=$(echo "$probe_msg" | jq -r '.result.message_id // empty') + local probe_result; probe_result=$(probe_server_tg "$target_ip" "$port") + local info_text="$target_ip:$port\n${probe_result}\nВведите имя (или - — пропустить):" + [ -n "$probe_mid" ] && tg_edit "$chat_id" "$probe_mid" "$info_text" "$(kbd_back)" > /dev/null \ + || tg_send "$chat_id" "$info_text" "$(kbd_back)" > /dev/null + bot_set_state "$chat_id" "STATE=awaiting_name" "PROTO=$proto" "NAME=$name" "CUSTOM=0" "TARGET_IP=$target_ip" "PORT=$port" + ;; + awaiting_name) + local proto name custom target_ip port + proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME") + custom=$(bot_get_state "$chat_id" "CUSTOM"); target_ip=$(bot_get_state "$chat_id" "TARGET_IP") + port=$(bot_get_state "$chat_id" "PORT") + if [ "$text" != "-" ] && [ -n "$text" ]; then set_alias "$target_ip" "$text"; fi + bot_set_state "$chat_id" "STATE=awaiting_note" "PROTO=$proto" "NAME=$name" "CUSTOM=$custom" "TARGET_IP=$target_ip" "PORT=$port" "IN_PORT=$(bot_get_state "$chat_id" "IN_PORT")" "OUT_PORT=$(bot_get_state "$chat_id" "OUT_PORT")" + tg_send "$chat_id" "Примечание (или - — пропустить):" "$(kbd_back)" > /dev/null + ;; + awaiting_note) + local proto name custom target_ip port + proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME") + custom=$(bot_get_state "$chat_id" "CUSTOM"); target_ip=$(bot_get_state "$chat_id" "TARGET_IP") + if [ "$text" != "-" ] && [ -n "$text" ]; then set_alias_note "$target_ip" "$text"; fi + if [ "$custom" = "1" ]; then + local in_port out_port + in_port=$(bot_get_state "$chat_id" "IN_PORT"); out_port=$(bot_get_state "$chat_id" "OUT_PORT") + bot_clear_state "$chat_id" + apply_iptables_rules "$proto" "$in_port" "$out_port" "$target_ip" "$name" + tg_send "$chat_id" "✅ Custom\n$proto ${MY_IP:-*}:$in_port → $target_ip:$out_port\n$(fmt_ip_tg "$target_ip")" "$(kbd_back)" > /dev/null + else + port=$(bot_get_state "$chat_id" "PORT") + bot_clear_state "$chat_id" + apply_iptables_rules "$proto" "$port" "$port" "$target_ip" "$name" + tg_send "$chat_id" "✅ $name\n$proto ${MY_IP:-*}:$port → $target_ip:$port\n$(fmt_ip_tg "$target_ip")" "$(kbd_back)" > /dev/null + fi ;; awaiting_in_port) if ! validate_port "$text"; then tg_send "$chat_id" "❌ Порт." "" > /dev/null; return; fi local proto name target_ip @@ -1426,9 +1436,14 @@ bot_handle_message() { local proto name target_ip in_port proto=$(bot_get_state "$chat_id" "PROTO"); name=$(bot_get_state "$chat_id" "NAME") target_ip=$(bot_get_state "$chat_id" "TARGET_IP"); in_port=$(bot_get_state "$chat_id" "IN_PORT") - bot_clear_state "$chat_id" - apply_iptables_rules "$proto" "$in_port" "$text" "$target_ip" "$name" - tg_send "$chat_id" "✅ Custom\n$proto ${MY_IP:-*}:$in_port → $target_ip:$text\n$(fmt_ip_tg "$target_ip")" "$(kbd_back)" > /dev/null ;; + local probe_msg; probe_msg=$(tg_send "$chat_id" "🔍 Проверяю $target_ip:$text..." "") + local probe_mid; probe_mid=$(echo "$probe_msg" | jq -r '.result.message_id // empty') + local probe_result; probe_result=$(probe_server_tg "$target_ip" "$text") + local info_text="$target_ip (вход:$in_port → выход:$text)\n${probe_result}\nВведите имя (или - — пропустить):" + [ -n "$probe_mid" ] && tg_edit "$chat_id" "$probe_mid" "$info_text" "$(kbd_back)" > /dev/null \ + || tg_send "$chat_id" "$info_text" "$(kbd_back)" > /dev/null + bot_set_state "$chat_id" "STATE=awaiting_name" "PROTO=$proto" "NAME=$name" "CUSTOM=1" "TARGET_IP=$target_ip" "IN_PORT=$in_port" "OUT_PORT=$text" + ;; awaiting_threshold) if ! validate_port "$text"; then tg_send "$chat_id" "❌ Число (1-65535):" "" > /dev/null; return; fi local mon_ip mon_interval