Useful CLI tools (bash) for Arch Linux administration
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

174 lines
6.2 KiB

#!/usr/bin/env bash
#
# genmac - Generate a random MAC address for a Systemd-configured network interface
#
# Copyright (C) 2021 Pekka Helenius <pekka.helenius@fjordtek.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#####################################
trap ctrl_c INT
function ctrl_c() {
echo -e "\nAborting.\n"
return
}
random_mac() {
MAC=$(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')
}
insert_mac() {
echo -e "\nChanging MAC address information (root permission required).\n"
sudo sed -i "/\[Link\]/!b;n;cMACAddress=$MAC" /etc/systemd/network/00-default.link
echo -e "MAC address changed from '$MAC_OLD' to '$MAC' for interface '$MAC_DEVICE'.\n\nPlease restart this interface to apply the changes.\n\nTo restore original MAC address, either delete configuration file '/etc/systemd/network/$linkname' or set real MAC address manually into it.\n"
return 0
}
geninsert_mac() {
gennew_mac() {
while true; do
unset response
read -r -p "Generate a new MAC address? [Y/n] " response
if [[ $(echo $response | sed 's/ //g') =~ ^([yY][eE][sS]|[yY])$ ]]; then
random_mac
newname_mac
else
echo -e "\nKeeping old MAC address configuration.\n"
return
fi
done
}
newname_mac() {
unset response
read -r -p "New MAC address for '$MAC_DEVICE' will be '$MAC'. Accept? [Y/n] " response
if [[ $(echo $response | sed 's/ //g') =~ ^([yY][eE][sS]|[yY])$ ]]; then
insert_mac
else
gennew_mac
fi
}
newname_mac
}
gen_mac() {
real_mac() {
AVAILABLE_MACS=$(ip -br link show | sed '/LOOPBACK/d' | awk '{print NR"\t"$1"\t"$3"\t"$2}')
IFS=$'\n'
echo -e "\nAvailable network interfaces with their MAC addresses are:\n\n${AVAILABLE_MACS[*]}"
echo -e "\nPlease select the interface which MAC address you want to spoof of\n"
read -r -p "Selection [number]: " number
if [[ ! $number =~ ^[0-9]+$ ]]; then
echo -e "\nInvalid input value. Aborting.\n"
return 1
fi
for INTERFACE in $(echo -e "${AVAILABLE_MACS[*]}"); do
intf_num=$(echo $INTERFACE | awk '{print $1}')
if [[ $number -eq $intf_num ]]; then
MAC_REAL=$(echo $INTERFACE | awk '{print $3}')
MAC_DEVICE=$(echo $INTERFACE | awk '{print $2}')
break
fi
done
unset IFS
if [[ $MAC_REAL == "" ]]; then
echo -e "\nNot a valid MAC address found for interface number $number. Aborting.\n"
return 1
fi
}
real_mac
PREV_CONF=$(grep -Ril "$MAC_REAL" /etc/systemd/network/)
if [[ ! $(echo $PREV_CONF | wc -w) -eq 0 ]]; then
echo -e "\nUsing existing configuration file for interface '$MAC_DEVICE':\n$PREV_CONF\n"
linkname=$(basename $PREV_CONF)
MAC_OLD=$(awk -F= '/\[Link\]/{getline; print $2}' $PREV_CONF)
else
MAC_OLD=$MAC_REAL
echo -e "\nPrevious configuration file not found. Creating it (root permission required).\n"
read -r -p "Configuration file name? (must follow syntax: 00-default.link, 41-default.link, 98-default.link etc.): " linkname
if [[ $linkname =~ ^[0-9][0-9]-default.link ]]; then
if [[ ! $(sudo -n true) ]]; then
sudo echo ""
fi
echo -e "[Match]\nMACAddress=$MAC_REAL\n\n[Link]\nMACAddress=$MAC_REAL\nNamePolicy=kernel database onboard slot path" \
| sudo tee /etc/systemd/network/$linkname > /dev/null
echo -e "Created new configuration file: /etc/systemd/network/$linkname\n"
else
echo -e "\nInvalid file name given. Aborting.\n"
return 1
fi
fi
unset response
echo -e "Either randomly generated or manually specified MAC address can be used.\n"
read -r -p "Do you want to use randomly generated MAC address? [Y/n] " response
if [[ $(echo $response | sed 's/ //g') =~ ^([yY][eE][sS]|[yY])$ ]]; then
random_mac
geninsert_mac
else
if [[ $(echo $response | sed 's/ //g') =~ ^([nN][oO]|[nN])$ ]]; then
read -r -p "Please type a new MAC address (Syntax is e.g. aa:bb:33:zz:f0:4a): " MAC
maxtries=5
while [[ $maxtries -gt 0 ]]; do
case "$MAC" in
[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]])
insert_mac
;;
esac
unset MAC
read -r -p "Invalid MAC address given. Please type again ($maxtries tries left): " MAC
let maxtries--
done
else
echo -e "\nInvalid answer. Aborting.\n"
fi
fi
}
echo -e "\nWARNING: Changing MAC address WILL DISRUPT connections to any network device using MAC-based authentication methods. These devices may include configured routers, WiFi hotspots etc. Remember to write down the new MAC address, and make sure you are authorized to configure the MAC address to all affected network devices if needed.\n"
read -r -p "You are going to spoof a MAC address of a network interface of this computer. Are you sure? [Y/n] " response
if [[ $(echo $response | sed 's/ //g') =~ ^([yY][eE][sS]|[yY])$ ]]; then
gen_mac
else
echo -e "\nKeeping old MAC address configuration.\n"
fi