Page 1 of 1

SCRIPT : mac_address_change.sh *bug?*

Posted: Sun Nov 21, 2021 7:51 pm
by held
This is something I ran into and wanted to report on. Now I'm no programmer so be gentle :lol:

I had an issue where an invalid mac address was created. After some troubleshooting I found the mac_address_change.sh. Afaict it does not create universally administered unicast addresses properly. Only x0- x4- x8- xC- are unicast. Which is probably the reason why it wasn't accepted by the NIC. I traced it back to this part of the code:

Code: Select all

# very rarely the hexdump thing plus bitwise operations fails, so I repeat the MAC address generation to be sure
until echo "${MAC_ADDRESS}" | grep -qE "[0-9A-F]{2}(\:[0-9A-F]{2}){5}"
do
	MAC_ADDRESS="$(printf "%012X" $(( 0x$(hexdump -n6 -e '/1 "%02X"' /dev/random) & 0xFEFFFFFFFFFF | 0x020000000000 )) | sed 's/.\{2\}/&:/g' | sed s/:$//g)"
done
Now since this is not cryptography I would use /dev/urandom because its faster. The last two bits of the first octet can be shifted to the right, then shifted back. This would skip any multicast or locally administered generated mac addresses.

Code: Select all

MAC_ADDRESS=`printf '%02x\n' $(( $(( 0x$(hexdump -n1 -e'1/1 "%02X"' /dev/urandom) >> 2 )) << 2 ))`
MAC_ADDRESS=${MAC_ADDRESS}$(hexdump -n5 -e '5/1 ":%02X"' /dev/urandom)
However the more simple solution would be to change the first octet to 00 which is unicast compliant.

Code: Select all

MAC_ADDRESS="$(hexdump -n5 -e'"00" 5/1 ":%02X"' /dev/urandom)"

Re: SCRIPT : mac_address_change.sh *bug?*

Posted: Mon Nov 22, 2021 8:54 am
by held
Well it would still fail sometimes,(I'm using it for something else also) so I dove into it again and I think i figured it out now 100% :D

1. The reason hexdump fails is because of not using this parameter

Code: Select all

 -v 
Cause hexdump to display all input data. Without the -v option, any number of groups of output lines, which would be identical to the immediately preceding group of output lines (except for the input offsets), are replaced with a line comprised of a single asterisk.

and therefor the $(( )) arithmetic would fail if a group is replaced with a single asterisk

2. & 0xFEFFFFFFFFFF | 0x020000000000 should be replaced by & 0xFCFFFFFFFFFF as you want to zero the last two bits, namely Universal vs local (U/L bit) and the Unicast vs multicast (I/G bit)

3. sed can be shortened to: sed 's/../:&/2g' , skipping the first insert of the colon

Resulting in:

Code: Select all

MAC_ADDRESS="$(printf "%012x" $(( 0x$(hexdump -n6 -ve '/1 "%02X"' /dev/urandom) & 0xFCFFFFFFFFFF )) | sed 's/../:&/2g;s/^://')"