получение mac-адреса

<p>мне нужен кроссплатформенный метод определения mac-адреса компьютера во время выполнения. для windows можно использовать модуль 'wmi', и единственный метод под linux, который я смог найти, - это запустить ifconfig и запустить регулярное выражение в выходных данных. мне не нравится использовать пакет, который работает только на одной ос, и анализ выходных данных другой программы выглядит не очень элегантно, не говоря уже о подверженности ошибкам. </p><p>кто-нибудь знает метод кросс-платформенный метод (windows и linux), чтобы получить mac-адрес? если нет, знает ли кто-нибудь более изящные методы, чем те, которые я перечислил выше?</p>

<p>python 2.5 включает в себя реализацию uuid, которой (по крайней мере, в одной версии) нужен mac-адрес. вы можете легко импортировать функцию поиска mac в свой собственный код:</p><pre><code>from uuid import getnode as get\_mac mac = get\_mac() </code></pre><p>возвращаемым значением является mac-адрес как 48-битное целое число.</p>

<p>чистое решение python для этой проблемы под linux, чтобы получить mac для определенного локального интерфейса, первоначально опубликованный в качестве комментария vishnubob и улучшенный беном макки в <a href="http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/">этот рецепт activestate</a> </p><pre><code>#!/usr/bin/python import fcntl, socket, struct def gethwaddr(ifname): s = socket.socket(socket.af\_inet, socket.sock\_dgram) info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15])) return ':'.join(['%02x' % ord(char) for char in info[18:24]]) print gethwaddr('eth0') </code></pre>

<p>netifaces - это хороший модуль для получения mac-адреса (и других адресов). он кроссплатформенный и имеет больше смысла, чем использование сокетов или uuid.</p><pre><code>>>> import netifaces >>> netifaces.interfaces() ['lo', 'eth0', 'tun2'] >>> netifaces.ifaddresses('eth0')[netifaces.af\_link] [{'addr': '08:00:27:50:f2:51', 'broadcast': 'ff:ff:ff:ff:ff:ff'}] </code></pre><hr><ul> <li><p> <a href="https://pypi.python.org/pypi/netifaces">расположение пипи</a> </p></li> <li><p> <a href="http://alastairs-place.net/projects/netifaces/">хорошее введение в netifaces</a> </p></li> </ul>

<p>еще одна вещь, на которую следует обратить внимание, это то, что <code>uuid.getnode()</code> может подделать mac-адрес, возвращая случайное 48-битное число, которое может не соответствовать ожидаемому. кроме того, нет явного указания на то, что mac-адрес был фальсифицирован, но вы можете обнаружить его, дважды вызвав функцию <code>getnode()</code> и проверив, меняется ли результат. если оба вызова возвращают одно и то же значение, у вас есть mac-адрес, в противном случае вы получаете поддельный адрес.</p><pre><code>>>> print uuid.getnode.\_\_doc\_\_ get the hardware address as a 48-bit positive integer. the first time this runs, it may launch a separate program, which could be quite slow. if all attempts to obtain the hardware address fail, we choose a random 48-bit number with its eighth bit set to 1 as recommended in rfc 4122. </code></pre>

<p>иногда у нас более одного сетевого интерфейса.</p><p>простой способ узнать mac-адрес определенного интерфейса:</p><pre><code>def getmac(interface): try: mac = open('/sys/class/net/'+interface+'/address').readline() except: mac = "00:00:00:00:00:00" return mac[0:17] </code></pre><p>вызвать метод просто</p><pre><code>mymac = getmac("wlan0") </code></pre>

<p>используя мой ответ отсюда: <a href="https://stackoverflow.com/a/18031868/2362361">https://stackoverflow.com/a/18031868/2362361</a> </p><p>было бы важно знать, для какого iface вы хотите mac, поскольку многие могут существовать (bluetooth, несколько сетевых карт и т.д.).</p><p>это делает работу, когда вы знаете ip-адрес iface, для которого вам нужен mac, используя <code>netifaces</code> (доступно в pypi):</p><pre><code>import netifaces as nif def mac\_for\_ip(ip): 'returns a list of macs for interfaces that have given ip, returns none if not found' for i in nif.interfaces(): addrs = nif.ifaddresses(i) try: if\_mac = addrs[nif.af\_link][0]['addr'] if\_ip = addrs[nif.af\_inet][0]['addr'] except indexerror, keyerror: #ignore ifaces that dont have mac or ip if\_mac = if\_ip = none if if\_ip == ip: return if\_mac return none </code></pre><p>тестирование:</p><pre><code>>>> mac\_for\_ip('169.254.90.191') '2c:41:38:0a:94:8b' </code></pre>

<p>обратите внимание, что вы можете создать свою собственную кроссплатформенную библиотеку в python, используя условный импорт. например.</p><pre><code>import platform if platform.system() == 'linux': import linuxmac mac\_address = linuxmac.get\_mac\_address() elif platform.system() == 'windows': # etc </code></pre><p>это позволит вам использовать системные вызовы os.s или библиотеки для конкретной платформы.</p>

<p>вы можете сделать это с помощью psutil, который является кроссплатформенным:</p><pre><code>import psutil mac\_addresses = [] nics = psutil.net\_if\_addrs() nics.pop('lo') # remove loopback since it doesnt have a real mac address for i in nics: for j in nics[i]: if j.family == 17: # af\_link mac\_addresses.append(j.address) </code></pre>

<p>для linux позвольте мне представить скрипт shell, который покажет mac-адрес и позволит изменить его (mac-сниффинг).</p><pre><code> ifconfig eth0 | grep hwaddr |cut -dh -f2|cut -d\ -f2 00:26:6c:df:c3:95 </code></pre><p>вырезать аргументы могут (я не эксперт) попробовать:</p><pre><code>ifconfig etho | grep hwaddr eth0 link encap:ethernet hwaddr 00:26:6c:df:c3:95 </code></pre><p>чтобы изменить mac, мы можем сделать:</p><pre><code>ifconfig eth0 down ifconfig eth0 hw ether 00:80:48:ba:d1:30 ifconfig eth0 up </code></pre><p>изменит mac-адрес на 00: 80: 48: ba: d1: 30 (временно восстановит реальный адрес после перезагрузки).</p>

<p>кроссплатформенный пакет <a href="https://github.com/ghostofgoes/getmac">getmac</a> будет работать для этого, если вы не возражаете против зависимости. работает с python 2.7+ и 3.4+. он будет пробовать много разных методов, пока не получит адрес или не вернет none.</p><pre class="lang-python prettyprint-override"><code>from getmac import get\_mac\_address eth\_mac = get\_mac\_address(interface="eth0") win\_mac = get\_mac\_address(interface="ethernet 3") ip\_mac = get\_mac\_address(ip="192.168.0.1") ip6\_mac = get\_mac\_address(ip6="::1") host\_mac = get\_mac\_address(hostname="localhost") updated\_mac = get\_mac\_address(ip="10.0.0.1", network\_request=true) </code></pre><p>отказ от ответственности: я являюсь автором пакета. </p><p>обновление (14 января 2019 г.): теперь пакет поддерживает только python 2.7+ и 3.4+. вы все еще можете использовать более старую версию пакета, если вам нужно работать со старым python (2.5, 2.6, 3.2, 3.3).</p>

<p>с другой стороны,</p><pre><code>import uuid mac\_id=(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff) </code></pre>

<p>я не знаю единого пути, но вот кое-что, что вы могли бы найти полезным:</p><p> <a href="http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451">http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451</a> </p><p>в этом случае я хотел бы заключить их в функцию, и в зависимости от ос он будет запускать правильную команду, анализировать при необходимости и возвращать только mac-адрес, отформатированный так, как вы хотите. конечно же, это все равно, за исключением того, что вам нужно сделать это только один раз, и он выглядит чище из основного кода.</p>