Geçici bir SSH tüneli kurmak için Bash betiği


133

Cygwin'de, bir Bash betiğinin şunları yapmasını istiyorum:

  1. Uzak sunucuya bir SSH tüneli oluşturun.
  2. Tüneli kullanan yerel olarak bazı işler yapın.
  3. Ardından tüneli kapatın.

Kapatma kısmı beni şaşırttı.

Şu anda kötü bir çözümüm var. Bir kabukta bir tünel oluşturmak için aşağıdakileri çalıştırıyorum:

# Create the tunnel - this works! It runs forever, until the shell is quit.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

Sonra başka bir kabuk penceresinde işimi yapıyorum:

# Do some MySQL stuff over local port 50000 (which goes to remote port 3306)

Son olarak, işim bittiğinde, tüneli öldürmek için ilk mermi penceresini kapatıyorum.

Tüm bunları tek bir komut dosyasında yapmak istiyorum:

# Create tunnel
# Do work
# Kill tunnel

Hangisini öldüreceğimi bilmek için tünel sürecini nasıl takip ederim?


Ssh tünelleme yapmaya yardımcı olacak bir komut dosyası yazdım, şu adresten
Nam Nguyen

Yanıtlar:


326

Bunu bir ssh 'kontrol soketi' ile temiz bir şekilde yapabilirsiniz. Halihazırda çalışan bir SSH süreciyle konuşmak ve onun pid'ini almak için, öldürün vs. 'kontrol soketini' (ana için -M ve soket için -S) aşağıdaki gibi kullanın:

$ ssh -M -S my-ctrl-socket -fnNT -L 50000:localhost:3306 jm@sampledomain.com
$ ssh -S my-ctrl-socket -O check jm@sampledomain.com
Master running (pid=3517) 
$ ssh -S my-ctrl-socket -O exit jm@sampledomain.com
Exit request sent. 

My-ctrl-soketinin oluşturulan gerçek bir dosya olacağını unutmayın.

Bu bilgiyi OpenSSH posta listesindeki çok RTFM yanıtından aldım .


7
Bu, şu ana kadar konuyla ilgili gördüğüm en iyi cevap. Çok teşekkür ederim, kabul edilen olmalı. Bunu Vagrant sanal makineme bağlanmak ve FlywayDB güncelleme komut dosyasını çalıştırmak için kullanıyorum.
Christian

2
Görünüşe göre kontrol soketleri her yerde çalışmıyor. Örneğin, Operation not permitteddrone.io sürekli entegrasyon ortamına giriyorum:muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted
Mikko

Peki my-ctrl-socketbu çalıştırıldıktan sonra dosyaya ne olacak ? Ben ne zaman ls -lageçerli klasörde artık dosyayı göremiyorum.
sachinruk

2
Bir komut dosyasında kullanırsanız, kontrol soketinin kullanılabilir olması için birkaç saniye beklemeniz gerekir. Benim çözümüm:while [ ! -e $ctrl_socket ]; do sleep 0.1; done
Adam Wallner

bunu yaptığımda alıyorum open failed: administratively prohibited: open failedve tüneli
Andy Ray

21

SSH'ye -f seçeneğiyle arka planda çalışmasını söyleyebilirsiniz, ancak $! İle PID'yi alamazsınız. Ayrıca, tüneli kullanmadan önce betiğinizin keyfi bir süre boyunca uyumasını sağlamak yerine -o ExitOnForwardFailure = yes ile -f kullanabilirsiniz ve SSH kendisini arka plana yerleştirmeden önce tüm uzak bağlantı noktalarının başarıyla kurulmasını bekler. PID'yi almak için ps çıktısını grep edebilirsiniz. Örneğin kullanabilirsiniz

...
ssh -Cfo ExitOnForwardFailure=yes -NL 9999:localhost:5900 $REMOTE_HOST
PID=$(pgrep -f 'NL 9999:')
[ "$PID" ] || exit 1
...

ve istediğiniz PID'yi aldığınızdan emin olun


Farkında olmayabilirsiniz, ama bu bir çeşit dahidir. SSH tüneli PID'lerini izlemenin bir yolunu arıyordum ve neredeyse systemd hizmet betiklerini kullanıyordum. Artık değil: Tünel adını kullanarak ihtiyacım olan SSH sürecini geliştirebilirim. Bu fikir bir şekilde beni tamamen atladı. Çok teşekkürler!
aexl

19
  • Bir komut satırı bayrağıyla diğer tarafta bir kabuk oluşturup oluşturmamayı (tüneli açmanız yeterlidir) (bunu zaten yaptığınızı görüyorum) ile ssharka plana geçmeyi söyleyebilirsiniz .&-N
  • PID'yi şununla kaydedin: PID=$!
  • İşini yap
  • kill $PID

DÜZENLEME: $ düzeltildi mi? $ için! ve &


3
Senaryom KILL'e ulaşmadan bir yerde ölürse, bunu halletmek için dikkatli olmalıyım.
jm.

2
@jm: trap 'kill $PID' 1 2 15birçok komut dosyası hatası durumunu kapsar.
Norman Ramsey

3
Bunun güvenilir bir şekilde çalışması için, tüneli oluşturduktan SONRA, ancak kullanmadan önce biraz "uyumam" gerekti.
jm.

@NormanRamsey Demek istediğini düşünüyorum trap "kill $PID", çünkü bash yalnızca çift tırnaklı dizelerdeki değişkenleri enterpolasyona
uğratacak

1
@JuanCaicedo Ayrım, yalnızca PIDdeğişken daha sonra yeniden tanımlanırsa önemli olacaktır . Değişken, trapyerleşik çağrıldığında (OP'nin yaklaşımı) veya bir sinyal yakalandığında (yaklaşımınız) genişletilir ; her iki yaklaşım da burada aynı sonucu verir.
Witiko

4

Ayrı görevler için yeni bir kabuk başlatmayı tercih ederim ve genellikle aşağıdaki komut kombinasyonunu kullanırım:

  $ sudo bash; exit

ya da bazen:

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

Bu komutlar, tüm işimi yapabileceğim iç içe geçmiş bir kabuk oluşturur; Bitirdiğimde CTRL-D'ye basıyorum ve ana kabuk da temizleniyor ve çıkıyor. İç içe geçmiş kabuktan çıkış yaptığınızda tüneliniz kapanacak şekilde parçadan bash;hemen önce ssh tünel komut dosyanızı kolayca atabilirsiniz kill:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

Çok ilginç. Bu, "tuzak" sorununu daha iyi çözebilir. Denemek zorunda kalacak.
jm.

2

Arka plana koymak ve yaparken kimliğini almak için bir uç sshile başlatabilirsiniz &. O killzaman işin bittiğinde o id'den bir tane yapmalısın.


Ve işareti ("&") kullanıp kullanmadığınıza dikkat edin. Kendiniz için kurulan gerçek bağlantıyı belirlemeniz gerekeceği için bu çirkin bir yaklaşımdır. Gerçek bağlantının tam olarak kurulmasını beklemeyen daha fazla kodun yürütülmesine neden olabilir. Ayrıca komut dosyası bozulursa bağlantı otomatik olarak kesilmez.
Jonathan

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.