2009-10-16 23 views
5

Tôi đang tìm một ví dụ về cách sử dụng libssh2 để thiết lập chuyển tiếp cổng ssh. Tôi đã xem xét API, nhưng có rất ít trong cách tài liệu trong lĩnh vực chuyển tiếp cổng.Mã ví dụ về libssh2 đang được sử dụng để chuyển tiếp cổng

Ví dụ, khi sử dụng số plink của PuTTY có cổng từ xa để nghe, nhưng cũng là cổng cục bộ mà lưu lượng truy cập sẽ được gửi đến. Có phải nhà phát triển chịu trách nhiệm thiết lập điều này không? Ai đó có thể đưa ra một ví dụ về làm thế nào để làm điều này?

Ngoài ra, một ví dụ khi cổng từ xa được đưa đến cổng cục bộ sẽ hữu ích. Tôi có sử dụng libssh2_channel_direct_tcpip_ex() không?

Tôi sẵn sàng trả một khoản tiền thưởng nếu cần để có được một vài ví dụ làm việc về điều này.

Trả lời

6

Chìa khóa để làm việc chuyển tiếp cổng libssh2 đã phát hiện ra rằng về cơ bản nó chỉ cung cấp cho bạn dữ liệu đi vào cổng đó. Bạn phải gửi dữ liệu lên cổng cục bộ mà bạn mở:

(Lưu ý, mã này chưa hoàn thành, không có kiểm tra lỗi và việc tạo luồng chỉ không đúng, nhưng nó đưa ra một phác thảo chung về cách thực hiện điều này.)

void reverse_port_forward(CMainDlg* dlg, addrinfo * hubaddr, std::string username, std::string password, int port) 
{ 
    int iretval; 
    unsigned long mode = 1; 
    int last_socket_err = 0; 
    int other_port = 0; 
    fd_set read_set, write_set; 

    SOCKET sshsock = socket(AF_INET, SOCK_STREAM, 0); 
    iretval = connect(sshsock, hubaddr->ai_addr, hubaddr->ai_addrlen); 
    if (iretval != 0) 
    ::PostQuitMessage(0); 

    LIBSSH2_SESSION * session = NULL; 
    session = libssh2_session_init(); 

    iretval = libssh2_session_startup(session, sshsock); 
    if (iretval) 
    ::PostQuitMessage(0); 

    iretval = libssh2_userauth_password(session, username.c_str(), password.c_str()); 

    dlg->m_track_status(dlg, 1, 0, "Authorized"); 

    LIBSSH2_LISTENER* listener = NULL; 
    listener = libssh2_channel_forward_listen_ex(session, "127.0.0.1", port, &other_port, 1); 
    if (!listener) 
    ::PostQuitMessage(0); 

    LIBSSH2_CHANNEL* channel = NULL; 

    ioctlsocket(sshsock, FIONBIO, &mode); 
    libssh2_session_set_blocking(session, 0); // non-blocking 
    int err = LIBSSH2_ERROR_EAGAIN; 
    while (err == LIBSSH2_ERROR_EAGAIN) 
    { 
    channel = libssh2_channel_forward_accept(listener); 
    if (channel) break; 
    err = libssh2_session_last_errno(session); 
    boost::this_thread::yield(); 
    } 

    if (channel) 
    { 
    char buf[MAX_BUF_LEN]; 
    char* chunk; 
    long bytes_read = 0; 
    long bytes_written = 0; 
    int total_set = 0; 
    timeval wait; 
    wait.tv_sec = 0; 
    wait.tv_usec = 2000; 

    sockaddr_in localhost; 
    localhost.sin_family = AF_INET; 
    localhost.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    localhost.sin_port = htons(5900); 
    SOCKET local_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    ioctlsocket(local_sock, FIONBIO, &mode); 
    iretval = connect(local_sock, (sockaddr*) &localhost, sizeof(localhost)); 
    if (iretval == SOCKET_ERROR) 
     iretval = WSAGetLastError(); 

    while (1) 
    { 
     bytes_read = libssh2_channel_read(channel, buf, MAX_BUF_LEN); 
     if (bytes_read >= 0){ 
     FD_ZERO(&read_set); 
     FD_ZERO(&write_set); 
     FD_SET(local_sock, &write_set); 

     // wait until the socket can be written to 
     while (select(0, &read_set, &write_set, NULL, &wait) < 1) 
      boost::this_thread::yield(); 

     if (FD_ISSET(local_sock, &write_set)) 
     { 
      FD_CLR(local_sock, &write_set); 
      chunk = buf; 

      // everything may not get written in this call because we're non blocking. So 
      // keep writing more data until we've emptied the buffer pointer. 
      while ((bytes_written = send(local_sock, chunk, bytes_read, 0)) < bytes_read) 
      { 
      // if it couldn't write anything because the buffer is full, bytes_written 
      // will be negative which won't help our pointer math much 
      if (bytes_written > 0) 
      { 
       chunk = buf + bytes_written; 
       bytes_read -= bytes_written; 
       if (bytes_read == 0) 
       break; 
      } 
      FD_ZERO(&read_set); 
      FD_ZERO(&write_set); 
      FD_SET(local_sock, &write_set); 

      // wait until the socket can be written to 
      while (select(0, &read_set, &write_set, NULL, &wait) < 1) 
       boost::this_thread::yield(); 
      } 

     } 
     } 

     FD_ZERO(&read_set); 
     FD_ZERO(&write_set); 
     FD_SET(local_sock, &read_set); 
     select(0, &read_set, &write_set, NULL, &wait); 
     if (FD_ISSET(local_sock, &read_set)) 
     { 
     FD_CLR(local_sock, &read_set); 
     bytes_read = recv(local_sock, buf, MAX_BUF_LEN, 0); 
     if (bytes_read >= 0) 
     { 
      while ((bytes_written = libssh2_channel_write_ex(channel, 0, buf, bytes_read)) == LIBSSH2_ERROR_EAGAIN) 
      boost::this_thread::yield(); 
     } 
     } 
     boost::this_thread::yield(); 
    } // while 
    } // if channel 
} 

PS Để làm cho tác phẩm này yêu cầu các bản dựng mới nhất của SVN của libssh2. Đã xảy ra lỗi trong các phiên bản trước để giữ cho chuyển tiếp cổng không thể sử dụng được.

+0

Dường như anh ta yêu cầu một cổng chuyển tiếp, nhưng chức năng của bạn rõ ràng có tiêu đề là "reverse_port_forward". Mã ví dụ này có mang một cổng cục bộ đến cổng máy chủ hay cổng máy chủ đến cổng cục bộ không? – Ralphleon

5

Mã nguồn libssh2 bao gồm từ một vài năm một ví dụ direct_tcpip.c minh họa cách tạo kênh SSH trực tiếp, và kể từ tuần trước ví dụ về forward-tcpip.c thể hiện cách tạo kênh SSH chuyển tiếp .

trực tiếp-tcpip là những gì ssh -L sử dụng và forward-tcpip là những gì ssh -R sử dụng.

Người dùng libssh2 luôn chịu trách nhiệm đối phó với dữ liệu thực tế. libssh2 quản lý kênh SSH và không có gì khác. Bạn có thể hưởng lợi đáng kể từ việc nghiên cứu các RFC SSH, đặc biệt là RFC 4254, để tìm hiểu thêm về chính xác từng loại kênh hứa hẹn cho bạn, và do đó những gì bạn có thể mong đợi từ libssh2.

Các vấn đề liên quan