Shell Scripting: Правильный способ проверки интернет-соединения?

Вопрос или проблема

Я нашел скрипты, которые якобы проверяют наличие интернет-соединения. Некоторые проверяют IP-адрес, если интерфейс активен, НО это не проверяет наличие интернет-соединения. Я нашел некоторые, которые используют ping, например: if [ 'ping google.com -c 4 | grep time' != "" ]; then, но иногда это может быть ненадежным, так как сам ping может зависнуть по какой-то причине (например, ожидание застрявшего IO).

Есть ли предложения по правильному/надежному способу проверки наличия интернет-соединения с помощью скриптов? Мне нужно использовать какие-то пакеты?

Он должен уметь периодически проверять с помощью cron, например, а затем выполнять что-нибудь, когда соединение разрывается, например, инициировать ifup --force [interface]

Я настоятельно не рекомендую использовать ping для определения подключения. Слишком много сетевых администраторов отключают ICMP (протокол, который он использует) из-за опасений относительно атак ping flood, исходящих из их сетей.

Вместо этого я использую быструю проверку надежного сервера на порту, который, как вы можете ожидать, будет открыт:

if nc -zw1 google.com 443; then
  echo "у нас есть подключение"
fi

Это использует netcat (nc) в режиме сканирования портов, быструю проверку (-z – это режим без ввода/вывода [используется для сканирования]) с быстрой задержкой (-w 1 ждет не более одной секунды, хотя пользователям Apple OS X может потребоваться использовать -G 1). Он проверяет Google на порте 443 (HTTPS).

Я использовал HTTPS вместо HTTP в качестве усилия по защите от захватных порталов и прозрачных прокси-серверов, которые могут отвечать на порту 80 (HTTP) для любого хоста. Это менее вероятно при использовании порта 443, так как будет несоответствие сертификатов, но это все же случается.

Если вы хотите защититься от этого, вам нужно будет проверить безопасность соединения:

test=google.com
if nc -zw1 $test 443 && echo |openssl s_client -connect $test:443 2>&1 |awk '
  $1 == "SSL" && $2 == "handshake" { handshake = 1 }
  handshake && $1 == "Verification:" { ok = $2; exit }
  END { exit ok != "OK" }'
then
  echo "у нас есть подключение"
fi

Это проверяет наличие соединения (вместо ожидания, пока openssl завершит выполнение) и затем выполняет SSL рукопожатие, сосредотачиваясь на этапе проверки. Он тихо завершает работу (“истина”), если проверка была “ОК”, или завершает с ошибкой (“ложь”), затем мы сообщаем о находке.

Код awk анализирует вывод openssl построчно:

  1. Если первое слово в строке “SSL”, а второе “Verification”, установите handshake в 1
  2. Если handshake установлен и первое слово в строке “Verification”,
    то сохраните второе слово (статус проверки) в ok и прекратите чтение
  3. Выйдите со значением 0 (истина), если статус проверки был OK, или выйдите со значением 1 (ложь).
    Мы используем != здесь, потому что коды выхода из shell обратны

(Особенность awk: Вызов exit во время чтения строк просто прекращает чтение строк и переходит к условию END, из которого можно действительно exit.)

Тестирование IPv4 соединения

Если ваша сеть пропускает ICMP-запросы, попробуйте отправить ping на 8.8.8.8 (сервер, который управляется Google).

if ping -q -c 1 -W 1 8.8.8.8 >/dev/null; then
  echo "IPv4 активно"
else
  echo "IPv4 неактивно"
fi

Тестирование IP-соединения и DNS

Если вы хотите, чтобы тест завершился успешно только тогда, когда DNS также работает, используйте имя хоста.

if ping -q -c 1 -W 1 google.com >/dev/null; then
  echo "Сеть активна"
else
  echo "Сеть неактивна"
fi

Тестирование интернет-соединения

Некоторые брандмауэры блокируют ICMP-запросы. В некоторых местах есть брандмауэр, который блокирует весь трафик, кроме веб-прокси. Если вы хотите протестировать интернет-соединение, вы можете выполнить HTTP-запрос.

case "$(curl -s --max-time 2 -I http://google.com | sed 's/^[^ ]*  *\([0-9]\).*/\1/; 1q')" in
  [23]) echo "HTTP-соединение активно";;
  5) echo "Веб-прокси не позволяет проходить дальше";;
  *) echo "Сеть неактивна или очень медленная";;
esac

Я сделал скрипт, который использует несколько способов проверки интернет-соединения (ping, nc и curl, благодаря Adam Katz, Gilles и Archemar). Надеюсь, это будет полезно кому-то. Смело редактируйте его на свой вкус/оптимизируйте.

Проверяет ваш шлюз, DNS и интернет-соединение (с использованием curl, nc и ping).
Поместите это в файл, затем сделайте его исполняемым (обычно sudo chmod +x filename)

#!/bin/bash

GW=`/sbin/ip route | awk '/default/ { print $3 }'`
checkdns=`cat /etc/resolv.conf | awk '/nameserver/ {print $2}' | awk 'NR == 1 {print; exit}'`
# google.com выдает ошибку 301/Перемещено
checkdomain=www.google.com

#несколько функций

function portscan
{
  tput setaf 6; echo "Начало сканирования порта $checkdomain порт 80"; tput sgr0;
  if nc -zw1 $checkdomain  80; then
    tput setaf 2; echo "Сканирование порта успешно, $checkdomain порт 80 доступен"; tput sgr0;
  else
    echo "Сканирование порта $checkdomain порт 80 не удалось."
  fi
}

function pingnet
{
  #Google имеет самое надежное имя хоста. Смело меняйте его.
  tput setaf 6; echo "Отправляю ping на $checkdomain для проверки интернет-соединения." && echo; tput sgr0;
  ping $checkdomain -c 4

  if [ $? -eq 0 ]
    then
      tput setaf 2; echo && echo "$checkdomain доступен. Интернет-соединение, вероятно, доступно."&& echo ; tput sgr0;
      #Вставьте любую команду, которую вы хотите здесь
    else
      echo && echo "Не удалось установить интернет-соединение. Здесь может быть что-то не так." >&2
      #Вставьте любую команду, которую вы хотите здесь
#      exit 1
  fi
}

function pingdns
{
  #Захватите первый DNS-сервер из /etc/resolv.conf
  tput setaf 6; echo "Отправляю ping на первый DNS-сервер в resolv.conf ($checkdns) для проверки разрешения имен" && echo; tput sgr0;
  ping $checkdns -c 4
    if [ $? -eq 0 ]
    then
      tput setaf 6; echo && echo "$checkdns доступен для ping. Продолжаю проверку домена."; tput sgr0;
      #Вставьте любую команду, которую вы хотите здесь
    else
      echo && echo "Не удалось установить интернет-соединение с DNS. Здесь может быть что-то не так." >&2
      #Вставьте любую команду, которую вы хотите здесь
#     exit 1
  fi
}

function httpreq
{
  tput setaf 6; echo && echo "Проверка HTTP-соединения"; tput sgr0;
  case "$(curl -s --max-time 2 -I $checkdomain | sed 's/^[^ ]*  *\([0-9]\).*/\1/; 1q')" in
  [23]) tput setaf 2; echo "HTTP-соединение активно"; tput sgr0;;
  5) echo "Веб-прокси не позволяет проходить дальше";exit 1;;
  *)echo "Что-то не так с HTTP-соединениями. Проверьте это."; exit 1;;
  esac
#  exit 0
}

#Сначала отправляю ping на шлюз для проверки соединения с ЛВС
tput setaf 6; echo "Отправляю ping на шлюз ($GW) для проверки соединения с ЛВС" && echo; tput sgr0;
if [ "$GW" = "" ]; then
    tput setaf 1;echo "Нет шлюза. Вероятно отключено..."; tput sgr0;
#    exit 1
fi

ping $GW -c 4

if [ $? -eq 0 ]
then
  tput setaf 6; echo && echo "Шлюз ЛВС доступен для ping. Продолжается проверка интернет-соединения."; tput sgr0;
  pingdns
  pingnet
  portscan
  httpreq
  exit 0
else
  echo && echo "Что-то не так с ЛВС (шлюз недоступен)"
  pingdns
  pingnet
  portscan
  httpreq

  #Вставьте любую команду, которую вы хотите здесь
#  exit 1
fi

в интернете много IP-адресов, легкий подход — отправить ping на несколько из них

 if ping -c 4 google.com ; then OK ; else KO ; fi
 if ping -c 4 facebook.com ; then OK ; else KO ; fi
 if ping -c 4 nsa.gov ; then OK ; else KO ; fi # <- возможно, этот не ответит

более полный ответ может включать получение страниц с использованием wget

 wget google.com -o google.txt
 if parse google.txt ; then OK ; else KO ; fi

где

  • parse — это программа, которую вы пишете, чтобы убедиться, что google.txt не является (слишком старой) кешированной версией google.com

благодаря вашим вкладам от каждого пользователя и других веб-ресурсов, мне удалось завершить этот скрипт за 3 дня. и я оставлю его в свободное использование.

этот скрипт автоматизирует обновление IP-адреса при потере соединения, он делает это настойчиво.

#!/bin/bash

# Автор: Джон Ллевелин
# FB: fb.com/johnwilliam.llewelyn
# Twitter: twitter.com/JWLLEWELYN
# Телефон: +584-1491-011-15
# Использование свободно.
# Описание: Монитор подключения для модема ADSL.
# Требования:
# Скопируйте этот код или сохраните в /home/administrator/ConnectionMonitor.sh
# Требуются установленные пакеты fping beep и cron
# Комментируйте blacklist pcspkr snd-pcsp в /etc/modprobe.d/blacklist.conf
# Дайте права на выполнение: chmod +x /home/administrator/ConnectionMonitor.sh
# Добавьте эту строку в crontab -e под пользователем root
# @reboot sleep 120 && /home/administrator/MonitorDeConexion.sh

#################################################################################
# НАСТРОЙКИ
TEST="8.8.8.8"       # ТЕСТОВЫЙ PING
ADAPTER1="enp4s0"    # ВНЕШНИЙ ЭКСПЕРТНЫЙ АДАПТЕР

# Отчет
LOGFILE=/home/administrator/Documentos/ReportInternet.log

# Сообщения
MESSAGE1="Восстановление подключения..."
MESSAGE2="Подождите немного, пожалуйста..."
MESSAGE3="Нет подключения к интернету."
MESSAGE4="Да, есть подключение к интернету."
#################################################################################

# Дата и время
TODAY=$(date "+%r %d-%m-%Y")

# Показать внешний IP-адрес
IPv4ExternalAddr1=$(ip addr list $ADAPTER1 |grep "inet " |cut -d' ' -f6|cut -d/ -f1)
IPv6ExternalAddr1=$(ip addr list $ADAPTER1 |grep "inet6 " |cut -d' ' -f6|cut -d/ -f1)

# Сигнализация
alarm() {
    beep -f 1500 -l 200;beep -f 1550 -l 200;beep -f 1500 -l 200;beep -f 1550 -l 200;beep -f 1500 -l 200;beep -f 1550 -l 200;beep -f 1500 -l 200;beep -f 1550$
}

# Восстановление подключения
resolve() {
    clear
    echo "$MESSAGE1"
    sudo ifconfig $ADAPTER1 up;sudo dhclient -r $ADAPTER1;sleep 5;sudo dhclient $ADAPTER1
    echo "$MESSAGE2"
    sleep 120
}

# Выполнение работы
while true; do
    if [[ "$(fping -I $ADAPTER1 $TEST | grep 'unreachable' )" != "" ]]; then
        alarm
        clear
        echo "================================================================================" >> ${LOGFILE}
        echo "$MESSAGE3 - $TODAY"                                                               >> ${LOGFILE}
        echo "$MESSAGE3 - $TODAY"
        echo "================================================================================" >> ${LOGFILE}
        sleep 10
        resolve
    else
        clear
        echo "================================================================================"   >> ${LOGFILE}
        echo "$MESSAGE4 - $TODAY - IPv4 Addr: $IPv4ExternalAddr1 - IPv6 Addr: $IPv6ExternalAddr1" >> ${LOGFILE}
        echo "$MESSAGE4 - $TODAY - IPv4 Addr: $IPv4ExternalAddr1 - IPv6 Addr: $IPv6ExternalAddr1"
        echo "================================================================================"   >> ${LOGFILE}
        sleep 120
    fi
done

pastebin: https://pastebin.com/wfSkpgKA

Я использую следующий скрипт:

#!/bin/bash

_beep() {
  ( \speaker-test --frequency 400 --test sine -l 1 -p 1 -P 2 >& /dev/null )& # розовый / волнообразный
  pid=$!
  \sleep 0.5s
  \kill -9 $pid 
  \wait $pid 2>/dev/null
}

con=0
while [ true ]; do
if ! ping -c1 -W 2 google.com >& /dev/null; then
    echo "Нет интернета..."
    con=0
    _beep
else
    if [[ $con -ne 1 ]]
    then
        echo "Подключено."
        con=1
    fi
    sleep 1
fi

done

Здесь я объявляю функцию beep, которая вызывается при сбое ping на сервер Google.

Вопрос:

Есть ли предложения по правильному/надежному способу проверки наличия интернет-соединения с помощью скриптов? Мне нужно использовать какие-то пакеты?

Ответ:

Я использую socat для проверки сетевого подключения:

socat (SOcket CAT) – это утилита командной строки, которая устанавливает два двусторонних потока байтов и передает данные между ними. Она достаточно эффективна для проверки сетевого подключения между двумя произвольными точками

while :
do
    socat /dev/null TCP4:google.com:443 && break
    sleep 60
done

Этот код вводит socat в бесконечный цикл. Он повторяется до тех пор, пока socat не “удастся” (возвращает значение $? равное 0), в этот момент выполняется break, и бесконечный цикл завершается для продолжения выполнения скрипта. Это означает, что вы можете проверить свое сетевое подключение прежде чем выполнять оставшуюся часть вашего кода.

Это работает в моей сети, так как у меня ничего не кэшируется на WAN-стороне моего брандмауэра. Если вы знаете сервер более надежный, чем google.com:443, вы можете использовать его. /dev/null включен в вызов socat, потому что socat требует две точки для соединения, но никакие данные от цели не нужны.

@PNDA предложил извлекать данные из ethtool, что мне нравится. Но я предпочитаю перенаправлять в grep и использовать более простой awk-команду, которую не-башевцы могут быстрее понять. Разница во времени между двумя минимальна.

Используя: Ubuntu Bionic 18.04

Определение сетевого интерфейса:

root@srv:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:1e:67:96:a3:97 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.101/8 brd 10.255.255.255 scope global eno1
       valid_lft forever preferred_lft forever
    inet6 fe80::21e:67ff:fe96:a397/64 scope link 
       valid_lft forever preferred_lft forever
3: rename3: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 00:1e:67:96:a3:96 brd ff:ff:ff:ff:ff:ff

вывод ethtool:

root@srv:~# ethtool eno1
Настройки для eno1:
        Поддерживаемые порты: [ TP ]
        Поддерживаемые режимы канала:  10baseT/Half 10baseT/Full 
                                        100baseT/Half 100baseT/Full 
                                        1000baseT/Full 
        Поддерживаемое использование управляющих кадров: Нет
        Поддержка авто-согласования: Да
        Поддерживаемые режимы FEC: Не сообщается
        Рекламируемые режимы канала:  10baseT/Half 10baseT/Full 
                                        100baseT/Half 100baseT/Full 
                                        1000baseT/Full 
        Рекламируемое использование управляющих кадров: Нет
        Рекламируемое авто-согласование: Да
        Рекламируемые режимы FEC: Не сообщается
        Скорость: 1000Мбит/с
        Дуплексность: Полный
        Порт: Витая пара
        PHYAD: 1
        Передатчик: внутренний
        Автосогласование: вкл
        MDI-X: вкл (авто)
        Поддержка Wake-on: pumbg
        Wake-on: г
        Текущий уровень сообщения: 0x00000007 (7)
                                    драйвер проверка связь
        Обнаружено соединение: да

Пример команды:

ethtool eno1 | grep "ink detected" | awk '{print $3}'

Выберите своё собственное приключение:

ethtool {{network adapter}} | grep "ink detected" | awk '{print $3}'

Вывод:

Если есть связь:

root@srv:~# ethtool eno1 | grep "ink detected" | awk '{print $3}'
да

Если связи нет:

root@srv:~# ethtool rename3 | grep "ink detected" | awk '{print $3}'
нет

Чтобы избежать ложных срабатываний из-за наличия портала с авторизацией, вам нужно будет проверить вывод соединения HTTP с веб-сайта с предсказуемым содержанием/ответом.

Что-то вроде этого:

#!/bin/sh

detection_out=$(wget -q http://detectportal.firefox.com/success.txt --timeout=10 -O - 2> /dev/null)

test "$detection_out" = "success"

exit $?

Это проверяет, является ли содержимое http://detectportal.firefox.com/success.txt точно идентичным success.

Вывод дается в виде кода выхода: если код выхода ноль, соединение доступно, в противном случае оно либо недоступно по какой-то причине, либо блокируется порталом с авторизацией.

Я взял этот скрипт отсюда:
https://github.com/libremesh/lime-packages/pull/712/files

Если вам нужен однострочный скрипт или alias для проверки наличия интернет-соединения на Linux или macOS, вы можете использовать это:

[ $(wget --quiet --spider https://google.com &>/dev/null; echo $?) -ne 0 ] && echo "Нет интернета" && exit

адаптировано из: 9 команд для проверки подключения к интернету с примерами скриптов на шелле | GoLinuxCloud

.

Ответ или решение

Вопрос об определении способа проверки подключения к интернету с помощью сценариев на оболочке (shell scripting) является актуальной задачей для специалистов по информационным технологиям. Важно найти надежный и точный метод, который будет эффективно определять наличие подключения к интернету при выполнении сценариев автоматически с использованием, например, cron для периодической проверки.

Теория

Проверка интернет-соединения с использованием сценариев на оболочке может быть сложным процессом, так как он должен учитывать различные аспекты соединения, такие как доступность DNS, ответ сервера HTTP и функциональность сетевых интерфейсов. Существует множество способов для выполнения такой проверки, включая использование команд ping, curl и nc. Однако, каждая из этих команд имеет свои нюансы и ограничения. Например, ICMP-запросы могут быть блокированы на уровне брандмауэра, и команда ping не всегда может дать надежный результат. В то время как использование HTTP-запросов с помощью curl может быть более надежным, так как проверка выполняется через широко использованный порт 80 или 443, который редко бывает закрыт в сети.

Пример

В качестве примера использования различных методов и их комбинирования можно привести сценарий, в котором используется командная утилита nc (netcat) для быстрой проверки доступности порта 443 на сервере google.com, что говорит о наличии интернет-соединения. Также можно использовать команду curl для выполнения HTTP-запросов и проверки, доступен ли интернет-сервис.

#!/bin/bash

test=google.com

# Проверка соединения с использованием netcat
if nc -zw1 $test 443; then
  echo "Есть соединение"
fi

# Проверка HTTPS соединения и валидации SSL сертификата
if nc -zw1 $test 443 && echo | openssl s_client -connect $test:443 2>&1 | awk '
  $1 == "SSL" && $2 == "handshake" { handshake = 1 }
  handshake && $1 == "Verification:" { ok = $2; exit }
  END { exit ok != "OK" }'
then
  echo "SSL соединение установлено"
fi

Данный сценарий проверяет наличие соединения через порт 443 — порт HTTPS, что увеличивает вероятность корректной проверки наличия интернет-соединения.

Применение

Представленный подход можно интегрировать в автоматизированные скрипты, которые запускаются через cron. Это позволит системно отслеживать состояние соединения и выполнять ответные действия, например, принудительную перезагрузку сетевого интерфейса, если соединение отсутствует. Такая практика часто применяется в организациях для обеспечения стабильной работы серверов и устранения проблем с подключением автоматически без участия человека.

Таким образом, выбор инструментов для проверки наличия соединения зависит от сетевой инфраструктуры и ограничений. Использование netcat для тестирования порта, а также curl для проверки доступности веб-сервисов позволяет строить надежные сценарии мониторинга соединения с интернетом. Это особенно ценно для автоматизированных процессов, которые требуют высокого уровня доступности и надежности сетевых соединений.

Оцените материал
Добавить комментарий

Капча загружается...