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()
@jonathanelscpt
Copy link

jonathanelscpt commented Mar 13, 2018

@fquinto - has a bug. sometimes gives blank chars in mac string.

@AleaLabs
Copy link

AleaLabs commented Jun 1, 2018

@fquinto @jonathanelscpt - fix the issue by using "%012x" which gives leading zeros in the answer

@larshb
Copy link

larshb commented Jan 17, 2019

':'.join("%02x"%random.randint(0, 255) for _ in range(5))

@fquinto
Copy link

fquinto commented Apr 11, 2019

Now, I like to use this:

':'.join('%02x'%random.randrange(256) for _ in range(5))

Why? Because this:

t1 = timeit.Timer("':'.join(('%012x' % random.randint(0, 0xFFFFFFFFFFFF))[i:i+2] for i in range(0, 12, 2))", "import random")
t2 = timeit.Timer("':'.join('%02x'%random.randint(0, 255) for _ in range(5))", "import random")
t3 = timeit.Timer("':'.join('%02x'%random.randrange(2**8) for _ in range(5))", "import random")
t4 = timeit.Timer("':'.join('%02x'%random.randrange(256) for _ in range(5))", "import random")
for t in t1, t2, t3, t4:
    t.timeit()
# 9.202233295989572
# 6.3932015799946385
# 5.115052343986463
# 5.105975616010255

@ahmedbilal
Copy link

i have a noob question to ask,don't hate me for this because i am genuinely confused,but where am i supposed to type this code into?
A code editor? if yes how will it work?

It is Python Code. You need to create a file like code.py and put the code in it.
Then, run the code by entering the following command on terminal/command prompt
python code.py

@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