Shell Scripting: Правильний спосіб перевірити наявність підключення до Інтернету?


26

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

Будь-які пропозиції щодо правильного / надійного способу перевірити наявність підключення до Інтернету за допомогою скриптів? Чи потрібно використовувати якісь пакети?

Потрібно мати можливість періодично перевіряти, cronнаприклад, тоді робити щось, коли з'єднання знижується, як викликifup --force [interface]

Відповіді:


29

Тестування підключення IPv4

Якщо ваша мережа дає змогу пінгінг, спробуйте pinging 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

Ви можете включити перевірку фізичного з'єднання (OSI-рівень 1) до будь-якого перевірки рівня 3 OSI, використовуючи ethtool; $ ethtool <dev> | awk '$0 ~ /link detected/{print $3}'
жас-

Чи можете ви пояснити мету додати це, будь ласка,>/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

Це перевіряє наявність з'єднання (замість того, щоб чекати, коли Opensl буде вичерпано), а потім робить рукостискання SSL, натискаючи на фазі перевірки. Він мовчки виходить ("вірно"), якщо перевірка була "ОК", або ж виходить із помилкою ("помилковою"), тоді ми повідомляємо про знахідку.


5
Я поважаю Джилі, проте це правильна відповідь.
gwillie

3
Додайте, -dнаприклад, nc -dzw1також, щоб він не слухав STDIN і не зависав невизначено у сценарії. і, можливо, використовуйте 8.8.8.8 замість google.com для збереження пошуку. nc -dzw1 8.8.8.8 443
децца

Я не впевнений у тому, наскільки надійний DNS-вирішальник Google обслуговує HTTPS. Сервер google.com повинен бути надійнішим для HTTPS (якщо ви не знаходитесь у Китаї, але вони, ймовірно, заблоковані). Я ніколи не потребував -dсвоїх сценаріїв, можливо, тому, що ніколи не мав невикористаного конвеєра. Це слід безпечно додати.
Адам Кац

1
@dezza - -w 1все-таки коштує секунду, коли немає підключення, хоча, можливо, у вас ncє якась незрозуміла проблема десь. Якщо у вас встановлена ​​остання версія nmap, ви можете замість цього ncat --send-only --recv-only -w 334msскоротити час відмови на третину nc(я виявив, що 334 мс - хороший час очікування).
Адам Кац

1
@dezza - Я не знаю, чому це відбувається з вами ncat ncat і 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

Приємно! Дякую ! До чого нам встановити шлюз $GW?
Ciprian Tomoiagă

@CiprianTomoiaga Не потрібно, /sbin/ip route | awk '/default/ { print $3 }'отримує адресу шлюзу з (сподіваємось) основного інтерфейсу. Якщо ви хочете, можете самі встановити IP-адресу шлюзу.
PNDA

Дякую за це! Що я сумую, - це можливість зберігати збої в Інтернеті у файлі txt та автоматизованому електронному листі для свого провайдера.
rhand

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

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 необов'язково, якщо у вас є 2 лінії Інтернет, але рекомендується залишити його відключеним. Дату, якщо я переконуюсь, що вона підтримує той самий час і дату з моменту запуску сценарію, я мушу виправити цю проблему. У ці вихідні я виправляю проблему.
Джон Левелін

Гаразд G-Man, я вніс деякі зміни, мені ще потрібно виправити дату та покращити деякі речі.
Джон Левелін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.