diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index b76c60e1ce2..3b013a8ef5e 100644
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -23,6 +23,12 @@ def importable(name):
return False
+def mock_get_command_stdout(data):
+ def get_command_stdout(command, args):
+ return io.BytesIO(data.encode())
+ return get_command_stdout
+
+
class BaseTestUUID:
uuid = None
@@ -673,7 +679,6 @@ class TestUUIDWithExtModule(BaseTestUUID, unittest.TestCase):
class BaseTestInternals:
_uuid = py_uuid
-
def test_find_under_heading(self):
data = '''\
Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Coll
@@ -685,15 +690,12 @@ en0 1500 192.168.90 x071 1714807956 0 711348489 0 0
224.0.0.1
'''
- def mock_get_command_stdout(command, args):
- return io.BytesIO(data.encode())
-
# The above data is from AIX - with '.' as _MAC_DELIM and strings
# shorter than 17 bytes (no leading 0). (_MAC_OMITS_LEADING_ZEROES=True)
with mock.patch.multiple(self.uuid,
_MAC_DELIM=b'.',
_MAC_OMITS_LEADING_ZEROES=True,
- _get_command_stdout=mock_get_command_stdout):
+ _get_command_stdout=mock_get_command_stdout(data)):
mac = self.uuid._find_mac_under_heading(
command='netstat',
args='-ian',
@@ -702,6 +704,43 @@ en0 1500 192.168.90 x071 1714807956 0 711348489 0 0
self.assertEqual(mac, 0xfead0c012304)
+ def test_find_under_heading_ipv6(self):
+ # bpo-39991: IPv6 address "fe80::5054:ff:fe9" looks like a MAC address
+ # (same string length) but must be skipped
+ data = '''\
+Name Mtu Network Address Ipkts Ierrs Idrop Opkts Oerrs Coll
+vtnet 1500 52:54:00:9d:0e:67 10017 0 0 8174 0 0
+vtnet - fe80::%vtnet0 fe80::5054:ff:fe9 0 - - 4 - -
+vtnet - 192.168.122.0 192.168.122.45 8844 - - 8171 - -
+lo0 16384 lo0 260148 0 0 260148 0 0
+lo0 - ::1/128 ::1 193 - - 193 - -
+ ff01::1%lo0
+ ff02::2:2eb7:74fa
+ ff02::2:ff2e:b774
+ ff02::1%lo0
+ ff02::1:ff00:1%lo
+lo0 - fe80::%lo0/64 fe80::1%lo0 0 - - 0 - -
+ ff01::1%lo0
+ ff02::2:2eb7:74fa
+ ff02::2:ff2e:b774
+ ff02::1%lo0
+ ff02::1:ff00:1%lo
+lo0 - 127.0.0.0/8 127.0.0.1 259955 - - 259955 - -
+ 224.0.0.1
+'''
+
+ with mock.patch.multiple(self.uuid,
+ _MAC_DELIM=b':',
+ _MAC_OMITS_LEADING_ZEROES=False,
+ _get_command_stdout=mock_get_command_stdout(data)):
+ mac = self.uuid._find_mac_under_heading(
+ command='netstat',
+ args='-ian',
+ heading=b'Address',
+ )
+
+ self.assertEqual(mac, 0x5254009d0e67)
+
def test_find_mac_near_keyword(self):
# key and value are on the same line
data = '''
@@ -710,14 +749,11 @@ cscotun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab
'''
- def mock_get_command_stdout(command, args):
- return io.BytesIO(data.encode())
-
# The above data will only be parsed properly on non-AIX unixes.
with mock.patch.multiple(self.uuid,
_MAC_DELIM=b':',
_MAC_OMITS_LEADING_ZEROES=False,
- _get_command_stdout=mock_get_command_stdout):
+ _get_command_stdout=mock_get_command_stdout(data)):
mac = self.uuid._find_mac_near_keyword(
command='ifconfig',
args='',
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 224a766ff22..3b3abc2a455 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -456,7 +456,10 @@ def _find_mac_under_heading(command, args, heading):
try:
words = line.rstrip().split()
word = words[column_index]
- if len(word) == 17:
+ # Accept 'HH:HH:HH:HH:HH:HH' MAC address (ex: '52:54:00:9d:0e:67'),
+ # but reject IPv6 address (ex: 'fe80::5054:ff:fe9') detected
+ # by '::' pattern.
+ if len(word) == 17 and b'::' not in word:
mac = int(word.replace(_MAC_DELIM, b''), 16)
elif _MAC_OMITS_LEADING_ZEROES:
# (Only) on AIX the macaddr value given is not prefixed by 0, e.g.
diff --git a/Misc/NEWS.d/next/Library/2020-03-17-12-40-38.bpo-39991.hLPPs4.rst b/Misc/NEWS.d/next/Library/2020-03-17-12-40-38.bpo-39991.hLPPs4.rst
new file mode 100644
index 00000000000..ef5a9e4d673
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-03-17-12-40-38.bpo-39991.hLPPs4.rst
@@ -0,0 +1,2 @@
+:func:`uuid.getnode` now skips IPv6 addresses with the same string length
+than a MAC address (17 characters): only use MAC addresses.