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

26

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

Любые предложения о правильном / надежном способе проверки подключения к Интернету с использованием сценариев? Должен ли я использовать некоторые пакеты?

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

PNDA
источник

Ответы:

29

Тестирование подключения IPv4

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

if ping -q -c 1 -W 1 8.8.8.8 >/dev/null; then
  echo "IPv4 is up"
else
  echo "IPv4 is down"
fi

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

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

if ping -q -c 1 -W 1 google.com >/dev/null; then
  echo "The network is up"
else
  echo "The network is down"
fi

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

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

case "$(curl -s --max-time 2 -I http://google.com | sed 's/^[^ ]*  *\([0-9]\).*/\1/; 1q')" in
  [23]) echo "HTTP connectivity is up";;
  5) echo "The web proxy won't let us through";;
  *) echo "The network is down or very slow";;
esac
Жиль "ТАК - перестань быть злым"
источник
Возможно, вы захотите включить проверку физического соединения (уровень 1 OSI) перед любыми проверками уровня 3 OSI с использованием ethtool; $ ethtool <dev> | awk '$0 ~ /link detected/{print $3}'
18
Можете ли вы объяснить цель добавления этого, пожалуйста>/dev/null
Амин Харбауи
@AmineHarbaoui - >/dev/nullперенаправляет стандартный вывод /dev/nullна нулевое устройство , которое избавляется от него, так как в этом случае оно нежелательно (все, что нас интересует, это значения выхода команд). Вместо этого, более применимый вывод берется из echoстрок.
Адам Кац
27

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

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

if nc -zw1 google.com 443; then
  echo "we have connectivity"
fi

При этом используется netcat ( nc) в режиме сканирования портов , быстрый щелчок ( -zэто режим с нулевым вводом-выводом [используется для сканирования] ) с быстрым таймаутом ( -w 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 '
  handshake && $1 == "Verification" { if ($2=="OK") exit; exit 1 }
  $1 $2 == "SSLhandshake" { handshake = 1 }'
then
  echo "we have connectivity"
fi

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

Адам Кац
источник
5
Я уважаю Джиллис, но это правильный ответ.
Гвилли
3
-dНапример, добавьте nc -dzw1также, чтобы он не слушал STDIN и не зависал в скрипте. и, возможно, используйте 8.8.8.8 вместо google.com для сохранения поиска. nc -dzw1 8.8.8.8 443
Dezza
Я не уверен, насколько надежен DNS-распознаватель Google при обслуживании HTTPS. Сервер google.com должен быть более надежным для HTTPS (если вы не в Китае, но оба они, вероятно, заблокированы). Я никогда не нуждался -dв моих сценариях, возможно, потому что у меня никогда не было неиспользованного конвейера. Это должно быть безопасно добавить.
Адам Кац
1
@dezza - -w 1все еще стоит секунду, когда нет соединения, хотя, возможно, у вас ncесть какая-то неясная проблема где-то здесь. Если у вас установлена ​​последняя версия nmap, вы можете вместо этого ncat --send-only --recv-only -w 334msсократить время отказа до трети nc(я обнаружил, что 334ms - это хорошее время ожидания).
Адам Кац
1
@dezza - я не знаю, почему это происходит с вами как в nmap, так и в netcat (nc) для этой системы. Возможно, что-то странное происходит в вашей сети или в этой системе BSD. Не стесняйтесь создавать новый вопрос unix.stackexchange и получить больше, чем просто мои глаза на эту проблему. Если вы это сделаете, пожалуйста, свяжите это в комментариях здесь и связать эту тему с вашим новым вопросом.
Адам Кац
9

Я создал скрипт, который использует несколько способов проверки интернет-соединения (ping, nc и curl, спасибо Адаму Кацу, Жилю и Архемару). Я надеюсь, что кто-то найдет это полезным. Не стесняйтесь редактировать его по своему вкусу / оптимизировать.

Проверяет ваш шлюз, 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}'`
checkdomain=google.com

#some functions

function portscan
{
  tput setaf 6; echo "Starting port scan of $checkdomain port 80"; tput sgr0;
  if nc -zw1 $checkdomain  80; then
    tput setaf 2; echo "Port scan good, $checkdomain port 80 available"; tput sgr0;
  else
    echo "Port scan of $checkdomain port 80 failed."
  fi
}

function pingnet
{
  #Google has the most reliable host name. Feel free to change it.
  tput setaf 6; echo "Pinging $checkdomain to check for internet connection." && echo; tput sgr0;
  ping $checkdomain -c 4

  if [ $? -eq 0 ]
    then
      tput setaf 2; echo && echo "$checkdomain pingable. Internet connection is most probably available."&& echo ; tput sgr0;
      #Insert any command you like here
    else
      echo && echo "Could not establish internet connection. Something may be wrong here." >&2
      #Insert any command you like here
#      exit 1
  fi
}

function pingdns
{
  #Grab first DNS server from /etc/resolv.conf
  tput setaf 6; echo "Pinging first DNS server in resolv.conf ($checkdns) to check name resolution" && echo; tput sgr0;
  ping $checkdns -c 4
    if [ $? -eq 0 ]
    then
      tput setaf 6; echo && echo "$checkdns pingable. Proceeding with domain check."; tput sgr0;
      #Insert any command you like here
    else
      echo && echo "Could not establish internet connection to DNS. Something may be wrong here." >&2
      #Insert any command you like here
#     exit 1
  fi
}

function httpreq
{
  tput setaf 6; echo && echo "Checking for HTTP Connectivity"; tput sgr0;
  case "$(curl -s --max-time 2 -I $checkdomain | sed 's/^[^ ]*  *\([0-9]\).*/\1/; 1q')" in
  [23]) tput setaf 2; echo "HTTP connectivity is up"; tput sgr0;;
  5) echo "The web proxy won't let us through";exit 1;;
  *)echo "Something is wrong with HTTP connections. Go check it."; exit 1;;
  esac
#  exit 0
}


#Ping gateway first to verify connectivity with LAN
tput setaf 6; echo "Pinging gateway ($GW) to check for LAN connectivity" && echo; tput sgr0;
if [ "$GW" = "" ]; then
    tput setaf 1;echo "There is no gateway. Probably disconnected..."; tput sgr0;
#    exit 1
fi

ping $GW -c 4

if [ $? -eq 0 ]
then
  tput setaf 6; echo && echo "LAN Gateway pingable. Proceeding with internet connectivity check."; tput sgr0;
  pingdns
  pingnet
  portscan
  httpreq
  exit 0
else
  echo && echo "Something is wrong with LAN (Gateway unreachable)"
  pingdns
  pingnet
  portscan
  httpreq

  #Insert any command you like here
#  exit 1
fi
PNDA
источник
Ницца ! Спасибо ! Что мы должны установить ворота $GW?
Ciprian Tomoiagă
@CiprianTomoiaga Нет необходимости, /sbin/ip route | awk '/default/ { print $3 }'получает адрес шлюза из (надеюсь) основного интерфейса. При желании вы можете установить IP-адрес шлюза самостоятельно.
PNDA
Спасибо за это! Что я пропускаю, так это возможность хранить сбои в Интернете в текстовом файле и автоматическое электронное письмо моему провайдеру.
января
2

Есть много IP-адресов в Интернете, легкий подход состоит в том, чтобы пинговать некоторые из них

 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 # <- this one might not reply

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

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

где

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

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

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

#!/bin/bash

# Autor: John Llewelyn
# FB: fb.com/johnwilliam.llewelyn
# Twitter: twitter.com/JWLLEWELYN
# TLF: +584-1491-011-15
# Its use is free.
# Description: Connection Monitor for ADSL modem.
# Requirements:
# Copy this code or save to /home/administrator/ConnectionMonitor.sh
# It requires the installed packages fping beep and cron
# Comment the blacklist pcspkr snd-pcsp in /etc/modprobe.d/blacklist.conf
# Give execute permissions: chmod +x /home/administrator/ConnectionMonitor.sh
# Add this line in crontab -e with root user
# @reboot sleep 120 && /home/administrator/MonitorDeConexion.sh

#################################################################################
# SETTINGS
TEST="8.8.8.8"       # TEST PING
ADAPTER1="enp4s0"    # EXTERNAL ETHERNET ADAPTER

# Report
LOGFILE=/home/administrator/Documentos/ReportInternet.log

# Messages
MESSAGE1="Restoring Connectivity..."
MESSAGE2="Wait a moment please..."
MESSAGE3="No Internet connectivity."
MESSAGE4="Yes, there is Internet connectivity."
#################################################################################

# Time and Date
TODAY=$(date "+%r %d-%m-%Y")

# Show IP Public Address
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
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$
}

# Restoring Connectivity
resolve() {
    clear
    echo "$MESSAGE1"
    sudo ifconfig $ADAPTER1 up;sudo dhclient -r $ADAPTER1;sleep 5;sudo dhclient $ADAPTER1
    echo "$MESSAGE2"
    sleep 120
}

# Execution of work
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

Джон Ллевелин
источник
Что могло бы сделать этот ответ лучше: (1) Объяснение того, как работает скрипт. (Похоже, что пользователь должен редактировать сценарий, если его сетевой интерфейс называется как-нибудь иначе eth0, но это не упоминается.) (2) Использование английского языка. (3) Поместить все переменные оболочки (например "$HOST", "$LINE1"и "$LOG") в двойные кавычки. (4) Либо установите, LINE2либо не используйте его. (Я подозреваю , что вы получили LINE1 /  LINE2путать с inet4 /  inet6.) ... (продолжение)
G-Man говорит 'восстановила Монику'
(Продолжение)… (5) На самом деле отображает текущее время, когда вы говорите, что отображаете текущее время, а не фиксируете время, когда запускается сценарий, и отображаете его в течение всего времени существования сценария. (6) Я думаю, что было что-то еще, но я не вижу этого сейчас.
G-Man говорит: «Восстановите Монику»
Это на испанском, потому что это на моем языке, но я могу исправить это на английском. $ HOST - это адрес, который нужно попробовать. $ LINE1 - это интернет-соединение, которое подключается с помощью адаптера eth0. $ LINE2 - это интернет-соединение, которое подключается с помощью адаптера eth1, если у вас есть две интернет-линии, но рекомендуется оставить его отключенным. Дата, если я проверяю, что она поддерживает то же время и дату с момента запуска сценария, я должен исправить эту проблему. В эти выходные я исправляю проблему.
Джон Ллевелин
Хорошо, G-Man, я внес некоторые изменения, мне все еще нужно исправить дату и улучшить некоторые вещи.
Джон Ллевелин