Статья Сканер локальной сети для получения списка IP и MAC адресов на Python

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

000.jpg


Что понадобиться?

Для того, чтобы создать быстрый сканер сети, с возможностью его дальнейшего расширения, нам понадобиться установить scapy. Это многофункциональная библиотека, которая позволяет отправлять, анализировать и подделывать сетевые пакеты, а также сканировать или атаковать сети. Установка ее достаточно простая. Нужно написать в терминале команду:

pip install --pre scapy[basic]

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

screenshot1.png

Если ваша операционная система отличается от Linux, а в данном случае имеется в виду Windows, то потребуется установить библиотеку захвата пакетов Npcap. Если же вы используете Windows XP, хотя на сегодняшнее время это вряд ли, то нужно использовать библиотеку WinPcap. Установить Npcap можно скачав его с официального сайта.

На этом подготовительный этап можно завершить. Давайте теперь импортируем scapy в наш скрипт.

Python:
from platform import system
from socket import socket, AF_INET, SOCK_DGRAM
from subprocess import check_output
import os

import scapy.all as sc

Как видите, помимо библиотеки scapy для скрипта нужно будет импортировать еще несколько модулей входящих в состав стандартных библиотек python. В данном случае библиотека platform будет нужна для определения операционной системы. Так как данный скрипт будет работать как в Windows, так и в Linux. Библиотека socket используется для получения локального IP-адреса компьютера, а subprocess для выполнения команды и тем самым получения IP-адреса роутера, используемого в системе по умолчанию.


Получаем локальный IP-адрес

Давайте приступим к созданию сканера сети. Для начала нам будет нужна функция, которая получает локальный IP-адрес машины. Создадим ее и назовем, к примеру: local_ipv4(). Данная функция устанавливает соединение с адресом 10.255.255.255, а затем с помощью getsockname возвращает адрес и порт сокета. В данном случае порт нам не нужен, а вот адрес вполне пригодится. Поэтому забираем его из кортежа и возвращаем из функции. Если же произошла ошибка и соединение не удалось, возвращается адрес 127.0.0.1. Что, в принципе, будет соответствовать действительности, так как в данном случае сетевого соединения не будет, а будет использоваться только localhost.

Python:
def local_ipv4():
    st = socket(AF_INET, SOCK_DGRAM)
    try:
        st.connect(('10.255.255.255', 1))
        ip_l = st.getsockname()[0]
    except Exception:
        ip_l = '127.0.0.1'
    finally:
        st.close()
    return ip_l

Дополнение: функцию получения локального адреса можно сделать немного по другому, но только в том случае, если у вас ОС Linux. Нужно дополнительно установить библиотеки getmac и netifaces.

pip install getmac netifaces

В импорт добавить:

Python:
from getmac.getmac import _get_default_iface_linux
from netifaces import ifaddresses, AF_INET

Тогда функция будет выглядеть вот так:

Python:
def local_ipv4():
    try:
        return ifaddresses(_get_default_iface_linux()).setdefault(AF_INET)[0]['addr']
    except TypeError:
        return '127.0.0.1'


Получение IP-адреса шлюза используемого в системе по умолчанию

На следующем этапе нужно получить IP-адрес шлюза, который используется в системе по умолчанию. Для этого используем subprocess.check_output, которая запускает выполнение определенной команды в терминале и возвращает ее вывод. И для Linux, и для Windows будем использовать похожие команды. Для Linux это «route -n», а вот с Windows все чуточку посложнее, так как там при выполнении команды возвращается куча всяких не особо то нужных в данном случае параметров. Поэтому нужно будет выполнить среди всей этой информации поиск и вывести уже отфильтрованный результат.

Давайте сделаем первую функцию для Windows. Создадим get_gateway_win(). На вход она не получает никаких данных, а на выходе возвращает адрес шлюза. С помощью subprocess.check_output выполняется команда, после чего результат приводится к нужному виду и возвращается из функции.

Python:
def get_gateway_win():
    # получаем адрес шлюза по умолчанию для текущего сетевого интерфейса
    com = f'route PRINT 0* | findstr {local_ipv4()}'.split()
    return check_output(com, shell=True).decode('cp866').split()[2]

И для Linux, создадим функцию get_gateway_linx(). Принцип получения адреса шлюза здесь тот же самый и на выходе получается нужный адрес шлюза.

Python:
def get_gateway_linx():
    com = 'route -n'.split()
    ip_route = str(subprocess.check_output(com, shell=True)).split("\\n")[2].split()[1].strip()
    if ip_route.isdigit():
        return ip_route
    else:
        sock = socket.gethostbyname(ip_route)
        return sock


Сканирование сети

Теперь самое время приступить к сканированию сети. Создадим функцию get_ip_mac_nework(ip), которая на входе будет получать начальный адрес для сканирования с маской подсети, а возвращать список из словарей с полученными значениями ip и mac адресов. Сделаем с помощью функции scapy.srp широковещательный ARP запрос, чтобы получить ответы от всех компьютеров, которые находятся с нами в одной сети. Для отправки запроса нужно сформировать пакет, который будет состоять из широковещательного адреса и ARP-пакета, в котором указывается адрес и маска подсети. Параметр timeout указывает на то, что между запросами нужно делать паузу в одну секунду, а параметр verbose позволяет не выводить результаты выполнения запроса в терминал.

answered_list = sc.srp(sc.Ether(dst='ff:ff:ff:ff:ff:ff') / sc.ARP(pdst=ip), timeout=1, verbose=False)[0]

С помощью данного запроса мы можем получить два списка. С запросами, на которые был получен ответ и с запросами, на которые ответ не был получен. Так как нам не отвеченные запросы вроде бы без надобности, забираем только те, ответ на которые был получен. Потому, указываем явно, что забираем 0 элемент.

Далее в цикле пробежимся по содержимому списка с запросами и получим из него нужные значения, которые добавим в список, возвращаемый из функции в виде словаря.

Python:
def get_ip_mac_nework(ip):
    answered_list = sc.srp(sc.Ether(dst='ff:ff:ff:ff:ff:ff') / sc.ARP(pdst=ip), timeout=1, verbose=False)[0]
    clients_list = []
    for element in answered_list:
        clients_list.append({'ip': element[1].psrc, 'mac': element[1].hwsrc})
    return clients_list


Печать результатов сканирования

Ну и осталось вывести полученные результаты на экран. В данном случае за это будет отвечать функция print_ip_mac(mac_ip_list), которая на входе получает сформированный ранее список со словарями. Тут все просто. Пробегаемся в цикле по списку и получаем определенные значений из словарей под нужным индексом. После чего выводим на экран.

Код функции печати:

Python:
def print_ip_mac(mac_ip_list):
    print(f"\nMachine in Network:\n\nIP\t\t\t\t\tMAC-address\n{'-' * 41}")
    for client in mac_ip_list:
        print(f'{client["ip"]}\t\t{client["mac"]}')


Запуск сканирования сети

Для запуска сканирования сети, а также получения ip адресов будем использовать функцию main(). Для начала получим локальный ip, затем, в зависимости от системы ip шлюза. Сформируем из полученного локального IP-адреса адрес сети с маской и запустим функцию сканирования сети. После чего выведем на экран IP-адреса и результаты сканирования.

Код функции main():

Python:
def main():
    local_ip = local_ipv4()
    if system() == "Windows":
        gateway = get_gateway_win()
    elif system() == 'Linux':
        if not os.getuid() == 0:
            print('\n[+] Запустите скрипт с правами суперпользователя!\n')
            return
        gateway = get_gateway_linx()
    ip_mac_network = get_ip_mac_nework(f'{local_ip.split(".")[0]}.{local_ip.split(".")[1]}.{local_ip.split(".")[2]}.1/24')
    print(f'\n[+] Local IP: {local_ip}\n[+] Local Gateway: {gateway}')
    print_ip_mac(ip_mac_network)

А на этом, в данном случае все. Сканер сети готов, осталось только посмотреть на результаты его работы. Запускаем и видим, что в нашей локальной сети есть межсетевой экран. А те, кто понимает, даже узнали, что это pfSense, а также три машины ip и mac адреса которых были благополучно получены.

Результат работы сканера:

screenshot2.png


Python:
from platform import system
from socket import socket, AF_INET, SOCK_DGRAM, gethostbyname
from subprocess import check_output
import os

import scapy.all as sc


# получаем локальный IP-адрес
def local_ipv4():
    st = socket(AF_INET, SOCK_DGRAM)
    try:
        st.connect(('10.255.255.255', 1))
        ip_l = st.getsockname()[0]
    except Exception:
        ip_l = '127.0.0.1'
    finally:
        st.close()
    return ip_l


def get_gateway_win():
    # получаем адрес шлюза по умолчанию для текущего сетевого интерфейса в Windows
    com = f'route PRINT 0* | findstr {local_ipv4()}'.split()
    return check_output(com, shell=True).decode('cp866').split()[2]


# получение ip адреса шлюза используемого по умолчанию в Linux
def get_gateway_linx():
    ip_route = str(check_output('route -n | grep UG', shell=True).decode()).split()[1].strip()
    return ip_route


# сканируем сеть, получаем ip и mac сетевых машин
def get_ip_mac_nework(ip):
    answered_list = sc.srp(sc.Ether(dst='ff:ff:ff:ff:ff:ff') / sc.ARP(pdst=ip), timeout=1, verbose=False)[0]
    clients_list = []
    for element in answered_list:
        clients_list.append({'ip': element[1].psrc, 'mac': element[1].hwsrc})
    return clients_list


# функция печати сканированных ip и mac
def print_ip_mac(mac_ip_list):
    print(f"\nMachine in Network:\n\nIP\t\t\t\t\tMAC-address\n{'-' * 41}")
    for client in mac_ip_list:
        print(f'{client["ip"]}\t\t{client["mac"]}')


def main():
    local_ip = local_ipv4()
    if system() == "Windows":
        gateway = get_gateway_win()
    elif system() == 'Linux':
        if not os.getuid() == 0:
            print('\n[+] Запустите скрипт с правами суперпользователя!\n')
            return
        gateway = get_gateway_linx()
    ip_mac_network = get_ip_mac_nework(f'{local_ip.split(".")[0]}.{local_ip.split(".")[1]}.{local_ip.split(".")[2]}.1/24')
    print(f'\n[+] Local IP: {local_ip}\n[+] Local Gateway: {gateway}')
    print_ip_mac(ip_mac_network)


if __name__ == "__main__":
    main()

Ну и да, не забывайте о том, что именно таким образом вам удастся просканировать только локальную сеть.

Спасибо за внимание. Надеюсь, что данная информация была кому-нибудь полезной
 

Вложения

  • network_scanner_lin_win.zip
    1,1 КБ · Просмотры: 67
Последнее редактирование:

Johan Van

Green Team
13.06.2020
153
280
если не начинал с С и это не универовский предмет, а самостоятельное изучение, возможно стоит начать учить Rust вместо С. Думаю, на нем тоже можно написать модули для питона, но еще и много всего другого

Спасибо за наводку. С раньше не учил нигде. Попробую. Что-то должно получиться ))
 

Polyglot

Green Team
25.02.2020
27
40
Вау, сколько жару из-за одного скрипта :)
Подведем итоги:

  • Python НЕ имеет надежной встроенной/стандартной функции определения адреса IP локальной машины. Документация и примеры посылают к
    import socket
    hostname = socket.gethostname()
    Ipaddr = socket.gethostbyname(hostname)
    print("Your Computer Name is:" + Ipaddr) Но тут адрес определяется запросом в ДНС и другие сервисы такого типа (/etc/hosts итд), то
    есть если резолвинга на адрес нет то выдаст ошибочный адрес (127.0.0.1).
  • имхо - питон зарождался во времена когда сети не были настолько важны и пропустили сей момент
  • Проблему пробовали решать/обойти, но на сегодня тот хак что @Johan Van привел самый популярный (и наверное надежный). Обзор
    всевозможных способов например тут How can I get the IP address from a NIC (network interface controller) in Python?
  • Моя проблема с таким хаком в том что он основан на "побочном эффекте" использования модуля socket и поэтому может перестать работать в будущем в любой момент.
    Как я бы решил проблему ? Не использовал бы Питон для такой задачи:
Golang:
C-подобный:
package main

import (
    "fmt"
    "net"
)

func main() {
    addrs, _ := net.InterfaceAddrs()
    fmt.Printf("%v\n", addrs)

1653487536836.png


Всем хорошего дня.
 
  • Нравится
Реакции: Архонт и Johan Van

Johan Van

Green Team
13.06.2020
153
280
Вау, сколько жару из-за одного скрипта :)
Подведем итоги:

  • Python НЕ имеет надежной встроенной/стандартной функции определения адреса IP локальной машины. Документация и примеры посылают к
    import socket
    hostname = socket.gethostname()
    Ipaddr = socket.gethostbyname(hostname)
    print("Your Computer Name is:" + Ipaddr) Но тут адрес определяется запросом в ДНС и другие сервисы такого типа (/etc/hosts итд), то
    есть если резолвинга на адрес нет то выдаст ошибочный адрес (127.0.0.1).
  • имхо - питон зарождался во времена когда сети не были настолько важны и пропустили сей момент
  • Проблему пробовали решать/обойти, но на сегодня тот хак что @Johan Van привел самый популярный (и наверное надежный). Обзор
    всевозможных способов например тут How can I get the IP address from a NIC (network interface controller) in Python?
  • Моя проблема с таким хаком в том что он основан на "побочном эффекте" использования модуля socket и поэтому может перестать работать в будущем в любой момент.
    Как я бы решил проблему ? Не использовал бы Питон для такой задачи:
Golang:
C-подобный:
package main

import (
    "fmt"
    "net"
)

func main() {
    addrs, _ := net.InterfaceAddrs()
    fmt.Printf("%v\n", addrs)

Посмотреть вложение 59940

Всем хорошего дня.

А в Go много чего интересного, похоже есть )) Надо будет подробнее с ним познакомиться ))
 
17.06.2022
6
0
Добрый день!
Подскажите, пожалуйста.
Зачем тут используется метод сплит в конце строки?
Python:
com = f'route PRINT 0* | findstr {local_ipv4()}'.split()
Ведь в check_output команду можно передать в виде строки.
 

Johan Van

Green Team
13.06.2020
153
280
Добрый день!
Подскажите, пожалуйста.
Зачем тут используется метод сплит в конце строки?
Python:
com = f'route PRINT 0* | findstr {local_ipv4()}'.split()
Ведь в check_output команду можно передать в виде строки.

Можно. Делить строку не обязательно. Но, у меня почему-то не получалось, уже не помню почему, передать команду с "|", вылетала ошибка. А когда делил на запчасти, тогда все работало. Попробуйте не делить. Может быть все будет работать и без split()
 
17.06.2022
6
0
Спасибо. Еще пара вопросов:
1. Почему в этой строке мы находим адрес первого узла сети, а не адрес самой сети?
Код:
ip_mac_network = get_ip_mac_nework(f'{local_ip.split(".")[0]}.{local_ip.split(".")[1]}.{local_ip.split(".")[2]}.1/24')

По ссылке
сказано следующее:

ARP Ping

The fastest way to discover hosts on a local ethernet network is to use the ARP Ping method:

>>> ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"), timeout=2)

Есть ли разница?

Там же по ссылке, кстати, предлагается использовать команду arping("192.168.1.0/24"), вместо той, что выше. Только не понял, как ее вывод перегнать в словарь. Если вернуть результат выполнения функции в переменную, то айпишники и макадреса внутри элементов видно, но обратиться к ним не получается.

2. Почему итоговая программа выдает всегда разное количество адресов устройств в сети? У меня к вай-фаю подключены всякие телефоны, телевизоры, камеры и все они находятся редко. Обычно сам ноут, роутер и 1-2 других устройств.
 
Последнее редактирование:

Johan Van

Green Team
13.06.2020
153
280
Спасибо. Еще пара вопросов:
1. Почему в этой строке мы находим адрес первого узла сети, а не адрес самой сети?
Код:
ip_mac_network = get_ip_mac_nework(f'{local_ip.split(".")[0]}.{local_ip.split(".")[1]}.{local_ip.split(".")[2]}.1/24')

По ссылке
сказано следующее:

ARP Ping

The fastest way to discover hosts on a local ethernet network is to use the ARP Ping method:

>>> ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"), timeout=2)

Есть ли разница?

Там же по ссылке, кстати, предлагается использовать команду arping("192.168.1.0/24"), вместо той, что выше. Только не понял, как ее вывод перегнать в словарь. Если вернуть результат выполнения функции в переменную, то айпишники и макадреса внутри элементов видно, но обратиться к ним не получается.

2. Почему итоговая программа выдает всегда разное количество адресов устройств в сети? У меня к вай-фаю подключены всякие телефоны, телевизоры, камеры и все они находятся редко. Обычно сам ноут, роутер и 1-2 других устройств.

1. Почему передаем адрес первого узла сети. Ну, логично же, что мы сканируем всю сеть, то есть все ip адреса, а следовательно, нужно начать с самого первого. Но, я немного поэкспериментировал и, если не ошибаюсь, передать можно просто локальный адрес и маску. А scapy сам прошерстит нужный диапазон.

2. srp и arping по большому счету, наверное ничем. Что от одного, что от другого, ответы одинаковые.

screenshot5.png


3. По поводу доступа к элементам. Обратите внимание, что прилетает в ответ кортеж из двух частей. То есть, чтобы обратиться к одной из них, надо указать индекс. Соответственно, пишем:

screenshot2.png


И указываем то, что вам нужно получить.

Ответ состоит также из двух частей. То есть отвеченных адресов и не отвеченных. Потому d и n. Можно убрать лишнюю переменную и записать так:

Python:
import scapy.all as sc

d = sc.arping("192.168.42.1/24", verbose=False)[0]


for i in d:
    print(i[1].hwsrc)

screenshot3.png


Соответственно, если вы наберете вместо .hwsrc .show() вы увидите, что можно еще оттуда вытащить. Ну или можно так глянуть, распечатав элемент. А можно без цикла, вот так:

Python:
import scapy.all as sc

d = sc.arping("192.168.42.1/24", verbose=False)[0]
print(d[0][1].hwsrc)

4. Насчет разного количества устройства в сети, точно не знаю. Тут могу только предположить. Уже вроде где-то натыкался на такой вопрос, что сканер не видит мобильные устройства. Так вот, скорее всего так происходит потому, что телефоны и прочие мобильные устройства находятся в сети не постоянно, а периодически делают запросы на обновление. А потому, подключение тоже может быть не постоянным. Возможно, поэтому.
 
Последнее редактирование:
  • Нравится
Реакции: Игнатпитон

zvepb

Green Team
04.04.2020
146
125
1. Почему передаем адрес первого узла сети. Ну, логично же, что мы сканируем всю сеть, то есть все ip адреса, а следовательно, нужно начать с самого первого. Но, я немного поэкспериментировал и, если не ошибаюсь, передать можно просто локальный адрес и маску. А scapy сам прошерстит нужный диапазон.

2. srp и arping по большому счету, наверное ничем. Что от одного, что от другого, ответы одинаковые.

Посмотреть вложение 60583

3. По поводу доступа к элементам. Обратите внимание, что прилетает в ответ кортеж из двух частей. То есть, чтобы обратиться к одной из них, надо указать индекс. Соответственно, пишем:

Посмотреть вложение 60580

И указываем то, что вам нужно получить.

Ответ состоит также из двух частей. То есть отвеченных адресов и не отвеченных. Потому d и n. Можно убрать лишнюю переменную и записать так:

Python:
import scapy.all as sc

d = sc.arping("192.168.42.1/24", verbose=False)[0]


for i in d:
    print(i[1].hwsrc)

Посмотреть вложение 60581

Соответственно, если вы наберете вместо .hwsrc .show() вы увидите, что можно еще оттуда вытащить. Ну или можно так глянуть, распечатав элемент. А можно без цикла, вот так:

Python:
import scapy.all as sc

d = sc.arping("192.168.42.1/24", verbose=False)[0]
print(d[0][1].hwsrc)

4. Насчет разного количества устройства в сети, точно не знаю. Тут могу только предположить. Уже вроде где-то натыкался на такой вопрос, что сканер не видит мобильные устройства. Так вот, скорее всего так происходит потому, что телефоны и прочие мобильные устройства находятся в сети не постоянно, а периодически делают запросы на обновление. А потому, подключение тоже может быть не постоянным. Возможно, поэтому.
По поводу телефонов вроде когда то тест делал. Если ты по кабелю подключён то мобилки с вай фай ты не увидишь. А вот с ноута на вафле трубки тоже сканятся по-моему.
 
  • Нравится
Реакции: Игнатпитон

Johan Van

Green Team
13.06.2020
153
280
По поводу телефонов вроде когда то тест делал. Если ты по кабелю подключён то мобилки с вай фай ты не увидишь. А вот с ноута на вафле трубки тоже сканятся по-моему.

У меня вафли нет, к сожалению. Вернее есть ноут. Да и роутер есть. Руки не доходят потестировать ))
 
17.06.2022
6
0
Спасибо за ответы и за статью в целом.
Загадку wi-fi устройств так и не разгадал. Пробовал на телефоне включать ютуб и при этом запускать сканер - не помогло, все равно телефон не всегда находится. Более того, иногда сканер не получает ответа от ноута, на котором запускается, иногда от шлюза. Если verbose отключить, то видно, что запросы отправляются, а ответы не приходят.

Функцию получения IP сделал по советам ниже и гугла вцелом:
Код:
def local_ipv4():
    return gethostbyname(gethostname())

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

Johan Van

Green Team
13.06.2020
153
280
Спасибо за ответы и за статью в целом.
Загадку wi-fi устройств так и не разгадал. Пробовал на телефоне включать ютуб и при этом запускать сканер - не помогло, все равно телефон не всегда находится. Более того, иногда сканер не получает ответа от ноута, на котором запускается, иногда от шлюза. Если verbose отключить, то видно, что запросы отправляются, а ответы не приходят.

Функцию получения IP сделал по советам ниже и гугла вцелом:
Код:
def local_ipv4():
    return gethostbyname(gethostname())

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

Ну, так то оно так, вот только вы получаете не адрес сетевого интерфейса, а адрес локальной петли, которая называется "localhost". А вам нужно получить ip вида 192.168.11.10, например. Так что, тот код, что приведен в статье, он работает и работает нормально. В комментах не было спора из-за того, что код не рабочий )) Там другие моменты были ))

UPD: Тут штука в чем, с тем кодом, что приведен у вас. Он правильный и каноничный, если так можно сказать. Но он начинает вести себя странно, когда у вас несколько сетевых интерфейсов или есть работающие интерфейсы виртуальных машин. Так что, полагаться на него на 100% не стоит. Хотя, если работает, то почему нет. А так да. При отключении инета конечно он выдаст петлю ))
 
Последнее редактирование:
17.06.2022
6
0
Ну, так то оно так, вот только вы получаете не адрес сетевого интерфейса, а адрес локальной петли, которая называется "localhost". А вам нужно получить ip вида 192.168.11.10, например. Так что, тот код, что приведен в статье, он работает и работает нормально. В комментах не было спора из-за того, что код не рабочий )) Там другие моменты были ))

UPD: Тут штука в чем, с тем кодом, что приведен у вас. Он правильный и каноничный, если так можно сказать. Но он начинает вести себя странно, когда у вас несколько сетевых интерфейсов или есть работающие интерфейсы виртуальных машин. Так что, полагаться на него на 100% не стоит. Хотя, если работает, то почему нет. А так да. При отключении инета конечно он выдаст петлю ))
У меня было два интерфейса: wi-fi, virtualbox (оба активных и с айпишниками). Сначала он выдавал wi-fi'ный. После отключения wi-fi он выдавал virtualboxвский. Ну а после отключения последнего, уже выдавал 127.
Действительно меня беспокоит то, что непонятно, как эти функции выбирают какой айпишник выбрать из нескольких.

Но и по функции из примера, как я понял из обсуждения на SO, такой же вопрос. Как будто бы это не декларируемая возможность, а не штатное использование функции connect. И не понятно, как оно поведет себя в будущем.
 

Johan Van

Green Team
13.06.2020
153
280
У меня было два интерфейса: wi-fi, virtualbox (оба активных и с айпишниками). Сначала он выдавал wi-fi'ный. После отключения wi-fi он выдавал virtualboxвский. Ну а после отключения последнего, уже выдавал 127.
Действительно меня беспокоит то, что непонятно, как эти функции выбирают какой айпишник выбрать из нескольких.

Но и по функции из примера, как я понял из обсуждения на SO, такой же вопрос. Как будто бы это не декларируемая возможность, а не штатное использование функции connect. И не понятно, как оно поведет себя в будущем.

Все началось с того, что я просто нашел данный код на СО, и не особо разобрался как он работает. А у меня об этом спросили. Я не смог ответить толком. Вот в этом была и загвоздка. Тут все дело в том, что он пока работает. Можно изобрести разные костыли, но все они будут сводиться к сокетам, так или иначе. Либо вы их будете использовать напрямую, либо через библиотеки, которые внутри тоже используют сокеты. Мы и обсуждали, как можно обойти это ограничение сокетов. Просто потому, что кто его знает, как измениться питон в будущем. И сокеты могут просто перестать работать так, как от них ожидали ранее. А раз код который в статье работает по не задокументированным возможностям, значит они могут просто отвалиться. Вот в чем была загвоздка. Но, на данный момент, код с СО лучше всего определяет локальный IP.
 
  • Нравится
Реакции: Игнатпитон
Мы в соцсетях: