After installing a freshly-copied microSD card in a headless Raspberry Pi, there is sometimes an awkward moment. The Raspberry Pi boots in its default configuration and obtains an address from DHCP, then you need to SSH into it. However, even if in general the Raspberry Pi can be found with its domain name (raspberrypi by default) using a local DNS server or mDNS, it can also become a pain sometimes, for instance when you configure multiple Raspberry Pis at the same time.
In situations where ssh pi@raspberrypi.local does not work, you need to scan the local network to find the Raspberry Pis, which can be achieved with nmap. Raspberry Pi devices can be recognized because their MAC addresses are issued by the organization "Raspberry Pi Trading".
This allows to automate the discovery process by enumerating interfaces with ip then enumerating the Raspberry Pis on each interface with nmap:
#!/bin/bash
echo "Looking for Raspberry Pis..."
IFACES=$(ip -4 -o addr show | awk '/docker0/ {found=1; next} /scope global/ {print $4}')
RPI_ADDRS=()
for IFACE in $IFACES; do
echo "Scanning on interface $IFACE..."
ADDRS=$(sudo nmap -n -sP "$IFACE" | grep 'Raspberry Pi Trading' -B2 | awk -F ' ' '/report for/ {print $5}')
for ADDR in $ADDRS; do
echo "Found address: $ADDR"
RPI_ADDRS+=($ADDR)
done
done
Note the -n flag to disable DNS resolution and -sP flag to disable port scanning. Also, we skip the potential docker0 interface since it's clearly useless to scan it.
We can now adapt the script to enumerate only unconfigured Raspberry Pis by trying to connect them via SSH using the default password (Don't forget to enable the SSH server by writing a file named ssh to the boot partition):
#!/bin/bash
DEFAULT_PASS='raspberry'
SSH_OPTIONS="-q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
echo "Looking for unconfigured Raspberry Pis..."
IFACES=$(ip -4 -o addr show | awk '/docker0/ {found=1; next} /scope global/ {print $4}')
UNCONFIGURED_RPI_ADDRS=()
for IFACE in $IFACES; do
echo "Scanning on interface $IFACE..."
ADDRS=$(sudo nmap -n -sP "$IFACE" | grep 'Raspberry Pi Trading' -B2 | awk -F ' ' '/report for/ {print $5}')
for ADDR in $ADDRS; do
echo "Trying candidate address $ADDR..."
if sshpass -p $DEFAULT_PASS ssh $SSH_OPTIONS pi@$ADDR hostname &>/dev/null; then
echo "Found address: $ADDR"
UNCONFIGURED_RPI_ADDRS+=($ADDR)
fi
done
done
The custom SSH options allow to make it silent and fully bypass host key checking.
You can now run any operation on the list of hosts to easily apply it on a batch of fresh Raspberry Pis:
for ADDR in "${UNCONFIGURED_RPI_ADDRS[@]}"; do
sshpass -p $DEFAULT_PASS ssh $SSH_OPTIONS pi@$ADDR foo
done