Как получить вывод команды ping в Python?
Как я понял stdout=subprocess.PIPE — это перехват вывода результатов команды.
Так вот я хочу спарсить этот результат и выдавать предупреждение не только по пристутствию/отсутствию пинга, но и по его длительности.
Как мне завести результат выдачи команды ping в переменную для дальнейшего анализа?
- Вопрос задан более трёх лет назад
- 13391 просмотр
1 комментарий
Оценить 1 комментарий
Ping пакеты как временное хранилище данных на python raw socket
Когда неподкованные пользователи (пенсионеры, школьники, офисный планктон) первый раз сталкиваются с чёрным окошком, именуемым «Командной строкой» они зачастую хотят с профессиональным видом проверить интернет соединение.
ping 8.8.8.8
Магический C:\Windows\System32\PING.EXE выполняет вполне интуитивно понятные действия: отправляет запрос на указанный адрес (в данном случае 8.8.8.8 — dns google), и если адрес отвечает, то выводит задержку ответа, по которой можно косвенно судить о скорости интернет соединения.
Если же вы имеете начальное представление о принципе работы интернетов этих ваших и примерно понимаете сетевую модель, то вам до следующего заголовка)
База базовая
Сидели умные люди такие в восьмидесятых и думали, как бы интернет сделать общий. Сидели они, будучи соединёнными сотнями Ethernet кабелей и разрабатывали иерархическую модель интернета, дабы каждый был соединён с каждым, и было всё стильно, да без централизации.

Зелёные (верхние) уровни нас не интересуют, их реализовывают конкретные приложения и сервисы, их зоопарк мы трогать не будем. Нужно идти с низов.

Провод передаёт приёмнику логическое состояние передатчика (0\1 — 1бит), является самым низким (физическим) уровнем.

Второй уровень добавляет понятие MAC адресов. Теперь тот, кто отправляет данные, идентифицирует того, кто на другом конце провода. Каждому устройству в сети даётся уникальный шестибайтный адрес, и появляется возможность маршрутизировать данные к конкретному абоненту (в зоне действия провода).

Теперь данные пакуются в пакеты и адресуются некому IP адресу получателя, а специальные устройства вроде вашего роутера или огромного шкафа-маршрутизатора в общаге заботятся об их доставке (но не гарантируют её!)
Поверх 3его уровня, в частности IP адресов были построены такие протоколы передачи данных как TCP, HTTPS, UDP, FTP, ICMP и т.д. Они заботятся о многих вещах: гарантии передачи данных, безопасности и передаче конкретных высокоуровневых структур данных.
Идея!
Тут лучше просто взглянуть на оригинал:
Его план такой (конечно, интернет подразумевается безлимитным, а сетевой адаптер достаточно мощным):


- Находим точки А и В максимально удалённые друг от друга в сети.
- Отправляем большие данные из А в В
- Они фрагментируются и тормозят по пути, оседая в кэшах маршрутизаторов, которые их соединяют. (растёт задержка)
- Пункт В просто отправляет данные обратно к А
- А использовал модель интернета как «дикое» хранилище файлов на некоторое время (сравнимое с секундой)
Звучит бесполезно, но интересно. Надо подумать
Есть проблема: В в данном случае остается ни с чем. И совершать такие пересылки взаимно не выгодно.
Вот если бы можно было обойтись без В
Ты не можешь контролировать улетевший пакет
Или можешь. Улетевший пакет. Ping?
Ping — утилита для проверки целостности и качества соединений в сетях (или, проще говоря, штука которая отправляет ICMP Echo пакеты)

Созревает план. Кладём пароль от крипто-кошелька в нагрузку пинг пакета (удаляем его локально), отправляем на другой конец земного шара и на протяжении 0.5сек он хранится, будучи в кэшах роутеров и маршрутизаторов по дороге!
Но windows не позволяет редактировать содержимое, отправляемое ping.exe(
Но, для начала, проверим: есть ли оно вообще?
Качаем Wireshark — (вики) — (офиц. сайт) — утилиту для перехвата пакетов. Запускаем перехват и ping 8.8.8.8 в консоли.
Полезная нагрузка (данные) в этом пакете действительно есть, однако до реальной пользы им далеко — это английский алфавит (нет, я не испытываю ненависть к латинице, просто мне хотелось бы уметь редактировать это содержимое).
Точка невозврата
С этого момента начинается практическое создание скрипта, который автоматизировал бы это. Идея изначально провальная, ведь icmp не гарантирует доставку, и очень ценные файлы, которые я буду фрагментировать и гонять таким образом рано или поздно будут по частям теряться).
Ну, а мне и не жалко, ведь дальше я хотел просто шутки ради реализовать этот механизм на Python\Sockets потестить, и забыть как страшный сон — поехали:
ICMP
Протокол межсетевых управляющих сообщений, или проще говоря — проверки связи.
Не гарантирует доставку данных, не использует шифрование — сплошной минимализм. Но, зато он просит получателя отправить себя обратно! Если получатель (сетевое устройство 3его уровня сетевой модели) не стало намеренно отклонять подключение, то оно скорее всего так и поступит.
icmp пакетами можно конечно отправлять полезные коды, которые помогут администрировать сеть, но мы его будем рассматривать как примитивный тестер связи, ок?
(я специально не упоминаю порты и всё что с ними связано, ведь 1й порт для ICMP это скорее условность, да и эта информация нигде далее не понадобится)
Структура ICMP пакета

Начнём с низов этой вложенной структуры.
- Заголовок кадра это всё, что о пакете нужно знать для MAC адресации — мы с этим уровнем взаимодействовать не будем, так что идём далее.
- Заголовок дейтограммы (Заголовок IP) — IP header 20 байт под адреса получателя\отправителя и прочей служебной информации для сетевой маршрутизации по IP.
- ICMP заголовок и ICMP данные — в нашем случае данные это: Идентификатор + Номер последовательности + Данные (payload, хехе. )
Ре-а-ли-за-ци-я
Строгое представление ICMP header:
type (8), code (8), checksum (16), id (16), sequence (16)
def create_packet(id): ICMP_ECHO_REQUEST=8 #Код типа ICMP - в нашем случае ECHO header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, (тут должен быть хэш пакета), 0, id, 1) data = "hello!" return header + data
Подготовим icmp пакет используя STRUCT для превращения типов данных в байты.
Но есть один нюанс. Это дырка (тут должен быть хэш пакета), checksum — если вам так угодно. Без него наш пакет будет сочтён за битый. Парадоксально, ведь мы должны посчитать хэш пакета, ещё до его создания. Однако, допустимо использовать для подсчёта хэша хэш в заголовке = 0
def create_packet(id): ICMP_ECHO_REQUEST=8 #Код типа ICMP - в нашем случае ECHO header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, 0, id, 1) data = b"hello!" my_checksum = checksum(header + data) header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), id, 1) return header + data
Создаем шаблон пакета, добавляем наши данные в виде «hello!», считаем checksum (пока не ясно как), и создаем окончательный пакет, зная хэш.
Функцию для подсчёта хэша пакета я подсмотрел где-то на просторах интернета, и не пожалел. Нужно было только немного адаптировать под python3.
def checksum(source_string): sum = 0 count_to = (len(source_string) / 2) * 2 count = 0 while count < count_to: this_val = source_string[count + 1]*256+source_string[count] sum = sum + this_val sum = sum & 0xffffffff count = count + 2 if count_to < len(source_string): sum = sum + source_string[len(source_string) - 1] sum = sum & 0xffffffff sum = (sum >> 16) + (sum & 0xffff) sum = sum + (sum >> 16) answer = ~sum answer = answer & 0xffff answer = answer >> 8 | (answer
Построитель пакетов полностью готов.
Остаются: функция send и функция recv
Вторая будет выполняться через время после первой и получать обратно отправленное.
def send(dest_addr): my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, ICMP_CODE) host = socket.gethostbyname(dest_addr) packet_id = random.randint(0,65535) packet = create_packet(packet_id) while packet: sent = my_socket.sendto(packet, (dest_addr, 1)) packet = packet[sent:] return my_socket,packet_id
Send отправляет наш hello на данный ей адрес и возвращает сокет и ид пакета, в котором ждать возвращения оного.
def recv(my_socket, packet_id): ready = select.select([my_socket], [], [], 2) #таймаут 2с rec_packet, addr = my_socket.recvfrom(1024) icmp_header = rec_packet[20:28] # Байты с 20 по 28 - заголовок ICMP type, code, checksum, p_id, sequence = struct.unpack( 'bbHHh', icmp_header) data = rec_packet[28:] # Наш hello будет лежать после заголовка ICMP return data
Recv получает пакет с заданным ID из старого сокета
Последние штрихи для запуска
import struct import socket import random import select ICMP_CODE = socket.getprotobyname('icmp')
Тест
Пора бы и продемонстрировать работу сия кода:
Попробуем отправить hello гуглу
send("8.8.8.8")
![]()
Попробуем отправить и получить обратно через время.
sock, src="https://habrastorage.org/getpro/habr/upload_files/1fa/489/c4e/1fa489c4e802d922cb86c8dfba1aede4.png" alt="кажется, работает" width="432" height="35" />
Добавил функции send аргумент data, для кастомизации этого Hello
import struct import socket import random import select ICMP_CODE = socket.getprotobyname('icmp') def checksum(source_string): sum = 0 count_to = (len(source_string) / 2) * 2 count = 0 while count < count_to: this_val = source_string[count + 1]*256+source_string[count] sum = sum + this_val sum = sum & 0xffffffff count = count + 2 if count_to < len(source_string): sum = sum + source_string[len(source_string) - 1] sum = sum & 0xffffffff sum = (sum >> 16) + (sum & 0xffff) sum = sum + (sum >> 16) answer = ~sum answer = answer & 0xffff answer = answer >> 8 | (answer
Была отправлена строка, и получена через 50мс, однако, это не есть решенная задача.
Дописать же функцию для фрагментации и последовательной отправки файла я предлагаю вам самим.
Я дописал и решил проблему маленького пинга до 8.8.8.8 (не успевал отправить много данных, как они начинали возвращаться). Нашел адрес одного стабильного сайта с хостингом в Новой Зеландии(пинг ~400). Что?
Однако есть ограничения, которые не позволяют получить зрелищный результат.
Один icmp пакет не хочет нести больше 1кб, а если отправлять их с очень большой частотой, то они бьются еще на старте.
Максимальный размер файла, который мне удалость удержать таким образом был текст 0.1мб (что вполне прилично для текста). Конечно, он со временем исчезал по кускам, но это следует из отсутствия гарантий доставки у ICMP.
Conclusion
Под конец могу сказать, что в итоге получилась (как и ожидалось) не самая полезная и практичная программа, которая может сохранить 0.1мб файлик у себя и потерять его спустя пару часов непрерывной работы. Зато был получен позитивный опыт работы с низкоуровневыми сокетами.
Будет интересно, дочитал ли вообще кто-то это до конца?
Оцените, пожалуйста первую статью на Хабре 🙂 Здравая критика, а что в особенности важно - ещё бесполезные, но весёлые идеи приветствуются!
Проверка пинга хоста на Python
Есть небольшой скрипт, где я подключаюсь к свитчам по телнету. Но перед этим нужно проверить доступен ли он. Программа работает, но если свитч недоступен программа не останавливается, пока я принудительно это не сделаю. Подскажите как сделать чтобы программа завершала процесс когда хост недоступен
import telnetlib import os Host = input("Введите Ip адрес свитча: ") Ping = os.system("ping -c 1 " + Host) if Ping == 0: User = input("Username: ").encode() Password = input("Password: ").encode() tn = telnetlib.Telnet(Host) tn.read_until(b'Username:') tn.write(User + b'\n') tn.read_until(b'Password:') tn.write(Password + b'\n') tn.write(b'terminal length 512' + b'\n') inputCommand = input("Введите команду: ").encode() tn.write(inputCommand + b'\n') exitLine = input("Введите exit для завершения: ").encode() tn.write(exitLine + b'\n') showInf = tn.read_all().decode() print(showInf) else: print(Host, "Недоступен")
Отслеживать
149k 12 12 золотых знаков 59 59 серебряных знаков 132 132 бронзовых знака
задан 9 июл 2019 в 11:47
Mr.Closer95 Mr.Closer95
31 1 1 серебряный знак 5 5 бронзовых знаков
[Python] Пинг
В общем задача написать небольшую программулину под никс, чтобы при запуске она пинговала определенный IP адрес, но без использования системного PING. Какие есть способы реализации?
strelockk
27.07.11 04:51:27 MSK

Бедняга. Забанен корпорацией добра? Сочувствую.
baverman ★★★
( 27.07.11 05:12:36 MSK )

но без использования системного PING
Попахивает домашним заданием. Я бы снес топик.
baverman ★★★
( 27.07.11 05:14:18 MSK )

Гугль внезапно отключился?
sambo ★
( 27.07.11 08:33:19 MSK )

papochka ★
( 27.07.11 08:44:46 MSK )
anonymous
( 27.07.11 10:57:00 MSK )

Я сейчас сам пишу низкоуровневую реализацию пинга на питоне. Можешь покурить исходники http://code.google.com/p/python-packet/ , там все просто - мутишь ICMP-пакет и отправляешь через RAW-сокет. Проблема только в том, что потребуются рутовые права на отправку либо suid-бит.
enchantner
( 27.07.11 11:39:27 MSK )
Ответ на: комментарий от enchantner 27.07.11 11:39:27 MSK

У тебя по коду разбросаны ахтунги в виде нативных типоразмеров. На другой архитектуре он может тупо не заработать.
baverman ★★★
( 27.07.11 12:05:10 MSK )
Ответ на: комментарий от baverman 27.07.11 12:05:10 MSK

Вот черт, неправильно выразился. По ссылке не моя разработка, а исходники, которые я курю для разбора raw-сокетов в питоне.
enchantner
( 27.07.11 12:10:21 MSK )
Ответ на: комментарий от enchantner 27.07.11 12:10:21 MSK

Если нужно просто собрать заголовки, без особого вникания в подробности, я бы взял scapy или pyip. Они, по крайней мере, что называется mature.
