Xác định cổng được phân bổ động cho OpenSSH RemoteForward


13

Câu hỏi (TL; DR)

Khi gán các cổng động để chuyển tiếp từ xa ( -Rtùy chọn aka ), làm thế nào một tập lệnh trên máy từ xa (ví dụ có nguồn gốc từ .bashrc) xác định cổng nào được OpenSSH chọn?


Lý lịch

Tôi sử dụng OpenSSH (ở cả hai đầu) để kết nối với máy chủ trung tâm của chúng tôi, mà tôi chia sẻ với nhiều người dùng khác. Đối với phiên từ xa của tôi (bây giờ) tôi muốn chuyển tiếp X, ly và pulseaudio.

Điều quan trọng nhất là chuyển tiếp X, sử dụng -Xtùy chọn. Địa chỉ X được phân bổ được lưu trữ trong biến môi trường DISPLAYvà từ đó tôi có thể xác định cổng TCP tương ứng, trong hầu hết các trường hợp. Nhưng tôi hầu như không cần, vì Xlib vinh danh DISPLAY.

Tôi cần một cơ chế tương tự cho ly và pulseaudio. Các khái niệm cơ bản cho cả hai dịch vụ tồn tại, dưới dạng các biến môi trường CUPS_SERVERPULSE_SERVER, tương ứng. Dưới đây là ví dụ sử dụng:

ssh -X -R12345:localhost:631 -R54321:localhost:4713 datserver

export CUPS_SERVER=localhost:12345
lowriter #and I can print using my local printer
lpr -P default -o Duplex=DuplexNoTumble minutes.pdf #printing through the tunnel
lpr -H localhost:631 -P default -o Duplex=DuplexNoTumble minutes.pdf #printing remotely

mpg123 mp3s/van_halen/jump.mp3 #annoy co-workers
PULSE_SERVER=localhost:54321 mpg123 mp3s/van_halen/jump.mp3 #listen to music through the tunnel

Vấn đề là thiết lập CUPS_SERVERPULSE_SERVERchính xác.

Chúng tôi sử dụng chuyển tiếp cổng rất nhiều và do đó tôi cần phân bổ cổng động. Phân bổ cổng tĩnh không phải là một lựa chọn.

OpenSSH có một cơ chế phân bổ cổng động trên máy chủ từ xa, bằng cách chỉ định 0là cổng liên kết để chuyển tiếp từ xa ( -Rtùy chọn). Bằng cách sử dụng lệnh sau, OpenSSH sẽ tự động phân bổ các cổng cho cốc và chuyển tiếp xung.

ssh -X -R0:localhost:631 -R0:localhost:4713 datserver

Khi tôi sử dụng lệnh đó, sshsẽ in như sau STDERR:

Allocated port 55710 for remote forward to 127.0.0.1:4713
Allocated port 41273 for remote forward to 127.0.0.1:631

Có thông tin tôi muốn! Cuối cùng tôi muốn tạo ra:

export CUPS_SERVER=localhost:41273
export PULSE_SERVER=localhost:55710

Tuy nhiên, thông báo "Cổng được phân bổ ..." được tạo trên máy cục bộ của tôi và được gửi tới STDERR, mà tôi không thể truy cập trên máy từ xa. OpenSSH đủ kỳ lạ dường như không có phương tiện để lấy Thông tin về chuyển tiếp cổng.

Làm cách nào để tôi tìm nạp thông tin đó để đưa nó vào tập lệnh shell để thiết lập đầy đủ CUPS_SERVERPULSE_SERVERtrên máy chủ từ xa?


Đường cùng

Điều dễ dàng duy nhất tôi có thể tìm thấy là tăng tính dài dòng sshdcho đến khi thông tin đó có thể được đọc từ nhật ký. Điều này là không khả thi vì thông tin tiết lộ nhiều thông tin hơn mức có thể truy cập được bởi người dùng không phải root.

Tôi đã suy nghĩ về việc vá OpenSSH để hỗ trợ một chuỗi thoát bổ sung in ra một biểu diễn đẹp của cấu trúc bên trong permitted_opens, nhưng ngay cả khi đó là những gì tôi muốn, tôi vẫn không thể truy cập tập lệnh thoát khỏi trình khách thoát khỏi phía máy chủ.


Phải có cách tốt hơn

Cách tiếp cận sau đây có vẻ rất không ổn định và bị giới hạn ở một phiên SSH như vậy cho mỗi người dùng. Tuy nhiên, tôi cần ít nhất hai phiên đồng thời như vậy và những người dùng khác thậm chí nhiều hơn. Nhưng tôi đã cố gắng ...

Khi các ngôi sao được căn chỉnh hợp lý, đã hy sinh một hoặc hai con gà, tôi có thể lạm dụng thực tế sshdkhông phải là người dùng của mình, nhưng bỏ đặc quyền sau khi đăng nhập thành công, để làm điều này:

  • lấy danh sách số cổng cho tất cả các ổ cắm nghe thuộc về người dùng của tôi

    netstat -tlpen | grep ${UID} | sed -e 's/^.*:\([0-9]\+\) .*$/\1/'

  • lấy danh sách số cổng cho tất cả các ổ cắm nghe thuộc quy trình người dùng của tôi bắt đầu

    lsof -u ${UID} 2>/dev/null | grep LISTEN | sed -e 's/.*:\([0-9]\+\) (LISTEN).*$/\1/'

  • Tất cả các cổng nằm trong tập đầu tiên, nhưng không phải trong tập thứ hai có khả năng cao là các cổng chuyển tiếp của tôi và thực sự trừ đi các sản lượng của tập hợp 41273, 557106010; cốc, xung và X, tương ứng.

  • 6010được xác định là cổng X sử dụng DISPLAY.

  • 41273là cổng cốc, vì lpstat -h localhost:41273 -atrả về 0.
  • 55710là cổng xung, vì pactl -s localhost:55710 stattrả về 0. (Nó thậm chí còn in tên máy chủ của khách hàng của tôi!)

(Để thực hiện cài đặt cơ sở I sort -uvà lưu trữ đầu ra từ các dòng lệnh trên và sử dụng commđể thực hiện cơ chế.)

Pulseaudio cho phép tôi xác định ứng dụng khách và, đối với tất cả ý định và mục đích, điều này có thể đóng vai trò là mỏ neo để phân tách các phiên SSH cần tách biệt. Tuy nhiên, tôi đã không tìm thấy một cách để buộc 41273, 557106010với cùng sshdquá trình. netstatsẽ không tiết lộ thông tin đó cho người dùng không root. Tôi chỉ nhận được một -trong các PID/Program namecột nơi tôi muốn đọc 2339/54(trong trường hợp đặc biệt này). Rất gần ...


fwiw, chính xác hơn để nói rằng netstatsẽ không hiển thị cho bạn PID cho các quy trình bạn không sở hữu hoặc đó là không gian hạt nhân. Ví dụ
Bratchley

Cách mạnh mẽ nhất là vá sshd ... Một bản vá nhanh & bẩn sẽ chỉ là một vài dòng tại nơi máy chủ lấy cổng cục bộ từ HĐH, ghi số cổng vào tệp, tên được tạo từ người dùng, máy chủ từ xa và Hải cảng. Giả sử máy chủ biết cổng ở phía máy khách, điều này không chắc chắn, thậm chí có thể không có khả năng (nếu không tính năng này sẽ tồn tại).
hyde

@hyde: chính xác. Máy chủ từ xa không biết về các cổng chuyển tiếp. Nó chỉ tạo ra một vài ổ cắm nghe và dữ liệu được chuyển tiếp qua kết nối ssh. Nó không biết về các cổng đích địa phương.
Bananguin

Câu trả lời:


1

Lấy hai (xem lịch sử cho một phiên bản mà scp từ phía máy chủ và đơn giản hơn một chút), điều này sẽ làm điều đó. Ý chính của nó là:

  1. chuyển một biến môi trường từ máy khách sang máy chủ, cho máy chủ biết cách nó có thể phát hiện khi thông tin cổng có sẵn và sau đó lấy và sử dụng nó.
  2. một khi thông tin cổng có sẵn, sao chép nó từ máy khách sang máy chủ, cho phép máy chủ lấy nó (với sự trợ giúp của phần 1 ở trên) và sử dụng nó

Trước tiên, thiết lập ở phía xa, bạn cần cho phép gửi một biến env trong cấu hình sshd :

sudo yourfavouriteeditor /etc/ssh/sshd_config

Tìm dòng với AcceptEnvvà thêm MY_PORT_FILEvào nó (hoặc thêm dòng dưới Hostphần bên phải nếu chưa có dòng nào). Đối với tôi, dòng trở thành này:

AcceptEnv LANG LC_* MY_PORT_FILE

Cũng nhớ khởi động lại sshd để điều này có hiệu lực.

Ngoài ra, để các tập lệnh bên dưới hoạt động, hãy thực hiện mkdir ~/portfilesở phía xa!


Sau đó về phía địa phương, một đoạn mã sẽ

  1. tạo tên tệp tạm thời cho chuyển hướng stderr
  2. để lại một công việc nền để chờ tập tin có nội dung
  3. chuyển tên tệp đến máy chủ dưới dạng biến env, đồng thời chuyển hướng ssh stderr sang tệp
  4. công việc nền tiến hành sao chép tệp temp stderr sang phía máy chủ bằng cách sử dụng scp riêng
  5. công việc nền cũng sao chép một tệp cờ đến máy chủ để cho biết tệp stderr đã sẵn sàng

Đoạn mã:

REMOTE=$USER@datserver

PORTFILE=`mktemp /tmp/sshdataserverports-$(hostname)-XXXXX`
test -e $PORTFILE && rm -v $PORTFILE

# EMPTYFLAG servers both as empty flag file for remote side,
# and safeguard for background job termination on this side
EMPTYFLAG=$PORTFILE-empty
cp /dev/null $EMPTYFLAG

# this variable has the file name sent over ssh connection
export MY_PORT_FILE=$(basename $PORTFILE)

# background job loop to wait for the temp file to have data
( while [ -f $EMPTYFLAG -a \! -s $PORTFILE ] ; do
     sleep 1 # check once per sec
  done
  sleep 1 # make sure temp file gets the port data

  # first copy temp file, ...
  scp  $PORTFILE $REMOTE:portfiles/$MY_PORT_FILE

  # ...then copy flag file telling temp file contents are up to date
  scp  $EMPTYFLAG $REMOTE:portfiles/$MY_PORT_FILE.flag
) &

# actual ssh terminal connection    
ssh -X -o "SendEnv MY_PORT_FILE" -R0:localhost:631 -R0:localhost:4713 $REMOTE 2> $PORTFILE

# remove files after connection is over
rm -v $PORTFILE $EMPTYFLAG

Sau đó, một đoạn trích cho phía từ xa, phù hợp với .bashrc :

# only do this if subdir has been created and env variable set
if [ -d ~/portfiles -a "$MY_PORT_FILE" ] ; then

       PORTFILE=~/portfiles/$(basename "$MY_PORT_FILE")
       FLAGFILE=$PORTFILE.flag
       # wait for FLAGFILE to get copied,
       # after which PORTFILE should be complete
       while [ \! -f "$FLAGFILE" ] ; do 
           echo "Waiting for $FLAGFILE..."
           sleep 1
       done

       # use quite exact regexps and head to make this robust
       export CUPS_SERVER=localhost:$(grep '^Allocated port [0-9]\+ .* localhost:631[[:space:]]*$' "$PORTFILE" | head -1 | cut -d" " -f3)
       export PULSE_SERVER=localhost:$(grep '^Allocated port [0-9]\+ .* localhost:4713[[:space:]]*$' "$PORTFILE" | head -1 | cut -d" " -f3)
       echo "Set CUPS_SERVER and PULSE_SERVER"

       # copied files served their purpose, and can be removed right away
       rm -v -- "$PORTFILE" "$FLAGFILE"
fi

Lưu ý : Mã trên tất nhiên không được kiểm tra kỹ lưỡng và có thể chứa tất cả các loại lỗi, lỗi sao chép-dán, v.v ... Bất kỳ ai sử dụng nó cũng hiểu rõ hơn, hãy tự chịu rủi ro khi sử dụng! Tôi đã thử nghiệm nó chỉ bằng kết nối localhost và nó hoạt động với tôi, trong env thử nghiệm của tôi. YMMV.


Tất nhiên điều đó đòi hỏi tôi có thể scptừ phía xa đến phía địa phương, điều mà tôi không thể. Tôi đã có một cách tiếp cận tương tự, nhưng tôi sẽ bọc sshnó sau khi thiết lập kết nối, sau đó gửi tệp đó từ cục bộ đến điều khiển từ xa scpvà sau đó kéo sshứng dụng khách lên nền trước và chạy tập lệnh ở phía xa. Tôi đã không tìm ra làm thế nào để kịch bản nền và tiền cảnh các quy trình từ xa và cục bộ độc đáo. Gói và tích hợp sshmáy khách cục bộ với một số tập lệnh từ xa như thế có vẻ không phải là một cách tiếp cận tốt.
Bananguin

Ah. Tôi nghĩ bạn chỉ nên nền scp phía khách hàng : (while [ ... ] ; do sleep 1 ; done ; scp ... )&. Sau đó đợi trên nền trước trong máy chủ .bashrc(giả sử máy khách gửi biến env bên phải) để tệp xuất hiện. Tôi sẽ cập nhật câu trả lời sau một số thử nghiệm (có thể không còn thời gian cho đến ngày mai).
hyde

@Bananguin Phiên bản mới được thực hiện. Có vẻ như để làm việc cho tôi, vì vậy nên thích ứng với trường hợp sử dụng của bạn. Về "cách tiếp cận tốt đẹp", vâng, nhưng tôi không nghĩ rằng thực sự có một cách tiếp cận tốt đẹp có thể ở đây. Thông tin cần phải được thông qua bằng cách nào đó và nó sẽ luôn là một bản hack, trừ khi bạn vá cả máy khách và máy chủ ssh để làm sạch thông qua một kết nối duy nhất.
hyde

Và tôi đang suy nghĩ nhiều hơn về việc vá openssh. Dường như không phải là một vấn đề lớn. Thông tin đã có sẵn. Tôi chỉ cần gửi nó đến máy chủ. Bất cứ khi nào máy chủ nhận được thông tin như vậy, nó sẽ ghi vào~/.ssh-${PID}-forwards
Bananguin

1

Một đoạn mã cho phía địa phương, phù hợp với .bashrc:

#!/bin/bash

user=$1
host=$2

sshr() {
# 1. connect, get dynamic port, disconnect  
port=`echo "exit" | ssh -R '*:0:127.0.0.1:52698' -t $1 2>&1 | grep 'Allocated port' | awk '/port/ {print $3;}'`
# 2. reconnect with this port and set remote variable
cmds="ssh -R $port:127.0.0.1:52698 -t $1 bash -c \"export RMATE_PORT=$port; bash\""
($cmds)
}

sshr $user@$host

0

Tôi đã đạt được điều tương tự bằng cách tạo một đường ống trên máy khách cục bộ, sau đó chuyển hướng stderr sang đường ống cũng được chuyển hướng đến đầu vào của ssh. Nó không yêu cầu nhiều kết nối ssh để giả định một cổng được biết miễn phí có thể bị lỗi. Bằng cách này, biểu ngữ đăng nhập và văn bản "Phân bổ cổng ### ..." được chuyển hướng đến máy chủ từ xa.

Tôi có một tập lệnh đơn giản trên máy chủ getsshport.shđang chạy trên máy chủ từ xa đọc đầu vào được chuyển hướng và phân tích cú pháp cổng. Miễn là đoạn script này không kết thúc, ssh remote Forward vẫn mở.

phía địa phương

mkfifo pipe
ssh -R "*:0:localhost:22" user@remotehost "~/getsshport.sh" 3>&1 1>&2 2>&3 < pipe | cat > pipe

3>&1 1>&2 2>&3 là một mẹo nhỏ để trao đổi stderr và stdout, để stderr được chuyển sang cat và tất cả các đầu ra bình thường từ ssh được hiển thị trên stderr.

phía xa ~ / gotshport.sh

#!/bin/sh
echo "Connection from $SSH_CLIENT"
while read line
do
    echo "$line" # echos everything sent back to the client
    echo "$line" | sed -n "s/Allocated port \([0-9]*\) for remote forward to \(.*\)\:\([0-9]*\).*/client port \3 is on local port \1/p" >> /tmp/allocatedports
done

Tôi đã thử gửi thông grepbáo "cổng được phân bổ" ở phía địa phương trước khi gửi nó qua ssh, nhưng dường như ssh sẽ chặn chờ đường ống mở trên stdin. grep không mở đường ống để viết cho đến khi nó nhận được một cái gì đó, vì vậy điều này về cơ bản là bế tắc. cattuy nhiên dường như không có hành vi tương tự và mở đường ống để viết ngay lập tức cho phép ssh mở kết nối.

đây là vấn đề tương tự ở phía xa và tại sao readtừng dòng thay vì chỉ grep từ stdin - nếu không thì `/ tmp / allocports 'không được viết ra cho đến khi đường hầm ssh bị đóng mà đánh bại toàn bộ mục đích

Đường ống tiêu chuẩn của ssh vào một lệnh như ~/getsshport.shđược ưu tiên, vì không chỉ định một lệnh, văn bản biểu ngữ hoặc bất cứ điều gì khác trong đường ống được thực thi trên vỏ từ xa.


đẹp. tôi đã thêm renice +10 $$; exec cattrước doneđể tiết kiệm tài nguyên.
Spongman

0

Đây là một mẹo khó, xử lý phía máy chủ bổ sung dọc theo dòng SSH_CONNECTIONhoặc DISPLAYsẽ rất tuyệt, nhưng không dễ để thêm: một phần của vấn đề là chỉ sshkhách hàng biết đích cục bộ, gói yêu cầu (đến máy chủ) có chứa chỉ địa chỉ từ xa và cổng.

Các câu trả lời khác ở đây có nhiều giải pháp khác nhau để bắt phía khách hàng này và gửi nó đến máy chủ. Đây là một cách tiếp cận thay thế không trung thực hơn nhiều, nhưng ít nhất thì bữa tiệc xấu xí này vẫn được giữ ở phía khách hàng ;-)

  • phía máy khách, thêm / sửa đổi SendEnvđể chúng tôi có thể gửi một số biến môi trường tự nhiên qua ssh (có thể không mặc định)
  • phía máy chủ, thêm / sửa đổi AcceptEnvđể chấp nhận tương tự (có thể không được bật theo mặc định)
  • giám sát sshđầu ra stderr của máy khách với thư viện được tải động và cập nhật môi trường máy khách ssh trong quá trình thiết lập kết nối
  • chọn phía máy chủ biến môi trường trong tập lệnh hồ sơ / đăng nhập

Điều này hoạt động (vui vẻ, bây giờ dù thế nào đi nữa) vì điều khiển từ xa được thiết lập và ghi lại trước khi môi trường được trao đổi (xác nhận với ssh -vv ...). Thư viện được tải động phải nắm bắt write()chức năng libc ( ssh_confirm_remote_forward()logit()do_log()write()). Chuyển hướng hoặc gói các hàm trong nhị phân ELF (không biên dịch lại) là các lệnh có độ lớn phức tạp hơn so với thực hiện tương tự cho một hàm trong thư viện động.

Trên máy khách .ssh/config(hoặc dòng lệnh -o SendEnv ...)

Host somehost
  user whatever
  SendEnv SSH_RFWD_*

Trên máy chủ sshd_config(yêu cầu thay đổi root / hành chính)

AcceptEnv LC_* SSH_RFWD_*

Cách tiếp cận này hoạt động cho các máy khách Linux và không yêu cầu gì đặc biệt trên máy chủ, nó nên hoạt động cho các * nix khác với một số điều chỉnh nhỏ. Hoạt động từ ít nhất OpenSSH 5,8p1 đến 7,5p1.

Biên dịch với gcc -Wall -shared -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c Gọi với:

LD_PRELOAD=./rfwd.so ssh -R0:127.0.0.1:4713 -R0:localhost:631 somehost

Mật mã:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>

// gcc -Wall -shared  -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c

#define DEBUG 0
#define dfprintf(fmt, ...) \
    do { if (DEBUG) fprintf(stderr, "[%14s#%04d:%8s()] " fmt, \
          __FILE__, __LINE__, __func__,##__VA_ARGS__); } while (0)

typedef ssize_t write_fp(int fd, const void *buf, size_t count);
static write_fp *real_write;

void myinit(void) __attribute__((constructor));
void myinit(void)
{
    void *dl;
    dfprintf("It's alive!\n");
    if ((dl=dlopen(NULL,RTLD_NOW))) {
        real_write=dlsym(RTLD_NEXT,"write");
        if (!real_write) dfprintf("error: %s\n",dlerror());
        dfprintf("found %p write()\n", (void *)real_write);
    } else {
        dfprintf(stderr,"dlopen() failed\n");
    }
}

ssize_t write(int fd, const void *buf, size_t count)
{
     static int nenv=0;

     // debug1: Remote connections from 192.168.0.1:0 forwarded to local address 127.0.0.1:1000
     //  Allocated port 44284 for remote forward to 127.0.0.1:1000
     // debug1: All remote forwarding requests processed
     if ( (fd==2) && (!strncmp(buf,"Allocated port ",15)) ) {
         char envbuf1[256],envbuf2[256];
         unsigned int rport;
         char lspec[256];
         int rc;

         rc=sscanf(buf,"Allocated port %u for remote forward to %256s",
          &rport,lspec);

         if ( (rc==2) && (nenv<32) ) {
             snprintf(envbuf1,sizeof(envbuf1),"SSH_RFWD_%i",nenv++);
             snprintf(envbuf2,sizeof(envbuf2),"%u %s",rport,lspec);
             setenv(envbuf1,envbuf2,1);
             dfprintf("setenv(%s,%s,1)\n",envbuf1,envbuf2);
         }
     }
     return real_write(fd,buf,count);
}

(Có một số bẫy gấu glibc liên quan đến phiên bản biểu tượng với phương pháp này, nhưng write()không có vấn đề này.)

Nếu bạn cảm thấy dũng cảm, bạn có thể lấy setenv()mã liên quan và vá nó vào ssh.c ssh_confirm_remote_forward()chức năng gọi lại.

Điều này đặt các biến môi trường được đặt tên SSH_RFWD_nnn, kiểm tra chúng trong hồ sơ của bạn, ví dụ như trongbash

for fwd in ${!SSH_RFWD_*}; do
    IFS=" :" read lport rip rport <<< ${!fwd}
    [[ $rport -eq "631" ]] && export CUPS_SERVER=localhost:$lport
    # ...
done

Hãy cẩn thận:

  • không có nhiều lỗi kiểm tra trong mã
  • thay đổi môi trường có thể gây ra các vấn đề liên quan đến luồng, PAM sử dụng các luồng, tôi không mong đợi các vấn đề nhưng tôi đã kiểm tra rằng
  • sshhiện tại không đăng nhập rõ ràng chuyển tiếp đầy đủ của biểu mẫu * local: port: remote: port * (nếu cần phân tích thêm debug1thông điệp với ssh -vsẽ được yêu cầu), nhưng bạn không cần điều này cho trường hợp sử dụng của bạn

OpenSSH đủ kỳ lạ dường như không có phương tiện để lấy Thông tin về chuyển tiếp cổng.

Bạn có thể (một phần) thực hiện việc này một cách tương tác với lối thoát ~#, kỳ lạ là việc triển khai bỏ qua các kênh đang nghe, nó chỉ liệt kê các kênh đang mở (ví dụ TCP ESTABOUNDED) và nó không in các trường hữu ích trong mọi trường hợp. Xemchannels.c channel_open_message()

Bạn có thể vá chức năng đó để in chi tiết cho SSH_CHANNEL_PORT_LISTENERcác vị trí, nhưng điều đó chỉ giúp bạn chuyển tiếp cục bộ ( các kênh không giống với chuyển tiếp thực tế ). Hoặc, bạn có thể vá nó để kết xuất hai bảng chuyển tiếp từ optionscấu trúc toàn cầu :

#include "readconf.h"
Options options;  /* extern */
[...]
snprintf(buf, sizeof buf, "Local forwards:\r\n");
buffer_append(&buffer, buf, strlen(buf));
for (i = 0; i < options.num_local_forwards; i++) {
     snprintf(buf, sizeof buf, "  #%d listen %s:%d connect %s:%d\r\n",i,
       options.local_forwards[i].listen_host,
       options.local_forwards[i].listen_port,
       options.local_forwards[i].connect_host,
       options.local_forwards[i].connect_port);
     buffer_append(&buffer, buf, strlen(buf));
}
snprintf(buf, sizeof buf, "Remote forwards:\r\n");
buffer_append(&buffer, buf, strlen(buf));
for (i = 0; i < options.num_remote_forwards; i++) {
     snprintf(buf, sizeof buf, "  #%d listen %s:%d connect %s:%d\r\n",i,
       options.remote_forwards[i].listen_host,
       options.remote_forwards[i].listen_port,
       options.remote_forwards[i].connect_host,
       options.remote_forwards[i].connect_port);
     buffer_append(&buffer, buf, strlen(buf));
}

Điều này hoạt động tốt, mặc dù đó không phải là giải pháp "lập trình", với lời cảnh báo rằng mã máy khách không (tuy nhiên, nó được gắn cờ XXX trong nguồn) cập nhật danh sách khi bạn thêm / xóa chuyển tiếp khi đang di chuyển ( ~C)


Nếu (các) máy chủ là Linux, bạn có thêm một tùy chọn, đây là tùy chọn tôi thường sử dụng, mặc dù để chuyển tiếp cục bộ chứ không phải từ xa. lolà 127.0.0.1/8, trên Linux, bạn có thể liên kết trong suốt với bất kỳ địa chỉ nào trong 127/8 , vì vậy bạn có thể sử dụng các cổng cố định nếu bạn sử dụng các địa chỉ 127.xyz duy nhất, ví dụ:

mr@local:~$ ssh -R127.53.50.55:44284:127.0.0.1:44284 remote
[...]
mr@remote:~$ ss -atnp src 127.53.50.55
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port 
LISTEN     0      128            127.53.50.55:44284                    *:*    

Điều này tuân theo các cổng đặc quyền ràng buộc <1024, OpenSSH không hỗ trợ các khả năng của Linux và có kiểm tra UID được mã hóa cứng trên hầu hết các nền tảng.

Các octet được chọn một cách khôn ngoan (ký hiệu thứ tự ASCII trong trường hợp của tôi) giúp gỡ rối mớ hỗn độn vào cuối ngày.

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.