Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Trying to script as clean as possible, I wonder if there is some solution for the following situation:

One Linux server running sshd and one android device, with dropbear ssh client and rsync installed (no server).

I'm writing a script to be run remotely with a cron that backups the android memory to the linux server. The cron calls something like:

ssh remoteuser@linuxserver -i path_to_rsa_key runthisscript.sh

runthisscript.sh performs a few things with the existent data, and, what I want to do, in the middle of the script, is to rsync from the android device back to the server, taking advantage of the ssh connection that is already opened (as there is no sshd running on the android).

I've developed other solutions, like breaking my server script in several parts and calling them one after another, with the rsync (android to server direction) in the middle, but I was looking for a more elegantly implemented solution (single script, most of the work done in the server side).

Ideas?

share|improve this question
    
oreilly.com/pub/h/38 –  dmourati Jan 4 at 22:00

2 Answers 2

I assume you want to be able to connect from anywhere, so you can't garantee what public IP address the tablet will be on (or even if that will allow connections to the tablet from the server, as it is unlikely to be a public address), otherwise you should install a SSH deamon and ash rsync to connect that way. Otherwise, a "reverse tunnel" may be what you are looking for.

If your SSH client on the Android device supports reverse port forwarding then look into using that to build a tunnel. For instance with openssh you can specify -R 2222:127.0.0.1:22 on the command line which would mean things on the server can connect to a SSHd server on the tablet (listening on port 22 on 127.0.0.1 as far as the tablet is concerned) by connecting to port 2222 on 127.0.0.1 (it is important to realise that from the code on the server's PoV 127.0.0.1 is the server, the 127.0.0.1 in the command line is relative the the SSH client). So if that works you can in your server script run something like rsync user@127.0.0.1:/path/to/stuff/on/tablet /path/to/destination/on/server -e 'ssh -p 2222' -a --compress. The -e option is used here to specify the non-standard port for SSH to connect to.

Some more detailed notes on the above (sorry, this is bit of a "mind dump" and may not be well organsied, though hopefully it'll help you experiemnt and/or lookup useful examples elsewhere):

  • This is called a reverse or remote tunnel because it is more usual to setup redirects fomr the client to the server (not the server to the client as you need here). A local tunnel (client-side to something server-side) is setup using the -L option instead of -R (at least with OpenSSH, check your server's documentation for confirmation).
  • You can give many -R and/or -L options on the same command line with OpenSSH, so you can setup more than one tunnel in either/any direction using a single SSH connection.
  • You may need GatewayPorts yes or similar specified in the server's sshd_config for reverse tunnels to work at all. Check your SSHd implementation's documentation for details.
  • It doesn't matter where the tablet calls from: the tunnel created by the port forward will always point (via the SSH connection) back to its SSH client. You could even point it at some other local resource with a forward like -R 8888:192.168.42.42:80 which will mean connections to 127.0.0.1:8888 on the server will go through the SSH tunnel and hit port 80 on what-ever machine answers to 192.168.42.42 on the network the tablet is currently on (this could even be another remote machine in a completely different location).
  • You will need the rsync client on the tablet to the server can run it over SSH via the tunnel.
  • The above example uses a non-standard port as SSHd is likely to be listening on port 22 on all interfaces on the server. If you are connecting to the server as root then using a port number below 1024 (i.e. 222 instead of 2222) is safer, though you should avoid being connect to remote resources as root where possible. Listending on a port below 1024 is blocked for non-privelaged users by default on Uinx-a-like systems.
  • If you don't want to run a SSH daemon on the tablet, you could instead run an instance of rsync in daemon mode instead. The port forward would then be something like 537:127.0.0.1:537 or (if you are running rsync in server mode on the server already so port 537 is taken, something like 5537:127.0.0.1:537 and add -p 5537 to the rsync command to tell it the server is not in the standard place).
  • If your server's SSHd does not listen on port 22 on all the server's interfaces/addresses, then you could use 22 instead of a non-standard port by specifying that the tunnel should attact to a specific interface by adding that address to the start of the -R part, like so: -R 192.168.1.1:22:127.0.0.1:22. The bind address is relative to the server so does not need to be something that is publically routable (in fact an address on a dummy interface even the rest of the local LAN can't see would work). You definitely need GatewayPorts on for this to work with OpenSSH. If you don't need GatewayPorts on (i.e. if using 127.0.0.1 server-side and a non-standard port and that works with your server's SSHd implementation without GatewayPorts yes or equivelant) then leave it off: it is safer this way.
  • I've assumed IPv4 in all of the above. If your client and server both support it and your networks at each end are appropriately configued, IPv6 addressing will work just as well.

Tunnels through SSH ocnfigured this way can be very powerful once you have played with them and work out what it possible and how to do it, assuming your client and server SSH/SSHd implementations support it all.

share|improve this answer

You may have a look at --rsh/-e argument of rsync.

You can replace the rsh with cat or something similar. But you have to add a script at android side which sends the output of your server script to a shell.

Android side:

socat 'EXEC:/bin/bash' 'TCP-LISTEN:20000' &
ssh remoteuser@linuxserver -i path_to_rsa_key -R 20000:127.0.0.1:20000 runthisscript.sh

helper.sh:

#!/bin/sh
host=$2
port=$1
shift 2
{
    echo exec "$@"
    socat 'STDIN' 'STDOUT'
} | socat '-' "TCP:$host:$port"

runthisscript.sh:

rsync -e './helper.sh 20000' --blocking-io <SRC> <DST>
share|improve this answer
    
Can you specify a bit more? –  Abilio Marques Jan 4 at 22:24
    
I have edited the answer. But its not complete. If you want better security, you should bind bash directly to stdio of ssh. It's not a good idea to bind bash to an ip port, even a local port. And consider add more arguments to socat to do non-blocking io so that it could be faster. –  Sherwood Wang Jan 5 at 5:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.