Skip to content

Commit c9409f7

Browse files
authored
Revert "bpo-32107 - Better merge of #4494 (#4576)" (#4593)
This reverts commit 9522a21.
1 parent 39f0bb5 commit c9409f7

File tree

3 files changed

+28
-93
lines changed

3 files changed

+28
-93
lines changed

Lib/test/test_uuid.py

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -512,69 +512,60 @@ def test_find_mac(self):
512512

513513
self.assertEqual(mac, 0x1234567890ab)
514514

515-
def check_node(self, node, requires=None, *, check_bit=True):
515+
def check_node(self, node, requires=None, network=False):
516516
if requires and node is None:
517517
self.skipTest('requires ' + requires)
518518
hex = '%012x' % node
519519
if support.verbose >= 2:
520520
print(hex, end=' ')
521-
# The MAC address will be universally administered (i.e. the second
522-
# least significant bit of the first octet must be unset) for any
523-
# physical interface, such as an ethernet port or wireless adapter.
524-
# There are some cases where this won't be the case. Randomly
525-
# generated MACs may not be universally administered, but they must
526-
# have their multicast bit set, though this is tested in the
527-
# `test_random_getnode()` method specifically. Another case is the
528-
# Travis-CI case, which apparently only has locally administered MAC
529-
# addresses.
530-
if check_bit and not os.getenv('TRAVIS'):
531-
self.assertFalse(node & (1 << 41), '%012x' % node)
521+
if network:
522+
# 47 bit will never be set in IEEE 802 addresses obtained
523+
# from network cards.
524+
self.assertFalse(node & 0x010000000000, hex)
532525
self.assertTrue(0 < node < (1 << 48),
533526
"%s is not an RFC 4122 node ID" % hex)
534527

535528
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
536529
def test_ifconfig_getnode(self):
537530
node = self.uuid._ifconfig_getnode()
538-
self.check_node(node, 'ifconfig')
531+
self.check_node(node, 'ifconfig', True)
539532

540533
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
541534
def test_ip_getnode(self):
542535
node = self.uuid._ip_getnode()
543-
self.check_node(node, 'ip')
536+
self.check_node(node, 'ip', True)
544537

545538
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
546539
def test_arp_getnode(self):
547540
node = self.uuid._arp_getnode()
548-
self.check_node(node, 'arp')
541+
self.check_node(node, 'arp', True)
549542

550543
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
551544
def test_lanscan_getnode(self):
552545
node = self.uuid._lanscan_getnode()
553-
self.check_node(node, 'lanscan')
546+
self.check_node(node, 'lanscan', True)
554547

555548
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
556549
def test_netstat_getnode(self):
557550
node = self.uuid._netstat_getnode()
558-
self.check_node(node, 'netstat')
551+
self.check_node(node, 'netstat', True)
559552

560553
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
561554
def test_ipconfig_getnode(self):
562555
node = self.uuid._ipconfig_getnode()
563-
self.check_node(node, 'ipconfig')
556+
self.check_node(node, 'ipconfig', True)
564557

565558
@unittest.skipUnless(importable('win32wnet'), 'requires win32wnet')
566559
@unittest.skipUnless(importable('netbios'), 'requires netbios')
567560
def test_netbios_getnode(self):
568561
node = self.uuid._netbios_getnode()
569-
self.check_node(node)
562+
self.check_node(node, network=True)
570563

571564
def test_random_getnode(self):
572565
node = self.uuid._random_getnode()
573-
# The multicast bit, i.e. the least significant bit of first octet,
574-
# must be set for randomly generated MAC addresses. See RFC 4122,
575-
# $4.1.6.
576-
self.assertTrue(node & (1 << 40), '%012x' % node)
577-
self.check_node(node, check_bit=False)
566+
# Least significant bit of first octet must be set.
567+
self.assertTrue(node & 0x010000000000, '%012x' % node)
568+
self.check_node(node)
578569

579570
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
580571
def test_unix_getnode(self):
@@ -584,17 +575,13 @@ def test_unix_getnode(self):
584575
node = self.uuid._unix_getnode()
585576
except TypeError:
586577
self.skipTest('requires uuid_generate_time')
587-
# Since we don't know the provenance of the MAC address, don't check
588-
# whether it is locally or universally administered.
589-
self.check_node(node, 'unix', check_bit=False)
578+
self.check_node(node, 'unix')
590579

591580
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
592581
@unittest.skipUnless(importable('ctypes'), 'requires ctypes')
593582
def test_windll_getnode(self):
594583
node = self.uuid._windll_getnode()
595-
# Since we don't know the provenance of the MAC address, don't check
596-
# whether it is locally or universally administered.
597-
self.check_node(node, check_bit=False)
584+
self.check_node(node)
598585

599586

600587
class TestInternalsWithoutExtModule(BaseTestInternals, unittest.TestCase):

Lib/uuid.py

Lines changed: 11 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -342,29 +342,11 @@ def _popen(command, *args):
342342
env=env)
343343
return proc
344344

345-
# For MAC (a.k.a. IEEE 802, or EUI-48) addresses, the second least significant
346-
# bit of the first octet signifies whether the MAC address is universally (0)
347-
# or locally (1) administered. Network cards from hardware manufacturers will
348-
# always be universally administered to guarantee global uniqueness of the MAC
349-
# address, but any particular machine may have other interfaces which are
350-
# locally administered. An example of the latter is the bridge interface to
351-
# the Touch Bar on MacBook Pros.
352-
#
353-
# This bit works out to be the 42nd bit counting from 1 being the least
354-
# significant, or 1<<41. We'll skip over any locally administered MAC
355-
# addresses, as it makes no sense to use those in UUID calculation.
356-
#
357-
# See https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local
358-
359-
def _is_universal(mac):
360-
return not (mac & (1 << 41))
361-
362345
def _find_mac(command, args, hw_identifiers, get_index):
363-
first_local_mac = None
364346
try:
365347
proc = _popen(command, *args.split())
366348
if not proc:
367-
return None
349+
return
368350
with proc:
369351
for line in proc.stdout:
370352
words = line.lower().rstrip().split()
@@ -373,9 +355,8 @@ def _find_mac(command, args, hw_identifiers, get_index):
373355
try:
374356
word = words[get_index(i)]
375357
mac = int(word.replace(b':', b''), 16)
376-
if _is_universal(mac):
358+
if mac:
377359
return mac
378-
first_local_mac = first_local_mac or mac
379360
except (ValueError, IndexError):
380361
# Virtual interfaces, such as those provided by
381362
# VPNs, do not have a colon-delimited MAC address
@@ -385,7 +366,6 @@ def _find_mac(command, args, hw_identifiers, get_index):
385366
pass
386367
except OSError:
387368
pass
388-
return first_local_mac or None
389369

390370
def _ifconfig_getnode():
391371
"""Get the hardware address on Unix by running ifconfig."""
@@ -395,15 +375,13 @@ def _ifconfig_getnode():
395375
mac = _find_mac('ifconfig', args, keywords, lambda i: i+1)
396376
if mac:
397377
return mac
398-
return None
399378

400379
def _ip_getnode():
401380
"""Get the hardware address on Unix by running ip."""
402381
# This works on Linux with iproute2.
403382
mac = _find_mac('ip', 'link list', [b'link/ether'], lambda i: i+1)
404383
if mac:
405384
return mac
406-
return None
407385

408386
def _arp_getnode():
409387
"""Get the hardware address on Unix by running arp."""
@@ -426,10 +404,8 @@ def _arp_getnode():
426404
# This works on Linux, FreeBSD and NetBSD
427405
mac = _find_mac('arp', '-an', [os.fsencode('(%s)' % ip_addr)],
428406
lambda i: i+2)
429-
# Return None instead of 0.
430407
if mac:
431408
return mac
432-
return None
433409

434410
def _lanscan_getnode():
435411
"""Get the hardware address on Unix by running lanscan."""
@@ -439,36 +415,32 @@ def _lanscan_getnode():
439415
def _netstat_getnode():
440416
"""Get the hardware address on Unix by running netstat."""
441417
# This might work on AIX, Tru64 UNIX.
442-
first_local_mac = None
443418
try:
444419
proc = _popen('netstat', '-ia')
445420
if not proc:
446-
return None
421+
return
447422
with proc:
448423
words = proc.stdout.readline().rstrip().split()
449424
try:
450425
i = words.index(b'Address')
451426
except ValueError:
452-
return None
427+
return
453428
for line in proc.stdout:
454429
try:
455430
words = line.rstrip().split()
456431
word = words[i]
457432
if len(word) == 17 and word.count(b':') == 5:
458433
mac = int(word.replace(b':', b''), 16)
459-
if _is_universal(mac):
434+
if mac:
460435
return mac
461-
first_local_mac = first_local_mac or mac
462436
except (ValueError, IndexError):
463437
pass
464438
except OSError:
465439
pass
466-
return first_local_mac or None
467440

468441
def _ipconfig_getnode():
469442
"""Get the hardware address on Windows by running ipconfig.exe."""
470443
import os, re
471-
first_local_mac = None
472444
dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
473445
try:
474446
import ctypes
@@ -486,23 +458,18 @@ def _ipconfig_getnode():
486458
for line in pipe:
487459
value = line.split(':')[-1].strip().lower()
488460
if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
489-
mac = int(value.replace('-', ''), 16)
490-
if _is_universal(mac):
491-
return mac
492-
first_local_mac = first_local_mac or mac
493-
return first_local_mac or None
461+
return int(value.replace('-', ''), 16)
494462

495463
def _netbios_getnode():
496464
"""Get the hardware address on Windows using NetBIOS calls.
497465
See http://support.microsoft.com/kb/118623 for details."""
498466
import win32wnet, netbios
499-
first_local_mac = None
500467
ncb = netbios.NCB()
501468
ncb.Command = netbios.NCBENUM
502469
ncb.Buffer = adapters = netbios.LANA_ENUM()
503470
adapters._pack()
504471
if win32wnet.Netbios(ncb) != 0:
505-
return None
472+
return
506473
adapters._unpack()
507474
for i in range(adapters.length):
508475
ncb.Reset()
@@ -521,11 +488,7 @@ def _netbios_getnode():
521488
bytes = status.adapter_address[:6]
522489
if len(bytes) != 6:
523490
continue
524-
mac = int.from_bytes(bytes, 'big')
525-
if _is_universal(mac):
526-
return mac
527-
first_local_mac = first_local_mac or mac
528-
return first_local_mac or None
491+
return int.from_bytes(bytes, 'big')
529492

530493

531494
_generate_time_safe = _UuidCreate = None
@@ -638,19 +601,9 @@ def _windll_getnode():
638601
return UUID(bytes=bytes_(_buffer.raw)).node
639602

640603
def _random_getnode():
641-
"""Get a random node ID."""
642-
# RFC 4122, $4.1.6 says "For systems with no IEEE address, a randomly or
643-
# pseudo-randomly generated value may be used; see Section 4.5. The
644-
# multicast bit must be set in such addresses, in order that they will
645-
# never conflict with addresses obtained from network cards."
646-
#
647-
# The "multicast bit" of a MAC address is defined to be "the least
648-
# significant bit of the first octet". This works out to be the 41st bit
649-
# counting from 1 being the least significant bit, or 1<<40.
650-
#
651-
# See https://en.wikipedia.org/wiki/MAC_address#Unicast_vs._multicast
604+
"""Get a random node ID, with eighth bit set as suggested by RFC 4122."""
652605
import random
653-
return random.getrandbits(48) | (1 << 40)
606+
return random.getrandbits(48) | 0x010000000000
654607

655608

656609
_node = None
@@ -673,14 +626,13 @@ def getnode():
673626
getters = [_unix_getnode, _ifconfig_getnode, _ip_getnode,
674627
_arp_getnode, _lanscan_getnode, _netstat_getnode]
675628

676-
for getter in getters:
629+
for getter in getters + [_random_getnode]:
677630
try:
678631
_node = getter()
679632
except:
680633
continue
681634
if _node is not None:
682635
return _node
683-
return _random_getnode()
684636

685637

686638
_last_timestamp = None

Misc/NEWS.d/next/Library/2017-11-26-18-48-17.bpo-32107.h2ph2K.rst

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)