When I powered on my new Raspberry Pi the other day, I realized I had a problem: even though we were both connected to the same WiFi network, I had no idea what its address was.
My anticlimatic solution was to connect it to a screen, but clearly this wouldn’t always be an option. No, we want to be able to locate a machine just by virtue of it being on the same network as us. The obvious idea is to have it broadcast some identifiable network packet periodically; then, we could wait for the packet, and, once we receive it, work our way back to the machine.
Let’s see if it works with UDP. On the local machine, we start
netcat(1) listening on UDP port \(23456\):
% nc -ulvn -p 23456 listening on [any] 23456 ...
On the Raspberry Pi, we have
netcat broadcast its hostname,
lily, to everybody on the above UDP port:
% echo "$(hostname)" | nc.traditional -ub -w 1 255.255.255.255 23456
Checking back on the local machine, we find
listening on [any] 23456 ... connect to [192.168.0.2] from (UNKNOWN) [192.168.0.6] 50028 lily
So, the idea works. But we’d like to get just the source address out of all that, and
netcat’s output is a bit hard to work with. Instead of trying to process it, let’s write
whereis.py, a Python script just for this task:
#!/usr/bin/python from __future__ import print_function import socket, sys if __name__ == "__main__": if len(sys.argv) != 2: print("USAGE: %s <id>" % (sys.argv,)) exit(1) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(("0.0.0.0", 23456)) while True: (data, (addr, port)) = sock.recvfrom(1024) if data.decode().strip() == sys.argv: break print(addr)
There’s nothing surprising about the above: we open a socket, bind it to a port, wait for packets, and exit only when the expected packet arrives. If we redo the experiment, we see:
% whereis.py lily 192.168.0.6
We still need to run the
netcat broadcast on
lily somehow. The simple solution is to add the command to its
crontab(1) so that it runs every minute:
% crontab -l * * * * * echo "$(hostname)" | nc.traditional -ub -w 1 255.255.255.255 23456
As an example, we can now
scvalex@alita ~ % ssh $(whereis.py lily) scvalex@lily ~ %
To recap, we wanted a way to find the address of a machine on the same network as us. We wrote a Python script that waits for a UDP packet with a certain content, and prints the source address of the packet. We then configured the remote machine to broadcast that packet using
We’ve already mentioned
netcat’s unwieldy output, but a bigger problem is that there’s no standard
netcat. The above commands work with the traditional
netcat (which is
nc on Gentoo, and
nc.traditional on Debian); the flags for other
netcat variants are probably different.