2

I have a raspberry pi that I connected to my home network, but each time I reboot it the IP address changes. Instead of calling ssh user@ipaddress each time, I want to run a bash script to know which is the address that works.

I'm trying to run ssh user@ipaddress several times changing the last number of the IP address. I don't know how bash works, so I attempted to make a file .sh to do it:

for i in {1..100}
do
  call=`ssh [email protected].$i`
  if [['$call'==*'user'*]]; then
    echo "$i"
  else
    :
  fi
done

My problems are:

  • I don't print anything
  • It is stuck in the first call and it doesn't make the loop

So I want to know if there is a bash function to pass over a command when it's another device, because I know the name of my user and I only need to find my user name in the command output of the first line, and don't need to wait for more output.

10
  • 3
    I don't really understand. For one thing, your IP won't have 7 groups of numbers, so 192.168.0.1.$i won't work. Next, you aren't actually running any command, you're opening a remote shell. So if it works, it will just stay there. Please edit your question and explain what you want a bit more clearly. Are you trying to find the IP of the only computer on the network to which you are allowed ssh? So that if you can ssh, then you want to print the IP you found?
    – terdon
    Jan 29, 2021 at 17:53
  • I have a raspberry pi that I connected to my home network, but each time I reboot it the last number changes of value, so instead of calling ssh user@ipadres each time, I want to run a bash script to know which is the final number that works.
    – iam_agf
    Jan 29, 2021 at 17:54
  • 4
    Oh wow. Then this is a really, really slow and complex way of doing it. You should either set up the Pi to have a static IP or set up a local DNS server to resolve hostnames.
    – terdon
    Jan 29, 2021 at 17:58
  • 1
    The problem is that I don't own the network to make it static. Also sometimes I go to the school to practice by myself with it and that's the only way I could also do it there.
    – iam_agf
    Jan 29, 2021 at 18:01
  • 5
    You don't need to own the network, you only need to own the Pi. Just search for "raspbian static ip".
    – terdon
    Jan 29, 2021 at 18:02

6 Answers 6

9

The Right Way® to do this, would be to either set up the Pi to have a static IP so it doesn't change on reboot or to set up a local DNS server to resolve the hostname. Setting up the static IP is by far the simplest. You can find dozens of tutorials if you just search for "raspbian static IP". Here's one: https://thepihut.com/blogs/raspberry-pi-tutorials/how-to-give-your-raspberry-pi-a-static-ip-address-update

Now, your script doesn't work for a multitude of reasons. First of all, this will never work:

call=`ssh [email protected].$i`

If the machine doesn't let you in or isn't accessible, then it will print an error, but that error is printed to standard error, not standard output, therefore $call will be empty. If it does work and you do ssh into the machine, then you will be logged in and, once more, $call will be empty since there is nothing returned.

In any case, your if is a syntax error. This:

if [['$call'==*'user'*]]; then

should be this:

if [[ "$call" == *user* ]]; then

You need spaces after and before the [[ and ]], and if you put a variable in single quotes ('$call'), then the variable isn't expanded:

$ echo '$call'
$call

What you probably want to do is to try to log in, run a command, and if that runs you store the ip. Something like this:

#!/bin/bash
for i in {1..100}
  do
    ## try to run a command and, if it works, we know the ip.
    ## you can use the command 'true' for this
    if ssh [email protected].$i true; then
      echo "The IP is 192.168.0.1.$i"
      break
    fi
done

This, however, is really, really inefficient and slow. Don't do this. Just set up a static IP. Some other options that might help are:

  1. Get the list of active IPs on the network

     nmap -sP 192.168.0.*
    
  2. Use ping instead of ssh to see which machine is up:

     for i in {1..100}
     do
         if ping -c1 192.168.0.$i 2>/dev/null; then
           echo "The first IP that is UP is 192.168.0.1.$i"
           break
         fi
     done
    

But really, if you need help setting up a static IP, then please post a new question about that. This just isn't a good solution to your problem.

7
  • 1
    Or use mDNS (avahi) to discover the IP address. The remote must run at least the server and be configured, the local must have at least the client. It is a sort of distributed (more than normal) local DNS. You can also try telling your router's DHCP to allocate a static IP address. Jan 29, 2021 at 23:10
  • your "right way" assumes the OP owns the network, this comment shows it isn't the case. The right way is to have the Pi transmit some sort of beacon, and this answer gives a nice prepackaged way of doing that.
    – Grump
    Jan 30, 2021 at 12:33
  • @Grump there is no need to "own the network". You set a static OP from the Pi itself, no need for any access to the router or other network infrastructure. Same for setting up a local resolver. Yes, you can set static IPs from the network's router, especially with devices designed for home use, but that is not the only way nor is it the simplest way. The answer you linked to (which sadly doesn't explain how only what), is indeed a very good way. It's one of the things I called the "right way": setting up a system that can resolve the hostname to an IP.
    – terdon
    Jan 30, 2021 at 16:43
  • I refer you again, @terden, to this comment -- setting a static IP on the Pi isn't appropriate in this case, as it is likely to conflict with a later dynamic IP allocation.
    – Grump
    Jan 30, 2021 at 18:19
  • @Grump please actually read my answer. The first thing I say is that the best way is to either set up a static IP or use a system like what you describe which will resolve hostnames to IPs. So please stop trying to convince me that setting up a system to resolve hostnames to IPs is a good idea. I know it is, I say so and I completely agree.
    – terdon
    Jan 30, 2021 at 18:31
6

Use mDNS (avahi) to discover the IP address. The remote must run at least the server and be configured, the local must have at least the client. It is a sort of distributed (more than normal) local DNS. You can also try telling your router's DHCP to allocate a static IP address.

3
  • I'm pretty sure Raspberry Pi OS includes & sets up avahi by default (at least it did when it was called Raspbian). Depending on what you're trying to connect from, you might need to install it (or some other mDNS client) there. On my network, I just use ssh [email protected] ('cause I named mine "pi-0") and it connects me. Jan 30, 2021 at 2:05
  • It would really be great if you could give some guidance on how to do this. I completely agree that this is a great solution, but sadly your answer only hints at how.
    – terdon
    Jan 30, 2021 at 16:44
  • @terdon Sorry. I would have to look it up: what I remember is that you install, then configure to add the service "desktop" or is it "workstation" (mDNS advertises services not IP addresses, but each service is at an IP address). You can use avahi-discover to see what services are advertised on your network. Then ssh host-name.local to connect, with ssh. Jan 30, 2021 at 17:14
3

To quickly connect use masscan to scan the alive host with ssh port:

sudo masscan 192.168.0.1/24 --ports 22 --rate 100000 > alive
awk '{print $6}' alive > file
while read -r line; do  ssh user@"$line"; done < file

More better, a one-liner as suggest @terdon:

ssh user@$(sudo masscan 192.168.0.1/24 --ports 22 --rate 100000 | awk '{print $6}')

masscan is packaged on some linux distributions.

masscan on github

0
3

Don't do it that way if you can help it.

Also, don't run the risk of annoying your school's IT team, so don't mess around with static IP addresses.

You have the advantage of knowing your Pi's MAC address

Iff you

  1. can have your remote system running when you turn the Pi on,
  2. can have tcpdump installed on your remote system
  3. have privileges to run tcpdump
  4. can have the Pi and your remote system running on the same network

You know it's going to send a packet you'll be able to see. Wait for it.

$ sudu tcpdump -ni interface arp and ether src 00:02:00:02:aa:76

Where interface is the network interface on your remote system and 00:02:00:02:aa:76 is the Pi's MAC address

This is the least intrusive method - it does nothing that wouldn't happen anyway, so keeps you off IT's radar.


Iff you
  1. can have arp-scan installed on your remote system

  2. have privileges to run arp-scan

  3. can have the Pi and your remote system running on the same network

then you can ask all the hosts on your network what their MAC addresses are, and look for the Pi

$ sudu arp-scan -li interface -NT 00:02:00:02:aa:76

Again, where interface is the network interface on your remote system and 00:02:00:02:aa:76 is the Pi's MAC address

This is fairly unobtrusive, so shouldn't be noticed by any but the most anal of network admins. NB I've not tried this, (I always have access to tcdump)


If those aren't possible, assuming the Pi lets you, use /etc/dhcp/dhclient-exit-hooks to email you the network configuration every time it changes.

2
  • I like this solution. How can I get the network interface? Or what string running which command is the one that defines it? Is the one in ifconfig?
    – iam_agf
    Jan 30, 2021 at 22:09
  • it varies between distributions @iam_agf , but yes the name of the interface used in ifconfig should be the one. ip addr show | awk '/ inet /{print $NF, $2}' should get it on the systems that use that form
    – Grump
    Jan 31, 2021 at 0:01
2

Setup a webserver on the Pi that returns "This is the Pi of iam_agf". Or even a dynamic page that returns the IP, something like "192.168.0.15 iam_agf". This is to make sure that it is your device and not he printer or coffee machine.

You can use nmap to see which IPs have a webserver running, and then check those to see if the contain your keyword and the IP.

Once you get back an IP, place it in your /etc/hosts file, so you can easily access the pi by name.

Simple check if it works without nmap, might take some time:

for i in $(seq 1 254); do
    curl "http://192.168.0.${i}" | grep iam_igf
done

There's a plugin for nmap called ssh-brute, you can try this with one fixed username and password combination. https://nmap.org/nsedoc/scripts/ssh-brute.html

Also what you were probably looking for initially:

#this will open an ssh connection and wait for you to type stuff:
ssh user@IP

#this will run a command after the connection is open, then close it
ssh user@IP command

# example
ssh user@IP echo ok

# or just use the true command to avoid output
ssh user@IP true

# so this loop might do what you need, (untested, make backups of /etc/hosts first!)
for i in $(seq 1 254); do
    if ssh "[email protected].${i}" true;
    then
        sed -i "/[0-9.]* mypi/d" /etc/hosts
        echo "192.168.0.${i} mypi" >> /etc/hosts
        break
    fi
done

May

1
  • I don't like your sed, I think it needs at least a $ in that regex, and probably a ^ too, and perhaps change the /d to /{d;t} to limit it to only deleting the first it finds. Personally, I'd use s rather than d and finish up with a $ a instead of the echo >>
    – Grump
    Feb 1, 2021 at 1:58
0

A "one and done" fix is to ask the administrator of the DHCP server for a static IP reservation.

The Pi will do DHCP as normal, but the DHCP server will always give it the same IP address, which will be inside the IP Network, but probably outside the range of DHCP addresses issued.

Its between you and the the network administrators to get this approved and implemented - its not a big deal, but does rely on a good working relationship.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .