Skip to content

Instantly share code, notes, and snippets.

@pklaus
Last active May 31, 2025 14:15
Show Gist options
  • Select an option

  • Save pklaus/9638536 to your computer and use it in GitHub Desktop.

Select an option

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

goneri commented Jan 13, 2015

Copy link
Copy Markdown

What about just:

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

ghost commented Nov 30, 2016

Copy link
Copy Markdown

Very nice @goneri! :-D

@mdminhazulhaque

Copy link
Copy Markdown

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)
        )

ghost commented Apr 2, 2017

Copy link
Copy Markdown
#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
Copy Markdown

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

rwarren commented Apr 21, 2017

Copy link
Copy Markdown

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
Copy Markdown

#!/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

fquinto commented Jun 24, 2017

Copy link
Copy Markdown

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

fatestapestry commented Mar 13, 2018

Copy link
Copy Markdown

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

@AleaLabs

AleaLabs commented Jun 1, 2018

Copy link
Copy Markdown

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

@larshb

larshb commented Jan 17, 2019

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

@fquinto

fquinto commented Apr 11, 2019

Copy link
Copy Markdown

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
Copy Markdown

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

pklaus commented Sep 4, 2019

Copy link
Copy Markdown
Author

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

jakabk commented Oct 24, 2019

Copy link
Copy Markdown

Or just

def rand_mac():
  ...

or

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

@2foil

2foil commented Sep 28, 2020

Copy link
Copy Markdown

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
Copy Markdown

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