Skip to content

Instantly share code, notes, and snippets.

@pklaus
Last active July 6, 2023 13:50
Show Gist options
  • Save pklaus/9638536 to your computer and use it in GitHub Desktop.
Save pklaus/9638536 to your computer and use it in GitHub Desktop.
Generating Random MAC Addresses with Python

The mini-tool has a CLI-Interface with the following options:

  • Unicast or Multicast? Default: Unicast
  • Locally Administered or Globally Unique? Default: Locally Administered
  • Prescribe specific OUI (overwrites the above two)

TODO

  • Add an option to generate a number of MACs without collisions.

Resources

#!/usr/bin/env python
import random
def random_bytes(num=6):
return [random.randrange(256) for _ in range(num)]
def generate_mac(uaa=False, multicast=False, oui=None, separator=':', byte_fmt='%02x'):
mac = random_bytes()
if oui:
if type(oui) == str:
oui = [int(chunk) for chunk in oui.split(separator)]
mac = oui + random_bytes(num=6-len(oui))
else:
if multicast:
mac[0] |= 1 # set bit 0
else:
mac[0] &= ~1 # clear bit 0
if uaa:
mac[0] &= ~(1 << 1) # clear bit 1
else:
mac[0] |= 1 << 1 # set bit 1
return separator.join(byte_fmt % b for b in mac)
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--uaa', action='store_true', help='generates a universally administered address (instead of LAA otherwise)')
parser.add_argument('--multicast', action='store_true', help='generates a multicast MAC (instead of unicast otherwise)')
parser.add_argument('--oui', help='enforces a specific organizationally unique identifier (like 00:60:2f for Cisco)')
parser.add_argument('--byte-fmt', default='%02x', help='The byte format. Set to %02X for uppercase hex formatting.')
parser.add_argument('--separator', default=':', help="The byte separator character. Defaults to ':'.")
args = parser.parse_args()
print(generate_mac(oui=args.oui, uaa=args.uaa, multicast=args.multicast, separator=args.separator, byte_fmt=args.byte_fmt))
if __name__ == '__main__':
main()
@pklaus
Copy link
Author

pklaus commented Sep 4, 2019

Thanks for all the comments. I updated my code today with the possibility to specify LAA/UAA and Unicast/Multicast or even prescribe a specific OUI. The code is optimized for clarity not speed but still quite fast compared to a simplistic approach neglecting UAA/LAA or Unicast/Multicast:

$ python -m timeit 'from randmac import generate_mac' 'generate_mac()'
50000 loops, best of 5: 9.73 usec per loop
$ python -m timeit "import random" "':'.join('%02x'%random.randrange(256) for _ in range(6))"
50000 loops, best of 5: 7.86 usec per loop

For any application that I could think of, generating a random MAC in under 10 μs shouln't be a showstopper 😄.

@jakabk
Copy link

jakabk commented Oct 24, 2019

Or just

def rand_mac():
  ...

or

   return ('{:02x}' * 6).format(*[random.randrange(256) for _ in range(6)])

@2foil
Copy link

2foil commented Sep 28, 2020

Here is a more dense version 😆:

>>> random_mac = lambda : ":".join([f"{random.randint(0, 255):02x}" for _ in range(6)])

>>> random_mac()
'b8:de:1a:98:8f:ab'

>>> random_mac()
'e4:c4:3e:40:27:7b'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment