Сканирование IP устройств в локальной сети. Python

Возникла тут тривиальная задача посмотреть какие IP заняты в локальной сети. И конечно есть целая куча всяких программ сканеров, но хочется же что то свое сварганить )

Немного подумав, пришел к выводу что самое простое это просто пингануть всю локальную сеть. На самом деле Ping это название утилиты которая входит в ОС, а сама эта хрень называется ICMP Echo-Request( запрос ) и ICMP Echo-Reply( ответ ). К стати пинг не гарантирует что устройство не доступно, так как ответ на пинг может быть просто запрещен на устройстве или брандмауэре .

ICMP (Internet Control Message Protocol — протокол межсетевых управляющих сообщений) — сетевой протокол, входящий в стек протоколов TCP/IP.

Вообщем он там зарыт где то глубоко глубоко, писать реализацию своего стека мне уж точно не под силу. По этому будем пользоваться уже готовой системной утилитой. Для отправки ICMP Echo-Request мы должны иметь права АДМИНИСТРАТОРА ( root ). Поехали.

Первым дело узнаем IP нашего сетевого интерфейса, в какой мы вообще сети :

import socket
def getMyIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #Создаем сокет (UDP)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # Настраиваем сокет на BROADCAST вещание.
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]
  • socket.AF_INET — для сокета используем IPv4 .
  • socket.SOCK_DGRAM — тип сокета. Датаграммный сокет (UDP) .
  • getsockname() — Вернет сокету его собственный адрес.

Это наверное не самый элегантный способ.Но должен работать в любой локальной сети, которая позволяет широковещательную рассылку UDP и не требует доступа куда либо. Есть еще идее ? Пишите в комментах )

Далее на надо узнать платформу. В Windows и Linux команда будет выглядеть немного по разному. Для определение ОС в Питоне есть команды platform.system() которая входит в стандартную библиотеку OS . Возвращает имя системы / ОС, например 'Linux','Windows', или 'Java'.  Пустая строка возвращается, если значение не может быть определено :

import os
import platform

oс = platform.system()

if (oс == "Windows"):
    ping_com = "ping -n 1 "
else:
    ping_com = "ping -c 1 "

Введем диапазон адресов для сканирования :

start_point = int(input("Enter the Starting Number: "))
end_point = int(input("Enter the Last Number: "))

Ну теперь напишем саму функцию сканирования :

net = getMyIp()
net_split = net.split('.')
a = '.'
net = net_split[0] + a + net_split[1] + a + net_split[2]+ a
def scan_ip(ip):
    addr = net + str(ip)
    comm = ping_com + addr
    response = os.popen(comm)
    data = response.readlines()
    for line in data:
        if 'TTL' in line:
            print(addr, "--> Ping Ok")
            break
  • os.popen(comm) — Класс Popen Python выполняет дочернюю программу в новом процессе.
  • data = response.readlines() — читаем ответ от утилиты.
  • Дальше просто парсим ответ, если есть TTL в строке значит пинг успешен.

Еще добавим многопоточность что бы быстрей пинговать. Весь код целиком :

import os
import platform
import threading
import socket
from datetime import datetime

def getMyIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #Создаем сокет (UDP)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # Настраиваем сокет на BROADCAST вещание.
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

def scan_Ip(ip):
    addr = net + str(ip)
    comm = ping_com + addr
    response = os.popen(comm)
    data = response.readlines()
    for line in data:
        if 'TTL' in line:
            print(addr, "--> Ping Ok")
            break

net = getMyIp()
print('You IP :',net)
net_split = net.split('.')
a = '.'
net = net_split[0] + a + net_split[1] + a + net_split[2] + a
start_point = int(input("Enter the Starting Number: "))
end_point = int(input("Enter the Last Number: "))

oс = platform.system()
if (oс == "Windows"):
    ping_com = "ping -n 1 "
else:
    ping_com = "ping -c 1 "

t1 = datetime.now()
print("Scanning in Progress:")

for ip in range(start_point, end_point):
    if ip == int(net_split[3]):
       continue
    potoc = threading.Thread(target=scan_Ip, args=[ip])
    potoc.start()

potoc.join()
t2 = datetime.now()
total = t2 - t1

print("Scanning completed in: ", total)

Получилось достаточно простая программка. В следующий раз добавим еще отображение MAC адреса и Vendor . Можно еще добавить определение сетевого имени ПК и т.д.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.