Получение IP -, MAC –адресов, имени сетевого интерфейса с помощью Python

Получение IP -, MAC –адресов, имени сетевого интерфейса с помощью Python, image #1

Порою возникают ситуации, когда необходимо использовать в скрипте Python IP-адрес используемый активной сетевой картой, которая смотрит в Интернет, узнать MAC-адрес этой карты и имя сетевого соединения. К сожалению, функций из коробки пока что не наблюдается. Есть сторонние модули, которые позволяют узнать MAC-адрес, например getmac, но в качестве параметров в них нужно также передавать или IP-адрес, или имя соединения. Но, что, если их нужно определять программно и вводить вручную не вариант?

Я нашел для себя решение, которое работает, но требует тестирования на большом количестве систем. Хотя, думаю, что на большинстве ОС семейства Windows или Linux оно будет работать.

Импорт библиотек

В данном решении не требуется устанавливать сторонние библиотеки. Необходимо лишь импортировать в скрип те, что нужны для его работы. Выполним их импорт:

from platform import system
from re import sub
from subprocess import check_output
from socket import socket, AF_INET, SOCK_DGRAM

Получение IP-адреса активной сетевой карты

Уже очень давно, около 15 лет назад на Stack Overflow был дан ответ по поводу получения «основного», имеющего маршрут по умолчанию, IP-адреса. Как описывает его автор скрипта, он работает под всеми основными ОС: Windows, Linux, OSX. Вот ссылка на данный пост.

Несмотря на то, что скрипту уже довольно много лет, он работает до сих пор. Потому, вместо изобретения велосипеда я использую его, за неимением лучшего. Тем более что он ни разу не давал сбоев. Вот сам скрипт:

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

Теперь, когда мы определились с тем, каким способом будем получать IP-адрес, приступим к написанию скрипта для получения IPv6-, MAC- адресов, а также имени сетевого интерфейса.

Получение информации об активном сетевом интерфейсе

Создадим класс NetInfo,который при инициализации будет получать необходимые данные в зависимости от операционной системы. Здесь мы определяем платформу с помощью модуля system библиотеки platform и в зависимости от этого запускаем тот или иной скрипт.

class NetInfo:
def __init__(self):
self.ipv4 = self.local()
self.platform = system()
self.mac = None
self.iface = None
self.ipv6 = None
if self.platform == "Windows":
self.mac_iface_win()
elif self.platform == "Linux":
self.mac_iface_lin()
else:
exit(0)
else:
exit(0)

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

@staticmethod
def local():
st = socket(AF_INET, SOCK_DGRAM)
try:
st.connect(('10.255.255.255', 1))
ip = st.getsockname()[0]
except OSError:
ip = '127.0.0.1'
finally:
st.close()
return ip

Напишем функцию mac_iface_win(self) в которой выполним получение нужных нам параметров. Для этого мы будем использовать возможности командной строки Windows, с частности инструмент командной стоки wmic. В частности будем использовать псевдоним NICCONFIG, который используется для управления сетевыми адаптерами. Отфильтруем только активные сетевые адаптеры. А их может быть в системе несколько, включая виртуальные: IPEnabled=true . После этого получим MAC – и IP – адреса используя GET MACAddress, IPAddress /FORMAT:csv, с указанием вывода полученных значений в формате csv для того, чтобы нам было проще их распарсить.

Вот полный вид данной команды:

wmic NICCONFIG WHERE IPEnabled=true GET MACAddress, IPAddress /FORMAT:csv

После того, как мы получим список активных сетевых адаптеров, поитерируемся по нему в цикле и проверим, есть ли в данном списке адаптер, IP-адрес которого равен полученному ранее локальному адресу. Если есть, забираем MAC-адрес, а также IPv6 адрес, если он не отключен в системе.

После того, как мы получим необходимые данные, выполним команду getmac /FO csv /NH /V с помощью которой получим список сетевых интерфейсов. Также в цикле проитерируемся по нему и будем проверять, есть ли уже полученный MAC-адрес в строке с параметрами интерфейса. Если есть, забираем название сетевого интерфейса.

def mac_iface_win(self):
adapter_lst = check_output("wmic NICCONFIG WHERE IPEnabled=true GET MACAddress, "
"IPAddress /FORMAT:csv", shell=False).decode().strip().splitlines()
for adapter in adapter_lst:
if adapter.strip():
node, ipaddr, mac = adapter.split(",")
ipaddr = sub("[{}]", "", ipaddr).split(";")
if ipaddr[0] == self.ipv4:
self.mac = mac.upper()
try:
self.ipv6 = ipaddr[1]
except IndexError:
pass
if self.mac:
interface_all = check_output('getmac /FO csv /NH /V', shell=False).decode('cp866').splitlines()
for line in interface_all:
if self.mac.upper().replace(":", "-") in line:
self.iface = line.split(",")[0].replace('"', '')
break

Если в предыдущей функции мы получили данные для сетевого интерфейса в ОС Windows, то следует также написать аналогичную функцию и для Linux. Поэтому создадим функцию mac_iface_lin(self). В ней кода будет поменьше, так как в командах Linux содержится больше информации в одном месте и ее легче распарсить. Команда, которую мы будем использовать выглядит следующим образом:

ip -h -br a | grep UP

Здесь мы получим название сетевого интерфейса и IPv6-адрес. В Linux данный адрес можно получить, даже если он отключен в настройках адаптера.

После этого выполним похожую команду, но уже отфильтруем из ее вывода MAC-адрес:

ip a | grep ether | gawk '{print $2}'

Осталось только свести написанный код, если вы этого еще не сделали воедино.

def mac_iface_lin(self):
com_run = check_output('ip -h -br a | grep UP', shell=True).decode().split()
self.iface = com_run[0].strip()
self.ipv6 = com_run[3].strip().split("/")[0]
self.mac = check_output("ip a | grep ether | gawk '{print $2}'", shell=True).decode().strip().upper()

Итак, продолжим. Полный код скрипта выглядит следующим образом:

from platform import system
from re import sub
from subprocess import check_output
from socket import socket, AF_INET, SOCK_DGRAM
class NetInfo:
def __init__(self):
self.ipv4 = self.local()
self.platform = system()
self.mac = None
self.iface = None
self.ipv6 = None
if self.platform == "Windows":
self.mac_iface_win()
elif self.platform == "Linux":
self.mac_iface_lin()
else:
exit(0)
@staticmethod
def local():
st = socket(AF_INET, SOCK_DGRAM)
try:
st.connect(('10.255.255.255', 1))
ip = st.getsockname()[0]
except OSError:
ip = '127.0.0.1'
finally:
st.close()
return ip
def mac_iface_win(self):
adapter_lst = check_output("wmic NICCONFIG WHERE IPEnabled=true GET MACAddress, "
"IPAddress /FORMAT:csv", shell=False).decode().strip().splitlines()
for adapter in adapter_lst:
if adapter.strip():
node, ipaddr, mac = adapter.split(",")
ipaddr = sub("[{}]", "", ipaddr).split(";")
if ipaddr[0] == self.ipv4:
self.mac = mac.upper()
try:
self.ipv6 = ipaddr[1]
except IndexError:
pass
if self.mac:
interface_all = check_output('getmac /FO csv /NH /V', shell=False).decode('cp866').splitlines()
for line in interface_all:
if self.mac.upper().replace(":", "-") in line:
self.iface = line.split(",")[0].replace('"', '')
break
def mac_iface_lin(self):
com_run = check_output('ip -h -br a | grep UP', shell=True).decode().split()
self.iface = com_run[0].strip()
self.ipv6 = com_run[3].strip().split("/")[0]
self.mac = check_output("ip a | grep ether | gawk '{print $2}'", shell=True).decode().strip().upper()

Теперь необходимо протестировать его в операционных системах. В данном случае у меня доступны две системы: Windows 10 и Linux Mint.

Создадим в данном скрипте вызов нашего класса и выведем в терминал полученные параметры:

name = NetInfo().iface
ip_ = NetInfo().ipv4
ip_6 = NetInfo().ipv6
mac_ = NetInfo().mac
print(f'{name} | {ip_} | {ip_6} | {mac_}')

Для начала, запустим в ОС Windows:

Получение IP -, MAC –адресов, имени сетевого интерфейса с помощью Python, image #2

А теперь то же самое в Linux Mint:

Получение IP -, MAC –адресов, имени сетевого интерфейса с помощью Python, image #3

Как видим, скрипт справляется со своей работой. Для чего он может пригодиться? Ну, например, для автоматической установки активного сетевого интерфейса по умолчанию в Scapy при прослушивании пакетов с активного сетевого интерфейса. Но о Scapy поговорим немного позже.

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

Наши тг каналы, подпишись!

#python #программирование #разработка #скрипт #linux #windows

19 views·1 share