New submission from Michael Felt:

Short version:

the five routines get_node() calls to get the MAC address either fail by 
definition, or is wrong.

The one routine that works - is wrong because it returns the same value 
regardless of the system it runs on - wrong character is used to identify the 
string containing the mac address.

Recommended: correct and call the one routine that can work for AIX.

Details (using Python2.7 as template, applies to all Python3 versions as well)

  +511  def getnode():
  +512      """Get the hardware address as a 48-bit positive integer.
  +513
  +514      The first time this runs, it may launch a separate program, which 
could
  +515      be quite slow.  If all attempts to obtain the hardware address 
fail, we
  +516      choose a random 48-bit number with its eighth bit set to 1 as 
recommended
  +517      in RFC 4122.
  +518      """
  +519
  +520      global _node
  +521      if _node is not None:
  +522          return _node
  +523
  +524      import sys
  +525      if sys.platform == 'win32':
  +526          getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
  +527      else:
  +528          getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
  +529                     _lanscan_getnode, _netstat_getnode]
  +530
  +531      for getter in getters + [_random_getnode]:
  +532          try:
  +533              _node = getter()
  +534          except:
  +535              continue
  +536          if _node is not None:
  +537              return _node
  +538
  +539  _last_timestamp = None

unixdll_getnode depends on finding uuid_generate_time in either libuuid, libc, 
or None

On a default install of AIX:
find_library("uuid") returns None
nm -Ae /usr/lib/*.a | grep uuid_generate # does not return a function name, no 
.a archives are stripped

  +339  def _ifconfig_getnode():
  +340      """Get the hardware address on Unix by running ifconfig."""
  +341      # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all 
Unixes.
  +342      for args in ('', '-a', '-av'):
  +343          mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda 
i: i+1)
  +344          if mac:
  +345              return mac

Does not work on AIX - why call it?

  +347  def _arp_getnode():
  +348      """Get the hardware address on Unix by running arp."""
  +349      import os, socket
  +350      try:
  +351          ip_addr = socket.gethostbyname(socket.gethostname())
  +352      except EnvironmentError:
  +353          return None
  +354
  +355      # Try getting the MAC addr from arp based on our IP address 
(Solaris).
  +356      return _find_mac('arp', '-an', [ip_addr], lambda i: -1)

Does not work on one Linux system I tried
root@x066:~# arp -an 192.168.129.66
arp: in 2 entries no match found.

on AIX:
root@x064:[/data/prj/aixtools/python/python-2.7.12.1]arp -an 192.168.129.64
  ? (192.168.129.254) at XX:YY:11:aa:ZZ:ca [ethernet] stored in bucket 27
...
Nothing for it's own IP address
again, why call it.

 +358  def _lanscan_getnode():
  +359      """Get the hardware address on Unix by running lanscan."""
  +360      # This might work on HP-UX.
  +361      return _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)

Again, from comments - looks like it should work on HP-UX, so why call it on AIX
(linux was probably solved via one of the first two, so no impact there)

So, finally, after 4 guaranteed failures the following is called:

 +363  def _netstat_getnode():
  +364      """Get the hardware address on Unix by running netstat."""
  +365      # This might work on AIX, Tru64 UNIX and presumably on IRIX.
  +366      try:
  +367          pipe = _popen('netstat', '-ia')
  +368          if not pipe:
  +369              return
  +370          with pipe:
  +371              words = pipe.readline().rstrip().split()
  +372              try:
  +373                  i = words.index('Address')
  +374              except ValueError:
  +375                  return
  +376              for line in pipe:
  +377                  try:
  +378                      words = line.rstrip().split()
  +379                      word = words[i]
  +380                      if len(word) == 17 and word.count(':') == 5:
  +381                          mac = int(word.replace(':', ''), 16)
  +382                          if mac:
  +383                              return mac
  +384                  except (ValueError, IndexError):
  +385                      pass
  +386      except OSError:
  +387          pass

For AIX - lines 380 and 381 do work - except the answer is ALWAYS the same:

See host x071:
michael@x071:[/usr/lib]netstat -ia
Name  Mtu   Network     Address            Ipkts Ierrs    Opkts Oerrs  Coll
en0   1500  link#2      fa.d1.8c.f7.62.4 553220627     0 181051589     0     0
                        01:00:5e:00:00:01
en0   1500  192.168.129 x071             553220627     0 181051589     0     0
                        224.0.0.1
en1   65390 link#3      fa.d1.8c.f7.62.5  8004448     0 11655497     0     0
                        01:00:5e:00:00:01
en1   65390 192.168.2   mail.aixtools.co  8004448     0 11655497     0     0
                        224.0.0.1
lo0   16896 link#1                         197583     0   197583     0     0
lo0   16896 127         loopback           197583     0   197583     0     0
                        224.0.0.1
lo0   16896 loopback                       197583     0   197583     0     0
                        ff01::1
                        ff02::1:ff00:1

See host x064:
root@x064:[/data/prj/aixtools/python/python-2.7.12.1]netstat -ia
Name  Mtu   Network     Address            Ipkts Ierrs    Opkts Oerrs  Coll
en0   1500  link#2      0.21.5e.a3.c7.44    192718     0    93218     0     0
                        01:00:5e:00:00:01
en0   1500  192.168.129 x064                192718     0    93218     0     0
                        224.0.0.1
lo0   16896 link#1                             231     0      240     0     0
lo0   16896 127         loopback               231     0      240     0     0
                        224.0.0.1
lo0   16896 ::1                                231     0      240     0     0
                        ff01::1
                        ff02::1:ff00:1
                        ff02::1

The answer found is always
01:00:5e:00:00:01

Where, for AIX at least, line 380 and line 381 should be looking at the 
character '.', not ':'
which is valid for linux, and perhaps others.

So,

two corrections suggested:

line 380 + 381 (or as appropriate per Python version) - modify:

  +378                      words = line.rstrip().split()
  +379                      word = words[i]
  +380                      if sys.platform.startswith("aix"):
  +381                          str = "."
  +382                      else:
  +383                          str = ":"
  +384                      if len(word) == 17 and word.count(str) == 5:
  +385                          mac = int(word.replace(str, ''), 16)
  +386                          if mac:
  +387                              return mac

NOTE: if str need to be a chr, then use that instead.

But much earlier in program logic - modify:

  +525      if sys.platform == 'win32':
  +526          getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
  +527      else:
  +528          getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
  +529                     _lanscan_getnode, _netstat_getnode]

to

  +529      if sys.platform == 'win32':
  +530          getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
  +531      elif sys.platform.startswith("aix"):
  +532          getters = [_netstat_getnode]
  +533      else:
  +534          getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
  +535                     _lanscan_getnode, _netstat_getnode]

----------
components: Library (Lib)
messages: 274909
nosy: Michael.Felt
priority: normal
severity: normal
status: open
title: core logic of uuid.getnode() is broken for AIX - all versions
type: behavior
versions: Python 2.7, Python 3.3, Python 3.4, Python 3.5, Python 3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue28009>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to