summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_uuid.py52
-rw-r--r--Lib/uuid.py72
2 files changed, 93 insertions, 31 deletions
diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index 3b013a8ef5..27fc56d226 100644
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -679,6 +679,58 @@ class TestUUIDWithExtModule(BaseTestUUID, unittest.TestCase):
class BaseTestInternals:
_uuid = py_uuid
+ def check_parse_mac(self, aix):
+ if not aix:
+ patch = mock.patch.multiple(self.uuid,
+ _MAC_DELIM=b':',
+ _MAC_OMITS_LEADING_ZEROES=False)
+ else:
+ patch = mock.patch.multiple(self.uuid,
+ _MAC_DELIM=b'.',
+ _MAC_OMITS_LEADING_ZEROES=True)
+
+ with patch:
+ # Valid MAC addresses
+ if not aix:
+ tests = (
+ (b'52:54:00:9d:0e:67', 0x5254009d0e67),
+ (b'12:34:56:78:90:ab', 0x1234567890ab),
+ )
+ else:
+ # AIX format
+ tests = (
+ (b'fe.ad.c.1.23.4', 0xfead0c012304),
+ )
+ for mac, expected in tests:
+ self.assertEqual(self.uuid._parse_mac(mac), expected)
+
+ # Invalid MAC addresses
+ for mac in (
+ b'',
+ # IPv6 addresses with same length than valid MAC address
+ # (17 characters)
+ b'fe80::5054:ff:fe9',
+ b'123:2:3:4:5:6:7:8',
+ # empty 5rd field
+ b'52:54:00:9d::67',
+ # only 5 fields instead of 6
+ b'52:54:00:9d:0e'
+ # invalid character 'x'
+ b'52:54:00:9d:0e:6x'
+ # dash separator
+ b'52-54-00-9d-0e-67',
+ ):
+ if aix:
+ mac = mac.replace(b':', b'.')
+ with self.subTest(mac=mac):
+ self.assertIsNone(self.uuid._parse_mac(mac))
+
+ def test_parse_mac(self):
+ self.check_parse_mac(False)
+
+ def test_parse_mac_aix(self):
+ self.check_parse_mac(True)
+
def test_find_under_heading(self):
data = '''\
Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Coll
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 3b3abc2a45..2799c75ba6 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -434,6 +434,34 @@ def _find_mac_near_keyword(command, args, keywords, get_word_index):
return first_local_mac or None
+def _parse_mac(word):
+ # 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' or '123:2:3:4:5:6:7:8').
+ #
+ # Virtual interfaces, such as those provided by VPNs, do not have a
+ # colon-delimited MAC address as expected, but a 16-byte HWAddr separated
+ # by dashes. These should be ignored in favor of a real MAC address
+ parts = word.split(_MAC_DELIM)
+ if len(parts) != 6:
+ return
+ if _MAC_OMITS_LEADING_ZEROES:
+ # (Only) on AIX the macaddr value given is not prefixed by 0, e.g.
+ # en0 1500 link#2 fa.bc.de.f7.62.4 110854824 0 160133733 0 0
+ # not
+ # en0 1500 link#2 fa.bc.de.f7.62.04 110854824 0 160133733 0 0
+ if not all(1 <= len(part) <= 2 for part in parts):
+ return
+ hexstr = b''.join(part.rjust(2, b'0') for part in parts)
+ else:
+ if not all(len(part) == 2 for part in parts):
+ return
+ hexstr = b''.join(parts)
+ try:
+ return int(hexstr, 16)
+ except ValueError:
+ return
+
+
def _find_mac_under_heading(command, args, heading):
"""Looks for a MAC address under a heading in a command's output.
@@ -453,39 +481,21 @@ def _find_mac_under_heading(command, args, heading):
first_local_mac = None
for line in stdout:
+ words = line.rstrip().split()
try:
- words = line.rstrip().split()
word = words[column_index]
- # 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.
- # en0 1500 link#2 fa.bc.de.f7.62.4 110854824 0 160133733 0 0
- # not
- # en0 1500 link#2 fa.bc.de.f7.62.04 110854824 0 160133733 0 0
- parts = word.split(_MAC_DELIM)
- if len(parts) == 6 and all(0 < len(p) <= 2 for p in parts):
- hexstr = b''.join(p.rjust(2, b'0') for p in parts)
- mac = int(hexstr, 16)
- else:
- continue
- else:
- continue
- except (ValueError, IndexError):
- # Virtual interfaces, such as those provided by
- # VPNs, do not have a colon-delimited MAC address
- # as expected, but a 16-byte HWAddr separated by
- # dashes. These should be ignored in favor of a
- # real MAC address
- pass
- else:
- if _is_universal(mac):
- return mac
- first_local_mac = first_local_mac or mac
- return first_local_mac or None
+ except IndexError:
+ continue
+
+ mac = _parse_mac(word)
+ if mac is None:
+ continue
+ if _is_universal(mac):
+ return mac
+ if first_local_mac is None:
+ first_local_mac = mac
+
+ return first_local_mac
# The following functions call external programs to 'get' a macaddr value to