Commits

Etienne Perot  committed 37d896e

Add install-udev-rules.sh script which generates udev rules instead of using a systemd service to do the job

  • Participants
  • Parent commits 08ec182

Comments (0)

Files changed (3)

 # Maintainer: Etienne Perot <etienne@perot.me>
 pkgname=macchiato-git
-pkgver=20130124
+pkgver=20130207
 pkgrel=1
 pkgdesc='MAC spoofing with a restricted range of OUI prefixes'
 arch=('i686' 'x86_64')
 	cd "$srcdir/$_gitname-build"
 	install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
 	install -D -m755 macchiato "${pkgdir}/usr/share/macchiato/macchiato"
+	install -D -m755 install-udev-rules.sh "${pkgdir}/usr/share/macchiato/install-udev-rules.sh"
 	for _oui in oui/*; do
 		install -D -m644 "$_oui" "${pkgdir}/usr/share/macchiato/$_oui"
 	done

File install-udev-rules.sh

+#!/usr/bin/env bash
+
+udev_rules='/etc/udev/rules.d'
+output_rule="$udev_rules/20-macchiato.rules"
+
+if [ "$#" -eq 0 ]; then
+	echo "This script requires macchiato's configuration directory as argument."
+	echo 'It also assumes that you have already set all the configuration files up,'
+	echo 'so make sure you do that first before running this script again.'
+	exit 1
+fi
+
+if [ -x /usr/share/macchiato/macchiato ]; then
+	macchiato_bin='/usr/share/macchiato/macchiato'
+else
+	if ! which macchiato &> /dev/null; then
+		echo 'Cannot find macchiato executable in $PATH.'
+		exit 1
+	fi
+	macchiato_bin=$(which macchiato)
+fi
+bash_bin=$(which bash)
+
+confDir="$1"
+if [ ! -d "$confDir" ]; then
+	echo "Configuration directory '$confDir' not found."
+	exit 1
+fi
+
+confGlob=$(echo "$confDir"/*.sh)
+if [ "$confGlob" == "$confDir/*.sh" ]; then
+	echo "No configuration files found matching pattern '$confDir/*.sh'."
+	exit 1
+fi
+
+devices=()
+for i in "$confDir"/*.sh; do
+	deviceName=$(basename "$i" | sed 's/\.sh$//')
+	if ip link show "$deviceName" &> /dev/null; then
+		devices+=("$deviceName")
+	else
+		echo "Configuration file '$i' found, but network interface '$deviceName' does not exist."
+		exit 1
+	fi
+done
+
+udevGlob=$(echo "$udev_rules/*")
+
+declare -A macAddresses
+for device in "${devices[@]}"; do
+	unsure=true
+	macAddress=$(ip link show "$deviceName" | grep -E '([0-9A-Fa-f][0-9A-Fa-f]:){5}[0-9A-Fa-f][0-9A-Fa-f]' | sed -r 's#\s*brd.*$##;s#^\s*(link/)?ether\s*##')
+	echo "[$device] MAC address '$macAddress' obtained from 'ip link show' command. Trying a more elaborate guess."
+	if [ "$udevGlob" != "$udev_rules/*" ]; then
+		for rule in "$udev_rules/*"; do
+			if grep -Ei "SUBSYSTEM\s*==\s*\"net\"\s*,\s*ATTR{address}\s*==\s*\"[^\"]*\"\s*,\s*NAME\s*=\s*\"$device\"" "$rule" &> /dev/null; then
+				macAddress=$(grep -Ei "SUBSYSTEM\s*==\s*\"net\"\s*,\s*ATTR{address}\s*==\s*\"[^\"]*\"\s*,\s*NAME\s*=\s*\"$device\"" "$rule" | sed -r 's#^.*ATTR\{address\}\s*==\s*"([^"]+)".*$#\1#i')
+				echo "[$device] MAC address '$macAddress' obtained from udev rules file: '$rule'"
+			fi
+		done
+	fi
+	if [ -f "$output_rule" ]; then
+		if grep -E "^#\\s*macchiato-data:\\s*$device\\s*=" "$output_rule" &> /dev/null; then
+			macAddress=$(grep -E "^#\\s*macchiato-data:\\s*$device\\s*=" "$output_rule" | sed -r "s/^#\\s*macchiato-data:\\s*$device\\s*=\\s*//")
+			echo "[$device] MAC address '$macAddress' obtained from previous run of the script."
+			unsure=''
+		fi
+	fi
+	if [ -n "$unsure" ]; then
+		echo "[$device] Is this correct?"
+		echo "     If it is correct, leave blank."
+		echo "     If it is incorrect, please enter the *hardware* MAC address."
+		read -p "[$device] Hardware MAC address? [$macAddress] " userMacAddress
+		if [ -n "$userMacAddress" ]; then
+			macAddress=$(echo "$userMacAddress" | sed 's/-/:/g' | tr '[A-Z]' '[a-z]')
+		fi
+		echo "[$device] Using '$macAddress' as definitive MAC address."
+	fi
+	macAddresses["$device"]="$macAddress"
+done
+
+echo '# This file is generated by by macchiato using the install-udev-rules.sh script.' > "$output_rule"
+echo '# As such, any changes you make here will be overwritten during the next run of script.' >> "$output_rule"
+echo '' >> "$output_rule"
+for device in "${!macAddresses[@]}"; do
+	echo "# macchiato-data: $device = ${macAddresses[$device]}" >> "$output_rule"
+	echo "ACTION==\"add\", ATTR{address}==\"${macAddresses[$device]}\", RUN+=\"$bash_bin '$macchiato_bin' '$confDir' '$device'\"" >> "$output_rule"
+	echo '' >> "$output_rule"
+done
+echo "All done. Udev rules have been written to '$output_rule'"
 #!/usr/bin/env bash
 
+# macchiato
+# Usage:
+#     macchiato [confdir] [device1] [device2] ...
+#
+# 'confdir' is expected to contain a bunch of .sh files, named after each network interface.
+#     If not provided, will use '$(dirname "$BASH_SOURCE")/conf'
+# 'deviceN' is the name of a network interface on which to apply whatever the config file says.
+#     If not provided, will apply all configurations defined in 'confdir'
+
 scriptDir=$(dirname "$BASH_SOURCE")
 hexadecimalCharacters=(0 1 2 3 4 5 6 7 8 9 a b c d e f)
 
-if [ "$#" -eq 1 ]; then
-	confDir="$1"
-else
-	confDir="$scriptDir/conf"
-fi
+devices=()
+confDir="$scriptDir/conf"
+for arg; do
+	if [ -d "$arg" ]; then
+		confDir="$arg"
+	elif ip link show "$arg" &> /dev/null; then
+		devices+=("$arg")
+	else
+		echo "Don't know how to interpret argument: '$arg' - Neither a directory or a network interface."
+		exit 1
+	fi
+done
 
 if [ ! -d "$confDir" ]; then
 	echo "Configuration directory '$confDir' does not exist."
+	if [ "$#" -eq 0 ]; then # Probably first use; show something more helpful
+		echo 'Is this your first time using macchiato?'
+		echo 'You need to spend some time configuring it first.'
+		echo 'Read the readme file for help.'
+	fi
 	exit 1
 fi
 
 	exit 1
 fi
 
-devices=()
-for i in "$confDir"/*.sh; do
-	deviceName=$(basename "$i" | sed 's/\.sh$//')
-	if ip link show "$deviceName" &> /dev/null; then
-		devices+=("$deviceName")
-	else
-		echo "Configuration file '$i' found, but network interface '$deviceName' does not exist."
-		exit 1
-	fi
-done
-
 if [ "${#devices[@]}" -eq 0 ]; then
-	echo 'Error: No device configuration found.'
-	exit 1
+	for i in "$confDir"/*.sh; do
+		deviceName=$(basename "$i" | sed 's/\.sh$//')
+		if ip link show "$deviceName" &> /dev/null; then
+			devices+=("$deviceName")
+		else
+			echo "Configuration file '$i' found, but network interface '$deviceName' does not exist."
+			exit 1
+		fi
+	done
+else
+	for device in "${devices[@]}"; do
+		if [ ! -f "$confDir/$device.sh" ]; then
+			echo "Interface '$device' found, but its configuration file ('$confDir/$device.sh') was not found."
+			exit 1
+		fi
+	done
 fi
 
 for device in "${devices[@]}"; do
 	}
 	
 	finalMACAddress=$(getGoodMACAddress)
-	echo "[$device] Assigning spoofed MAC address: '$finalMACAddress'"
 	deviceIsUp=$(ip link show "$device" up)
 	if [ -n "$deviceIsUp" ]; then
 		echo "[$device] Bringing device down"
 			echo "[$device] Failed to bring device down! Assigning a new MAC address is likely to fail as well."
 		fi
 	fi
+	echo "[$device] Assigning spoofed MAC address: '$finalMACAddress'"
 	if ! ip link set "$device" address "$finalMACAddress"; then
 		echo "[$device] WARNING: Failed to assign MAC address '$finalMACAddress'"
+		if [ "$EUID" -ne 0 ]; then
+			echo 'It looks like you are not running this script as root. You may want to change that.'
+		fi
 	fi
 	if [ -n "$deviceIsUp" ]; then
 		echo "[$device] Bringing device back up"