Bash script เพื่อตั้งค่าอุโมงค์ SSH ชั่วคราว


133

ใน Cygwin ฉันต้องการสคริปต์ Bash เพื่อ:

  1. สร้างอุโมงค์ SSH ไปยังเซิร์ฟเวอร์ระยะไกล
  2. ทำงานบางอย่างในพื้นที่ที่ใช้อุโมงค์
  3. จากนั้นปิดอุโมงค์

ส่วนการปิดเครื่องทำให้ฉันงง

ปัจจุบันฉันมีวิธีแก้ง่อย ในหนึ่งเชลล์ฉันเรียกใช้สิ่งต่อไปนี้เพื่อสร้างอุโมงค์:

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

จากนั้นในหน้าต่างเชลล์อื่นฉันทำงานของฉัน:

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

ในที่สุดเมื่อฉันทำเสร็จแล้วฉันก็ปิดหน้าต่างเชลล์แรกเพื่อฆ่าอุโมงค์

ฉันต้องการทำสิ่งนี้ทั้งหมดในสคริปต์เดียวเช่น:

# Create tunnel
# Do work
# Kill tunnel

ฉันจะติดตามกระบวนการอุโมงค์ได้อย่างไรจึงจะรู้ว่าควรฆ่าคนไหน?


ฉันเขียนสคริปต์ที่จะช่วยในการทำ ssh tunneling คุณสามารถตรวจสอบได้ที่: github.com/gdbtek/ssh-tunneling.git
Nam Nguyen

คำตอบ:


326

คุณสามารถทำได้อย่างหมดจดด้วยซ็อกเก็ตควบคุม ssh หากต้องการพูดคุยกับกระบวนการ SSH ที่รันอยู่แล้วและรับมันเป็น pid ให้ฆ่ามันเป็นต้นใช้ 'ซ็อกเก็ตควบคุม' (-M สำหรับมาสเตอร์และ -S สำหรับซ็อกเก็ต) ดังต่อไปนี้:

$ 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-socket จะเป็นไฟล์จริงที่สร้างขึ้น

ผมได้รับข้อมูลนี้จากมาก RTFM การตอบกลับใน OpenSSH รายการทางไปรษณีย์


7
นี่เป็นคำตอบที่ดีที่สุดที่ฉันเคยเห็นในหัวข้อนี้ ขอบคุณมากควรเป็นที่ยอมรับ ฉันใช้สิ่งนี้เพื่อเชื่อมต่อกับ Vagrant VM ของฉันและเรียกใช้สคริปต์อัพเดต FlywayDB
คริสเตียน

2
เห็นได้ชัดว่าซ็อกเก็ตควบคุมไม่ทำงานทุกที่ ตัวอย่างเช่นฉันได้รับOperation not permittedสภาพแวดล้อมการรวมอย่างต่อเนื่องของ drone.io:muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted
Mikko Ohtamaa

แล้วจะเกิดอะไรขึ้นกับmy-ctrl-socketไฟล์หลังจากนี้เรียกใช้? เมื่อฉันทำls -laในโฟลเดอร์ปัจจุบันฉันไม่สามารถมองเห็นไฟล์ได้อีกต่อไป
sachinruk

2
หากคุณใช้ในสคริปต์คุณต้องรอให้ซ็อกเก็ตควบคุมสองสามวินาทีจึงจะพร้อมใช้งาน วิธีแก้ปัญหาของฉัน:while [ ! -e $ctrl_socket ]; do sleep 0.1; done
Adam Wallner

เมื่อฉันทำสิ่งนี้ฉันได้รับopen failed: administratively prohibited: open failedและฉันไม่คิดว่ามันจะเปิดอุโมงค์
Andy Ray

21

คุณสามารถบอก SSH ให้เป็นพื้นหลังได้ด้วยตัวเลือก -f แต่คุณจะไม่ได้รับ PID ด้วย $! นอกจากนี้แทนที่จะให้สคริปต์ของคุณเข้าสู่โหมดสลีปโดยพลการก่อนที่คุณจะใช้อุโมงค์คุณสามารถใช้ -o ExitOnForwardFailure = ใช่ด้วย -f และ SSH จะรอให้พอร์ตระยะไกลทั้งหมดถูกสร้างขึ้นก่อนที่จะวางตัวเองในพื้นหลัง คุณสามารถ grep เอาต์พุตของ ps เพื่อรับ PID ตัวอย่างเช่นคุณสามารถใช้

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

และค่อนข้างมั่นใจว่าคุณได้รับ PID ที่ต้องการ


คุณอาจไม่รู้ตัว แต่นี่คืออัจฉริยะ ฉันกำลังค้นหาวิธีติดตาม SSH tunnel PID และเกือบจะจบลงด้วยการใช้สคริปต์บริการ systemd ไม่อีกต่อไป: ฉันสามารถ grep กระบวนการ SSH ที่ฉันต้องการโดยใช้ชื่ออุโมงค์ ความคิดนี้ข้ามฉันไปโดยสิ้นเชิง ขอบคุณมาก!
aexl

19
  • คุณสามารถบอกsshให้เข้าสู่พื้นหลัง&และไม่สร้างเชลล์ในอีกด้านหนึ่ง (เพียงแค่เปิดอุโมงค์) ด้วยแฟล็กบรรทัดคำสั่ง (ฉันเห็นว่าคุณทำสิ่งนี้แล้วด้วย-N)
  • บันทึก PID ด้วย PID=$!
  • ทำสิ่งต่างๆของคุณ
  • kill $PID

แก้ไข: แก้ไข $? ถึง $! และเพิ่ม &


3
ถ้าสคริปต์ของฉันตายไปที่ไหนสักแห่งก่อนที่จะถึง KILL ฉันต้องระวังให้ดี
jm.

2
@jm: trap 'kill $PID' 1 2 15จะครอบคลุมหลายกรณีของความล้มเหลวของสคริปต์
Norman Ramsey

3
เพื่อให้ทำงานได้อย่างน่าเชื่อถือฉันต้อง "นอน" สักหน่อยหลังจากสร้างอุโมงค์ แต่ก่อนที่จะใช้
jm.

@NormanRamsey ฉันคิดว่าคุณหมายถึงtrap "kill $PID"เพราะ bash จะสอดแทรกตัวแปรภายในสตริงที่ยกมาคู่เท่านั้น
JuanCaicedo

1
@JuanCaicedo ความแตกต่างจะมีความสำคัญPIDก็ต่อเมื่อตัวแปรถูกกำหนดใหม่ในภายหลัง ตัวแปรจะถูกขยายเมื่อtrapมีการเรียกบิวท์อิน (แนวทางของ OP) หรือเมื่อสัญญาณถูกจับได้ (แนวทางของคุณ) ทั้งสองวิธีให้ผลลัพธ์เดียวกันที่นี่
Witiko

4

ฉันชอบเปิดเชลล์ใหม่สำหรับงานแยกต่างหากและฉันมักใช้ชุดคำสั่งต่อไปนี้:

  $ sudo bash; exit

หรือบางครั้ง:

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

คำสั่งเหล่านี้สร้างเชลล์ที่ซ้อนกันซึ่งฉันสามารถทำงานทั้งหมดได้ เมื่อฉันทำเสร็จแล้วฉันกด CTRL-D และพาเรนต์เชลล์ล้างและออกเช่นกัน คุณสามารถโยนbash;เข้าไปในสคริปต์อุโมงค์ ssh ของคุณก่อนkillส่วนหนึ่งได้อย่างง่ายดายเพื่อที่เมื่อคุณออกจากระบบเชลล์ที่ซ้อนกันอุโมงค์ของคุณจะถูกปิด:

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

น่าสนใจมาก. วิธีนี้อาจจัดการปัญหา "กับดัก" ได้ดีขึ้น จะต้องลอง.
jm.

2

คุณสามารถเริ่มต้นsshด้วย&การสิ้นสุดเพื่อวางไว้ในพื้นหลังและคว้ารหัสเมื่อทำ จากนั้นคุณต้องทำkillid นั้นเมื่อคุณทำเสร็จแล้ว


ระวังถ้าใช้เครื่องหมายและ ("&") เป็นแนวทางที่น่าเกลียดเนื่องจากคุณจะต้องพิจารณาการเชื่อมต่อจริงที่สร้างขึ้นด้วยตัวคุณเอง อาจทำให้มีการเรียกใช้โค้ดเพิ่มเติมซึ่งไม่ได้รอให้การเชื่อมต่อจริงเสร็จสมบูรณ์ นอกจากนี้การเชื่อมต่อจะไม่ถูกฆ่าโดยอัตโนมัติหากสคริปต์หยุดทำงาน
Jonathan

2

อีกทางเลือกหนึ่งที่เป็นไปได้ - หากคุณสามารถติดตั้งแพ็คเกจที่คาดหวังได้คุณควรจะสามารถเขียนสคริปต์ได้ทั้งหมด ตัวอย่างดีๆที่นี่: http://en.wikipedia.org/wiki/Expect

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.