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()
@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.

@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