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

goneri commented Jan 13, 2015

What about just:

    print("52:54:00:%02x:%02x:%02x" % (
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255),
        ))

Copy link

ghost commented Nov 30, 2016

Very nice @goneri! :-D

@mdminhazulhaque
Copy link

Or just

def rand_mac():
    return "%02x:%02x:%02x:%02x:%02x:%02x" % (
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255)
        )

Copy link

ghost commented Apr 2, 2017

#coded for python 3.5
import random
import string

def gen_hex(length): #this helps generate valid HEX addresses.
    return ''.join(random.choice('0123456789ABCDEF') for _ in range(length))

def gen_00mac(): #this generates a 00-XX-XX-XX-XX-XX mac address
    generated = '00' + gen_hex(2) + gen_hex(2) + gen_hex(2) + gen_hex(2) + gen_hex(2)
    return generated

def gen_list(what): #this generates our hex list.
    list1 = ""
    for i in range(what):
        if (what < i):
            list1+=gen_00mac()
        else:
            list1+=gen_00mac() + "\n"
    return list1

def gen_save(filename, output): #save our list
    file = open(filename, "w")
    print("Saving to: " + filename)
    file.write(output)
    print("Finished saving!")
    return

def gen_yn(): #simple check func
    option = input("Do you wish to save (y/n): ") #our Y/N option
    print ("Generating results...")
    tempgen = gen_list(numgen) #save our generated list to a variable
    print ("Results generated.")
    if (option == "y"):
        print ("Please wait for results...\n")
        print (tempgen) #print out the results
        gen_save("PyMAC.txt", tempgen) #filename, data
    else:
        print ("Please wait for results...\n")
        print (tempgen) #print out the results
    return

print ("PyMAC Generator v0.1 by LeftBased")
numgen = int(input("Generate # of MACs: "))
gen_yn()

@Kingwindie
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?

@rwarren
Copy link

rwarren commented Apr 21, 2017

This code generates a MAC Address globally registered to "Xensource Inc"! The first three bytes are important here, especially the bottom 2 bits of the top byte. I'm also not sure why the top bit of the NIC-specific is forced to zero.

You very likely want this code instead (for a locally administered unicast address):

"02:00:00:%02x:%02x:%02x" % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

If you actually have an OUID (top 23 bits) to use, you probably aren't looking at this gist. :)

This also works in bash and others:

printf '02:00:00:%02X:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256))

I also added this to Stackoverflow here: http://stackoverflow.com/a/43546406/465838

See the definition of a MAC address here.
See the registered OUIDs here (for fun, find the Xensource OUI that the original code was using!).

@RVDaescu
Copy link

#!/usr/bin/python

import random

def mac():
i=0
r=[]
while i<6:
s="".join([random.choice('0123456789ABCDE'),random.choice('0123456789ABCDE')])
r.append(s)
i+=1
r[0]="".join([random.choice('0123456789ABCDEF'),random.choice('0123456789ABC')])
return ":".join(r)

a=input("How many MACs do you need? \n >")
for b in range(a):
print mac()

#this creates as many MAC addresses as the user wants to - this is not specific OUI but it can be changed easily

@fquinto
Copy link

fquinto commented Jun 24, 2017

Sometimes you need only one compact line of code:

mac = ':'.join(("%012x" % random.randint(0, 0xFFFFFFFFFFFF))[i:i+2] for i in range(0, 12, 2))

Now is corrected! Sorry.

@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