SSH: ระบุ "ท่อ" fds เพิ่มเติมนอกเหนือจาก stdin, stdout, stderr


12

เมื่อเชื่อมต่อไปยังโฮสต์กับ SSH มักจะสาม "ท่อ" ที่มีให้ระหว่างเจ้าภาพและแขกสำหรับstdin, และstdoutstderr

มีตัวเลือกบรรทัดคำสั่งเพื่อส่งต่อสำหรับตัวอธิบายไฟล์เพิ่มเติม ( 3เป็นต้นไป) หรือไม่?

ตัวอย่างเช่นฉันต้องการทำ

ssh --forwardfd=10:3 remotehost 'echo test >&3'

ซึ่งจะพิมพ์ 'ทดสอบ' ไปยังตัวอธิบายไฟล์ที่เปิดในเครื่อง 10


2
อาจไม่ได้โดยไม่ต้องแก้ไขแหล่งที่มายุ่งยากให้รับclosefrom(STDERR_FILENO + 1)สายต่าง ๆภายใต้รหัสที่มา OpenSSH คุณพยายามทำอะไรที่ต้องการสิ่งนี้
thrig

โปรโตคอลรองรับการขุดอุโมงค์เพิ่มเติมนอกเหนือจากstdin/ out/ errแต่ AFAIK ไม่มีเซิร์ฟเวอร์ / ไคลเอ็นต์ที่ให้การสนับสนุนในลักษณะใด ๆ
salva

@ thrig Not OP และเป็นเวลานาน แต่ในกรณีที่คุณยังสงสัยว่าสิ่งนี้จะเป็นประโยชน์สำหรับสิ่งที่ฉันหวังว่าจะได้พบที่นี่คือเบาะแสเกี่ยวกับวิธีการผ่าน ssh สคริปต์สำหรับทุบตีและ stdin สำหรับสคริปต์นั้น บางสิ่งบางอย่างคล้ายกับ:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL

@thrig มันเกิดขึ้นกับฉันที่บางสิ่งบางอย่างเช่น--forwardfdไม่ควรที่จะต้องการ sshสามารถตรวจสอบสิ่งที่อธิบายไฟล์ที่เปิดอยู่ก่อนที่จะเปิดสิ่งอื่นใดและส่งต่อพวกเขาโดยอัตโนมัติไปที่อธิบายไฟล์เดียวกันในด้านระยะไกล มันอาจจะโปร่งใสเหมือนตัวอย่างของฉัน ผมสงสัยว่ามันยากที่จะแก้ไขsshสำหรับการที่ closefrom(STDERR_FILENO + 1)เช่นเดียวกับที่คุณกล่าวว่ามันอาจจะเป็นเรื่องยุ่งยากขึ้นอยู่กับเหตุผลที่อยู่เบื้องหลังเหล่านั้น
JoL

คำตอบ:


6

คุณสามารถทำได้โดยใช้การส่งต่อซ็อกเก็ตซึ่งสามารถใช้ได้ตั้งแต่ openssh-6.7 นี่คือท่อบางชนิด เทคนิคนี้มีการอธิบายเช่นที่นี่: http://www.25thandclement.com/~william/projects/streamlocal.html

คุณจะได้รับเส้นทางสองทิศทางสำหรับข้อมูลของคุณ มีตัวอย่างด้วย mysql:

การเชื่อมต่อไคลเอนต์ MySQL บนเซิร์ฟเวอร์ระยะไกลไปยังอินสแตนซ์ในพื้นที่ของคุณ:

ssh -R/var/run/mysql.sock:/var/run/mysql.sock \
    -R127.0.0.1:3306:/var/run/mysql.sock somehost 

1

ฉันแน่ใจว่ามันควรจะเป็นไปได้ ฉันสามารถแนะนำการแฮ็กที่คุณใช้การเชื่อมต่อ ssh เพิ่มเติมเพื่อให้แต่ละตัวอธิบายไฟล์อีกคู่ เช่นการพิสูจน์สคริปต์แนวคิดต่อไปนี้เป็น ssh แรกที่รันคำสั่ง dummy (sleep) เพื่อเชื่อมต่อ local fds 5 และ 6 ไปยัง remote stdin และ stdout โดยสมมติว่า fds เหล่านี้เป็นสิ่งที่คุณต้องการเพิ่มใน 0,1 ปกติ 2

จากนั้นจึงสร้าง ssh จริงและบนรีโมตจะเชื่อมต่อรีโมต fds 5 และ 6 กับ stdin และ stdout ของ ssh อื่น ๆ

ตัวอย่างนี้สคริปต์นี้ส่งหน้า man gzipped ผ่านไปยังรีโมตซึ่งคลายซิปและเรียกใช้ผ่าน man stdin และ stdout ของ ssh จริงยังคงมีอยู่สำหรับสิ่งอื่น ๆ

#!/bin/bash
exec 5</usr/share/man/man1/ssh.1.gz 6>/tmp/out6 # pretend need 5 and 6

ssh remote 'echo $$ >/tmp/pid; exec sleep 99999' <&5 >&6 &
sleep 1 # hack. need /tmp/pid to be set

ssh remote '
  pid=$(</tmp/pid) 
  exec 5</proc/$pid/fd/0 6>/proc/$pid/fd/1
  echo start
  gzip -d <&5 | man /dev/stdin >&6
  echo stop
  kill -hup $pid
'
wait
less /tmp/out6

1

ปัญหาเกี่ยวกับคำตอบจาก @jakuje คือ: ใช้งานได้กับซ็อกเก็ตเท่านั้น แต่คุณไม่สามารถใช้เครื่องมือ UNIX มาตรฐานที่คาดหวังไฟล์ได้

ssh -R/tmp/sock.remote:/tmp/sock.local "$HOST" 'LANG=C cat >/tmp/sock.remote'

bash: /tmp/sock.remote: ไม่มีอุปกรณ์หรือที่อยู่ดังกล่าว

ยังมีปัญหาที่ไฟล์ซ็อกเก็ตท้องถิ่นไม่ได้ถูกลบบนโฮสต์ระยะไกล; เมื่อถัดไปที่คุณเรียกใช้คำสั่งเดียวกันคุณจะได้รับคำเตือนและซ็อกเก็ตจะไม่ถูกสร้างขึ้นใหม่อย่างถูกต้อง คุณสามารถให้ตัวเลือก-o StreamLocalBindUnlink=yesเพื่อsshยกเลิกการเชื่อมโยงซ็อกเก็ตเก่านั้น แต่ในการทดสอบของฉันมันไม่เพียงพอ คุณต้องแก้ไขsshd_configให้มีStreamLocalBindUnlink=yesเพื่อให้ตัวเลือกนั้นใช้งานได้

แต่คุณสามารถใช้socatหรือnetcatหรือเครื่องมือที่คล้ายกันอื่น ๆ ที่สนับสนุนระบบปฏิบัติการยูนิกซ์ซ็อกเก็ตท้องถิ่น ( netcat-traditionalคือไม่พอ!) เพื่อใช้ส่งต่อซ็อกเก็ตในท้องถิ่นสำหรับการถ่ายโอนไฟล์:

# start local process listening on local socket, which receives the data when ssh opens the connections and saves it to a local file
nc -l -N -U /tmp/sock.local >/tmp/file.local &
# connect to remote $HOST and pipe the remote file into the remote socket end
ssh \
 -o ExitOnForwardFailure=yes \
 -o StreamLocalBindUnlink=yes \
 -R /tmp/sock.remote:/tmp/sock.local \
 "$HOST" \
 'nc -N -U /tmp/sock.remote </tmp/file.remote'

คุณยังสามารถเรียกใช้คำสั่งแบบโต้ตอบซึ่งในกรณีนี้คุณควรใช้ssh -tเพื่อจัดสรร TTY

ปัญหาเกี่ยวกับวิธีแก้ปัญหานี้คือคุณต้องเขียนโค้ดพา ธ ของซ็อกเก็ต UNIX แบบโลคอล: ในพื้นที่นี่ไม่ใช่ปัญหามากเท่าที่คุณสามารถรวม$$ไว้ในพา ธ เพื่อทำให้เป็นเอกลักษณ์เฉพาะต่อกระบวนการหรือผู้ใช้เป็นไดเรกทอรีชั่วคราว รีโมตเอนด์คุณควรอย่าใช้ไดเร็กตอรี่ที่เขียนได้ทั่วโลก/tmp/อย่างที่ฉันทำในตัวอย่าง ไดเรกทอรีจะต้องมีอยู่แล้วเมื่อsshเริ่มเซสชัน และซ็อกเก็ตไอโหนดจะยังคงอยู่แม้หลังจากปิดเซสชันดังนั้นการใช้บางอย่างเช่น "$ HOME / .ssh. $$" จะทำให้ไดเรกทอรีของคุณยุ่งเหยิงด้วยไอโหนดที่ตายแล้วในช่วงเวลานั้น

คุณยังสามารถใช้ซ็อกเก็ต TCP ที่เชื่อมโยงกับlocalhostซึ่งจะช่วยให้คุณประหยัดจากความยุ่งเหยิงในระบบไฟล์ของคุณด้วย inodes ที่ตายแล้ว แต่ถึงกระนั้นคุณก็ยังมีปัญหาในการเลือกหมายเลขพอร์ตที่ไม่ได้ใช้ ดังนั้นจึงยังไม่เหมาะ ( sshมีรหัสในการจัดสรรพอร์ตแบบไดนามิก แต่ฉันไม่พบวิธีการดึงข้อมูลนั้นบนรีโมตโฮสต์)

อาจเป็นวิธีที่ง่ายที่สุดในการคัดลอกไฟล์คือการใช้ฟังก์ชั่นการแบ่งปันการเชื่อมต่อในตัวของ ssh และเพื่อทำscpหรือsfrpคำสั่งในขณะที่เซสชันการโต้ตอบของคุณยังคงทำงานแบบขนาน ดูการคัดลอกไฟล์กลับไปที่ระบบท้องถิ่นที่มี SSH

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