[2.7] bpo-32502: Discard 64-bit (and other invalid) hardware addresses (GH-9125)

(cherry picked from commit 6b273f7f4056f8276f61a97c789d6bb4425e653c)

Co-authored-by: Bo Bayles <bbayles@gmail.com>
diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index 3749564..6cd2c39 100644
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -287,6 +287,39 @@
         node2 = uuid.getnode()
         self.assertEqual(node1, node2, '%012x != %012x' % (node1, node2))
 
+    # bpo-32502: UUID1 requires a 48-bit identifier, but hardware identifiers
+    # need not necessarily be 48 bits (e.g., EUI-64).
+    def test_uuid1_eui64(self):
+        # Confirm that uuid.getnode ignores hardware addresses larger than 48
+        # bits. Mock out each platform's *_getnode helper functions to return
+        # something just larger than 48 bits to test. This will cause
+        # uuid.getnode to fall back on uuid._random_getnode, which will
+        # generate a valid value.
+        too_large_getter = lambda: 1 << 48
+
+        uuid_real__node = uuid._node
+        uuid_real__NODE_GETTERS_WIN32 = uuid._NODE_GETTERS_WIN32
+        uuid_real__NODE_GETTERS_UNIX = uuid._NODE_GETTERS_UNIX
+        uuid._node = None
+        uuid._NODE_GETTERS_WIN32 = [too_large_getter]
+        uuid._NODE_GETTERS_UNIX = [too_large_getter]
+        try:
+            node = uuid.getnode()
+        finally:
+            uuid._node = uuid_real__node
+            uuid._NODE_GETTERS_WIN32 = uuid_real__NODE_GETTERS_WIN32
+            uuid._NODE_GETTERS_UNIX = uuid_real__NODE_GETTERS_UNIX
+
+        self.assertTrue(0 < node < (1 << 48), '%012x' % node)
+
+        # Confirm that uuid1 can use the generated node, i.e., the that
+        # uuid.getnode fell back on uuid._random_getnode() rather than using
+        # the value from too_large_getter above.
+        try:
+            uuid.uuid1(node=node)
+        except ValueError as e:
+            self.fail('uuid1 was given an invalid node ID')
+
     @unittest.skipUnless(importable('ctypes'), 'requires ctypes')
     def test_uuid1(self):
         equal = self.assertEqual
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 973013c..80d33c0 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -522,6 +522,11 @@
 
 _node = None
 
+_NODE_GETTERS_WIN32 = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
+
+_NODE_GETTERS_UNIX = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
+                      _lanscan_getnode, _netstat_getnode]
+
 def getnode():
     """Get the hardware address as a 48-bit positive integer.
 
@@ -537,18 +542,19 @@
 
     import sys
     if sys.platform == 'win32':
-        getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
+        getters = _NODE_GETTERS_WIN32
     else:
-        getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode,
-                   _lanscan_getnode, _netstat_getnode]
+        getters = _NODE_GETTERS_UNIX
 
     for getter in getters + [_random_getnode]:
         try:
             _node = getter()
         except:
             continue
-        if _node is not None:
+        if (_node is not None) and (0 <= _node < (1 << 48)):
             return _node
+    assert False, '_random_getnode() returned invalid value: {}'.format(_node)
+
 
 _last_timestamp = None