35

How do I generate a random MAC address from the Linux command line?

I search for a solution that only requires standard tools commonly found on the Linux command line.

The MAC address will be used for a guest KVM.

0

13 Answers 13

58

I use

macaddr=$(echo $FQDN|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')

The benefit of this method, over a completely random number, is that it's possible to reliably reproduce the MAC address based on the FQDN of the machine, which I find useful sometimes. The 02 for the first octet just sets the "locally assigned" bit, which makes it obvious that it's not a vendor-provided MAC address, and guarantees that you won't collide with a real NIC's MAC address.

If you need to generate multiple MAC addresses per host, I used to concatenate the FQDN with the name of the bridge to connect the interface to; this did a good job of spreading things out for different NICs.

5
  • 1
    +1 for the reproducibility; for certain applications, that makes it a much superior method to mine.
    – MadHatter
    Aug 10, 2011 at 8:18
  • Thanks a lot, I like the idea of having it reproducible. Aug 10, 2011 at 11:58
  • 1
    Plus no mac address conflicts in the unlikely event you'd randomly generate the same mac twice
    – Petter H
    Sep 25, 2014 at 8:06
  • 3
    As alternative you can use tr -dc A-F0-9 < /dev/urandom | head -c 10 | sed -r 's/(..)/\1:/g;s/:$//;s/^/02:/'
    – ALex_hha
    May 26, 2016 at 8:59
  • 1
    It's only an "alternative" in the sense that it produces a completely different end result to what my snippet does...
    – womble
    May 30, 2016 at 6:10
10

The posted scripts are good, but I want to add a warning: Mind the Birthday (paradoxon)!

It comes from the fact that even if you have just 23 people, the chance is already 50% that 2 of them have birthday on the same day.

It depends on your scenario how you use it, but if you generate the MACS randomly, at approx 1 million your chance for a mac number clash is 40% at 2 million it is already 87%!

If you need just a couple this is ok, but when you maintain a server farm with hundreds of servers, each of them hosting tens of virtual machines, or if you use the macs as index in some db for bookkeeping and you need uniques be careful!

4
  • Thanks, for the warning about the Birthday paradox! In my case I will take the risk as I will generate around 20 MAC addresses. Aug 10, 2011 at 12:22
  • 3
    If you're running hundreds of servers each hosting tens of virtual machines all on the same broadcast domain, you've got bigger problems than MAC address collision risk.
    – womble
    Sep 25, 2014 at 23:28
  • 1
    "It comes from the fact that even if you have just 23 people, the chance is already 50% that 2 of them have birthday on the same day." That's not even remotely true. There is about a 50% chance that two of 23 people have the same birthday anniversary, not the same birthday.
    – Ron Maupin
    Jul 29, 2016 at 21:45
  • If you choose 40 of the 48 bits randomly, as suggested in womble's answer, you need 100,000 servers to have a 0.5% chance of any of them conflicting. You can use instacalc.com/28845 to calculate this. So it's not hundreds of servers, it's millions of servers.
    – Arnout
    Apr 24, 2020 at 10:34
9

These variants work as well.

longer:

openssl rand -hex 6 | sed 's/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/\1:\2:\3:\4:\5:\6/'

or shorter:

openssl rand -hex 6 | sed 's/\(..\)/\1:/g; s/:$//'

The load consumption of both variants is very similar according to quick measuring with time.

6
  • Hi Anthony, I see no other variant combining openssl rand and sed here, so this is unique solution in this topic. Sep 26, 2016 at 11:27
  • That's true. He/she used fold -w2|paste -sd: - instead of sed. The sed solution is probably easier to remember as it uses a more familiar tool – though I learned more from his/her answer. Sep 26, 2016 at 13:21
  • 1
    I think the first command won't work because it does not set the first bit to be even!
    – amrx
    Jul 26, 2018 at 21:49
  • 2
    Hi @JaroslavKucera, Unicast MAC addresses must never set the 1's place bit in the first byte. That's the "group" (multicast/broadcast) bit. If you make up your own MAC address, you're supposed to set the 2's place bit (the "locally administered" bit) in the first byte, to differentiate it from a guaranteed globally unique MAC address.
    – amrx
    Jul 28, 2018 at 21:52
  • 1
    On a Linux machine, if the user tries to set their MAC address to 03:00:00:00:00:00 locally, they'll get RTNETLINK answers: Cannot assign requested address, because the second bit must be set, but not the first. In other words, 00000011 fails, while 00000010 is correct. 03 octet fails; 02 octet is correct. Actually, in a broadcast address, the user would see 11111111 (255), 255.255.255.255. To make a long story short, the first octet should represent an even number, not an odd. Jun 10, 2021 at 17:11
7

I know this post is old, but for future visitors, if you want a cryptographically secure pseudorandom MAC address, without being limited to 0x02 as the OUI, here is a fast mostly platform agnostic generator:

$ printf '%02x' $((0x$(od /dev/urandom -N1 -t x1 -An | cut -c 2-) & 0xFE | 0x02)); od /dev/urandom -N5 -t x1 -An | sed 's/ /:/g'
1
  • 1
    This is my favorite answer because it gets the local unicast bits right. I modified it slightly to use just tr instead of but cut and sed: printf '%02x' $((0x$(od /dev/urandom -N1 -t x1 -An | tr -d ' ') & 0xFE | 0x02)); od /dev/urandom -N5 -t x1 -An | tr ' ' ':' Mar 14, 2022 at 19:30
6
myserver% perl -e 'for ($i=0;$i<6;$i++){@m[$i]=int(rand(256));} printf "%X:%X:%X:%X:%X:%X\n",@m;'
55:C2:A5:FA:17:74

Ah, the ol' Swiss Army Chainsaw rides again. And by way of version 0.2, I'm unashamedly stealing womble's excellent point about the first octet being 02:

myserver% perl -e 'for ($i=0;$i<5;$i++){@m[$i]=int(rand(256));} printf "02:%X:%X:%X:%X:%X\n",@m;'
02:8E:94:A3:47:26
1
  • Thanks MadHatter, I tried your second variant and it worked. Very nice! Aug 11, 2011 at 12:47
3

Here are five other options, all of which use random bits for the least significant bit of the most significant byte that indicates if the address is unicast or multicast and for the second-least significant bit of the most significant byte that indicates if the address is universally or locally administered.

jot -w%02X -s: -r 6 1 256
openssl rand -hex 6|fold -w2|paste -sd: -
od -N6 -tx1 -An /dev/random|awk '$1=$1'|tr \  :
god -N6 -tx1 -An /dev/random|cut -c2-|tr \  :
hexdump -n6 -e'/1 ":%02X"' /dev/random|cut -c2-

jot comes with OS X and BSDs but not with most Linux distributions. In jot -w changes the format, -s changes the separator, and -r generates random numbers.

od is in POSIX but hexdump is not.

OS X's od (/usr/bin/od below) uses a different output format than GNU od:

$ /usr/bin/od -N6 -tx1 -An /dev/random|tr ' ' :
:::::::::::d9::b9::d7::da::5f::96::::::::::::::::::::::::::::::::::::::::
$ god -N6 -tx1 -An /dev/random|tr ' ' :
:f5:6d:0a:3b:39:f9

In OS X's od options placed after an argument for an input file are treated as the names of input files, so the command in the answer by Aaron Toponce reads from /dev/urandom indefinitely with OS X's od.

2

Here's another one, based on wombie's answer:

macaddr=$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/')
echo $macaddr
1
  • There's no need to run urandom output through md5sum; you can just use od as per Aaron Toponce's answer.
    – womble
    Sep 25, 2014 at 23:29
1

I use:

echo -n 02; od -t x1 -An -N 5 /dev/urandom | tr ' ' ':'
1

You could just add a $RANDOM after $FQDN and this would give you random mac addresses every time you run it. This is especially helpful for poeple who want to create backup vms using snapshots or clones of vms.

macaddr=$(echo $FQDN$RANDOM|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
1
  • 1
    Note that $RANDOM is available in bash, but may not be available in other shells. Oct 31, 2018 at 15:27
0

Python one-liner:

python3 -c 'import os; print(":".join(["{:02x}".format(x) for x in b"\02x" + os.urandom(5)]))'
0

Just for fun, here is a pure bash version, tested against Bash 4.4.12(1)-release:

read -N6 b </dev/urandom
LC_ALL=C printf "%02x:%02x:%02x:%02x:%02x:%02x\n" "'${b:0:1}" "'${b:1:1}" "'${b:2:1}" "'${b:3:1}" "'${b:4:1}" "'${b:5:1}"

First line reads 6 characters from /dev/urandom; then using the C character set print the 0-filled hex value of each character separated with a colon (the newline is optional but useful to print out the value).

Since you can print directly to a variable with printf -v myvar there is no fork/subshell needed to capture the result.

Extracting the value of a character using printf is defined in POSIX printf documentation:

If the leading character is a single-quote or double-quote, the value shall be the numeric value in the underlying codeset of the character following the single-quote or double-quote.

NB: read will not block on /dev/urandom, so it may return early causing the last bytes of the MAC to be all 0's. This will be particularly noticeable if run in a thigh loop or if another application is doing heavy reads at the same time from /dev/urandom.

0

If you're an idiot^H^H^H^H^Hnaive like I was and don't do the local/unicast right, I found the following works to patch six random bytes. And of course you can use one of the simple schemes here and feed it into this.

echo -n "01:23:45:AB:CD:EF" | sed 's/^\(.\)[013]\(.*\)/\12\2/' | sed 's/^\(.\)[457]\(.*\)/\16\2/' | sed 's/^\(.\)[89B]\(.*\)/\1A\2/' | sed 's/^\(.\)[CDF]\(.*\)/\1E\2/')

If there's a shorter variant, I'd love to see it.

0

Locally administered unicast address randomizing all the remaining bits:

python3 -c 'import os;print(":".join(f"{os.urandom(1)[0]&~m|m*2:02x}" for m in [1]+5*[0]))'

(the ~m mask is used to clear bit 0 of the leftmost byte; the m*2 mask is to set bit 1)

Why posting one more solution here: wanted something short and readable without the bad feeling of leaving some bits wasted (regardless the practical importance of these extra 6 bits of address space).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .