How to remotely write to a file using multi-hop SSH

0

Questions like How to remotely write to a file using SSH are about a direct SSH.

But I am reaching the end of a reverse tunnel which ends on intermediateserver. That is, I'm ssh'ing to one machine through another. And I want to write to a file on the distant machine. The following fails; it ends up writing on the intermediateserver!

ssh -A -t  intermediateserver ssh -A -t -p 666 localhost  "echo 30 > tmp"

The fact that there's a reverse ssh tunnel in there probably doesn't make things more complicated, so more generally, I am sitting on homeserver and going through intermediateserver to distantserver.

(In my case here, distant server appears to intermediate server internally on its port 666, due to a preexisting reverse tunnel) .

CPBL

Posted 2018-11-02T05:28:11.437

Reputation: 103

If you’re sshing from “intermediateserver” to localhost, then you’re still on “intermediateserver”.  Where are you connecting to a distant machine?  You say that the tunnel ends on “intermediateserver”, so what machine is more distant than the end of the line? – Scott – 2018-11-02T05:47:56.183

I've edited for clarity. My situation is probably a bit more complex than relevant to the question. – CPBL – 2018-11-02T16:09:02.467

Answers

2

For each hop, you'll need a layer of quoting. Essentially, ssh server some command foo bar ends up running $SHELL with the arguments -c and some command foo bar, so:

  1. The first layer of quotes is stripped by your local shell, where you ran the ssh command, and
  2. Each subsequent hop invokes a shell which strips another layer of quoting.

This in turn means that shell operations like variable expansion, redirection, wildcard expansion all need extra quoting to prevent intermediate shells from acting on them.

For example, if I had the files foo-a and foo-? in my home directory:

$ touch foo-a foo-\?
$ echo foo-*
foo-? foo-a
$ ssh Server1 echo foo-*
foo-? foo-a foo-a # foo-* expanded locally to foo-? foo-a, foo-? expanded again remotely
$ ssh Server1 'echo foo-*'
foo-? foo-a       # foo-* expanded remotely to foo-? foo-a
$ ssh Server2 ssh Server1 'echo foo-*'
foo-? foo-a foo-a # foo-* expanded remotely to foo-? foo-a, foo-? expanded again remotely in the next hop
$ ssh Server2 "ssh Server1 'echo foo-*'"
foo-? foo-a       # foo-* expanded in the last hop

It would be simpler if you used a ProxyCommand or ProxyHost. This will establish a tunnel between the two systems, instead of creating a baklava of shells executing commands:

~ ssh -o ProxyCommand='ssh Server2 nc %h %p' Server1 'echo foo-*'
foo-? foo-a

~ ssh -J Server2 Server1 'echo foo-*'
foo-? foo-a

muru

Posted 2018-11-02T05:28:11.437

Reputation: 975

I only know of two options for quoting things: ' and ". Can I re-use these, in an alternating way, for further layers? ie does the quote-unwrapping peel off the very end and very beginning? (Anyway I will try your better approach) – CPBL – 2018-11-02T16:12:06.053

muru: Our code of conduct says “be nice”, not “be sweet”.  What does baklava have to do with this?   :-)   ⁠ – Scott – 2018-11-02T18:23:34.957

@CPBL unfortunately, no. "l1 'l2 "l3 'l4' 3" 2' 1" is seen by the first shell as three strings: l1 'l2 l3, l4, 3 2' 1. It might be possible to get up to three layers of quoting by using backslashes as well, but that way leads to insanity. – muru – 2018-11-02T19:06:05.833

@Scott reminded me of something I saw on Jeff Atwood's blog a while ago: See #14 in https://blog.codinghorror.com/new-programming-jargon/

– muru – 2018-11-02T19:07:14.943

Any chance you could provide the ProxyCommand example using my situation in which the destination is a port on the intermediate? I am still stuck interpreting these cryptic bits – CPBL – 2018-11-03T04:11:35.763

@CPBL something like: ssh -o ProxyCommand='ssh intermediateserver nc %h %p' -p 666 localhost "echo 30 > tmp" – muru – 2018-11-03T05:43:14.703

@muru That gives me "bash: nc: command not found" . – CPBL – 2018-11-03T15:42:02.277