SSH: Cung cấp thêm các fds đường ống khác ngoài stdin, stdout, stderr


12

Khi kết nối với một máy chủ với SSH, thường là ba "ống" được cung cấp giữa chủ và khách, cho stdin, stdout, và stderr.

Có một tùy chọn dòng lệnh để tạo chuyển tiếp cho các mô tả tệp bổ sung ( 3và trở đi) không?

Ví dụ, tôi muốn làm

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

sẽ in 'test' cho bộ mô tả tệp được mở cục bộ 10.


2
Có lẽ không phải không có các chỉnh sửa nguồn khó khăn, được đưa ra các closefrom(STDERR_FILENO + 1)cuộc gọi khác nhau theo mã nguồn OpenSSH. Bạn đang cố gắng làm gì để đòi hỏi điều này?
thrig

Giao thức hỗ trợ đường hầm các luồng bổ sung bên cạnh stdin/ out/ err, nhưng AFAIK, không có máy chủ / máy khách nào cung cấp hỗ trợ theo bất kỳ cách nào có tính năng đó.
salva

@thrig Không phải OP, và đã lâu rồi, nhưng trong trường hợp bạn vẫn tò mò điều này có thể hữu ích cho điều gì, thì điều tôi hy vọng tìm thấy ở đây là manh mối về cách chuyển qua ssh, một kịch bản cho bash và stdin cho kịch bản đó. Một cái gì đó giống với:infinite-output-cmd | ssh user@host bash /proc/self/fd/3 3< local-script-to-execute-remotely.sh
JoL

@thrig Nó xảy ra với tôi rằng một cái gì đó --forwardfdthậm chí không cần thiết. sshcó thể kiểm tra các bộ mô tả tệp đang mở là gì trước khi mở bất kỳ thứ gì khác và tự động chuyển tiếp chúng đến cùng một bộ mô tả tệp ở phía xa. Nó có thể hoàn toàn minh bạch như ví dụ của tôi. Tôi tự hỏi làm thế nào khó khăn để vá sshcho điều đó. Giống như bạn đã nói, nó có thể là khó khăn tùy thuộc vào lý do đằng sau những lý do closefrom(STDERR_FILENO + 1).
JoL

Câu trả lời:


6

Bạn có thể làm điều này bằng cách sử dụng chuyển tiếp ổ cắm, có sẵn kể từ openssh-6.7. Đây là một số loại ống. Kỹ thuật này được mô tả ví dụ ở đây: http://www.25thandclement.com/~william/projects/streamlocal.html

Bạn sẽ đạt được tuyến đường hai chiều cho dữ liệu của bạn. Có ví dụ với mysql:

Proxy kết nối máy khách MySQL trên một máy chủ từ xa đến phiên bản cục bộ của bạn:

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

1

Tôi chắc chắn rằng nó nên có thể. Tôi chỉ có thể đề xuất một bản hack trong đó bạn sử dụng các kết nối ssh bổ sung để mỗi người mang một cặp mô tả tệp khác. Vd 2.

Sau đó, ssh thực sự được thực hiện, và trên điều khiển từ xa, nó kết nối từ xa fds 5 và 6 với stdin và stdout của ssh khác.

Cũng giống như một ví dụ, tập lệnh này chuyển một trang man được nén vào điều khiển từ xa, mở khóa và chạy nó thông qua con người. Stdin và stdout của ssh thực vẫn có sẵn cho những thứ khác.

#!/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

Vấn đề với câu trả lời từ @jakuje là: nó chỉ hoạt động với các socket , nhưng bạn không thể sử dụng các công cụ UNIX tiêu chuẩn để mong đợi các tệp với chúng:

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

bash: /tmp/sock.remote: Không có thiết bị hoặc địa chỉ như vậy

Ngoài ra, có vấn đề là tệp ổ cắm cục bộ không bị xóa trên máy chủ từ xa; Khi tiếp theo bạn chạy cùng một lệnh, bạn sẽ nhận được cảnh báo và ổ cắm không được tạo lại chính xác. Bạn có thể cung cấp tùy chọn -o StreamLocalBindUnlink=yesđể sshbỏ liên kết mà ổ cắm cũ, nhưng trong các thử nghiệm của tôi đó là không đủ; bạn cũng phải chỉnh sửa bạn sshd_configđể chứa StreamLocalBindUnlink=yestùy chọn đó hoạt động.

Nhưng bạn có thể sử dụng socathoặc netcathoặc bất kỳ công cụ tương tự khác hỗ trợ socket địa phương UNIX ( netcat-traditionalKHÔNG đủ!) Để sử dụng các chuyển tiếp ổ cắm địa phương để chuyển tập tin:

# 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'

Bạn cũng có thể chạy các lệnh tương tác, trong trường hợp đó bạn nên sử dụng ssh -tđể phân bổ TTY.

Vấn đề với giải pháp này là bạn phải mã hóa cứng các đường dẫn của các socket cục bộ UNIX: Về mặt cục bộ, đây không phải là vấn đề nhiều như bạn có thể đưa $$vào đường dẫn để làm cho nó trở thành duy nhất cho mỗi tiến trình hoặc thư mục tạm thời, nhưng trên từ xa, tốt hơn hết bạn không nên sử dụng thư mục có thể ghi trên thế giới /tmp/như trong ví dụ của tôi. Thư mục cũng phải tồn tại khi sshphiên bắt đầu. Và inode ổ cắm sẽ vẫn còn ngay cả sau khi phiên được đóng lại, vì vậy sử dụng cái gì đó như "$ HOME / .ssh. $$" sẽ làm lộn xộn thư mục của bạn với các nút chết theo thời gian.

Bạn cũng có thể sử dụng các socket TCP bị ràng buộc localhost, điều này sẽ giúp bạn tránh làm lộn xộn các hệ thống tệp của bạn với các nút chết, nhưng ngay cả với chúng, bạn vẫn phải gặp vấn đề khi chọn số cổng không sử dụng (duy nhất). Vì vậy, vẫn không lý tưởng. ( sshcó mã để phân bổ động các cổng, nhưng tôi không tìm thấy cách nào để lấy thông tin đó trên máy chủ từ xa.)

Có lẽ giải pháp đơn giản nhất để sao chép tệp là sử dụng chức năng chia sẻ kết nối tích hợp của ssh và thực hiện một lệnh scphoặc sfrptrong khi phiên tương tác của bạn vẫn chạy song song. Xem Sao chép tệp trở lại hệ thống cục bộ bằng ssh .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.