Skip to content

Instantly share code, notes, and snippets.

@pklaus
Last active May 31, 2025 14:15
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()
@fatestapestry
Copy link

fatestapestry 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'

@jpramosi
Copy link

A non-random version for generating a MAC address from a string:

def generate_mac(text: str, multicast=False, universally_administered=False) -> str:
    from hashlib import sha256

    h = sha256(text.encode("utf-8")).digest()

    # https://en.wikipedia.org/wiki/MAC_address#Unicast_vs._multicast_(I/G_bit)
    # https://gist.github.com/pklaus/9638536
    bit = h[0]
    if multicast:
        bit |= 1  # set bit 0
    else:
        bit &= ~1  # clear bit 0
    if universally_administered:
        bit &= ~(1 << 1)  # clear bit 1
    else:
        bit |= 1 << 1  # set bit 1

    m0 = int.from_bytes([bit], "little")
    m1 = int.from_bytes([h[4]], "little")
    m2 = int.from_bytes([h[8]], "little")
    m3 = int.from_bytes([h[8]], "little")
    m4 = int.from_bytes([h[16]], "little")
    m5 = int.from_bytes([h[20]], "little")

    return f"{m0:02x}:{m1:02x}:{m2:02x}:{m3:02x}:{m4:02x}:{m5:02x}"

It might have a high hash collision rate, but it's still pretty useful to me. I use it to generate a MAC from a hostname to stop my router from delivering an old IP address from my recreated virtual machines.

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