Index: Doc/library/uuid.rst =================================================================== --- Doc/library/uuid.rst (revision 79908) +++ Doc/library/uuid.rst (working copy) @@ -117,10 +117,11 @@ 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. "Hardware address" - means the MAC address of a network interface, and on a machine with multiple - network interfaces the MAC address of any one of them may be returned. + attempts to obtain the hardware address fail, we choose a random 47-bit number + with its eighth bit set to 1 as recommended in RFC 4122, section 4.5. + "Hardware address" means the MAC address of a network interface, and on a + machine with multiple network interfaces the MAC address of any one of them + may be returned. .. index:: single: getnode Index: Lib/uuid.py =================================================================== --- Lib/uuid.py (revision 79908) +++ Lib/uuid.py (working copy) @@ -445,21 +445,35 @@ pass def _unixdll_getnode(): - """Get the hardware address on Unix using ctypes.""" + """Get the hardware address on Unix using a UUID generated by a ctypes + library call. If the UUID is not RFC_4122 version 1, return None.""" + if _uuid_generate_time is None: + return None # Issue 1481 _buffer = ctypes.create_string_buffer(16) _uuid_generate_time(_buffer) - return UUID(bytes=bytes_(_buffer.raw)).node + u = UUID(bytes=bytes_(_buffer.raw)) + if u.variant != RFC_4122 or u.version != 1: + return None + return u.node def _windll_getnode(): - """Get the hardware address on Windows using ctypes.""" + """Get the hardware address on Windows using a UUID generated by a ctypes + library call. If the UUID is not RFC_4122 version 1, return None.""" _buffer = ctypes.create_string_buffer(16) if _UuidCreate(_buffer) == 0: - return UUID(bytes=bytes_(_buffer.raw)).node + u = UUID(bytes=bytes_(_buffer.raw)) + if u.variant != RFC_4122 or u.version != 1: + return None + return u.node + else: + return None def _random_getnode(): - """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" + """Get a version 1 random 47-bit node ID, as suggested by RFC 4122, + section 4.5. + """ import random - return random.randrange(0, 1<<48) | 0x010000000000 + return random.randrange(0, 1<<47) | 0x010000000000 _node = None @@ -468,8 +482,8 @@ 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. + choose a version 1 random 47-bit node ID, as recommended by RFC 4122, + section 4.5. """ global _node Index: Lib/test/test_uuid.py =================================================================== --- Lib/test/test_uuid.py (revision 79909) +++ Lib/test/test_uuid.py (working copy) @@ -292,15 +292,9 @@ badtype(lambda: setattr(u, 'node', 0)) def check_node(self, node, source): - individual_group_bit = (node >> 40) & 1 - universal_local_bit = (node >> 40) & 2 - message = "%012x doesn't look like a real MAC address" % node - self.assertEqual(individual_group_bit, 0, message) - self.assertEqual(universal_local_bit, 0, message) - self.assertNotEqual(node, 0, message) - self.assertNotEqual(node, 0xffffffffffff, message) - self.assertTrue(0 <= node, message) - self.assertTrue(node < (1 << 48), message) + message = "%012x is not an RFC 4122 node ID" % node + self.assertTrue(0 < node, message) + self.assertTrue(node < 0xffffffffffff, message) TestUUID.source2node[source] = node if TestUUID.last_node: @@ -318,10 +312,6 @@ def test_ifconfig_getnode(self): import sys - print(""" WARNING: uuid._ifconfig_getnode is unreliable on many platforms. - It is disabled until the code and/or test can be fixed properly.""", file=sys.__stdout__) - return - import os if os.name == 'posix': node = uuid._ifconfig_getnode() @@ -341,30 +331,28 @@ def test_random_getnode(self): node = uuid._random_getnode() - self.assertTrue(0 <= node) - self.assertTrue(node < (1 <<48)) + self.assertTrue(0 < node) + # Least significant bit of first octet must be set. + self.assertTrue(node & 0x010000000000) + self.assertTrue(node < (1 << 47)) def test_unixdll_getnode(self): import sys - print(""" WARNING: uuid._unixdll_getnode is unreliable on many platforms. - It is disabled until the code and/or test can be fixed properly.""", file=sys.__stdout__) - return - import os if importable('ctypes') and os.name == 'posix': - self.check_node(uuid._unixdll_getnode(), 'unixdll') + node = uuid._unixdll_getnode() + if node is not None: + self.check_node(node, 'unixdll') def test_windll_getnode(self): import os if importable('ctypes') and os.name == 'nt': - self.check_node(uuid._windll_getnode(), 'windll') + node = uuid._windll_getnode() + if node is not None: + self.check_node(node, 'windll') def test_getnode(self): import sys - print(""" WARNING: uuid.getnode is unreliable on many platforms. - It is disabled until the code and/or test can be fixed properly.""", file=sys.__stdout__) - return - node1 = uuid.getnode() self.check_node(node1, "getnode1")