Пример кода libssh2, используемого для перенаправления портов

Добавьте новый класс к своему проекту и отправьте код, показанный ниже. Сборка. Отбросьте новое управление от вершины панели инструментов на Вашу форму.

using System;
using System.Windows.Forms;

public class TransparentLabel : Label {
  public TransparentLabel() {
    this.SetStyle(ControlStyles.Opaque, true);
    this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
  }
  protected override CreateParams CreateParams {
    get {
      CreateParams parms = base.CreateParams;
      parms.ExStyle |= 0x20;  // Turn on WS_EX_TRANSPARENT
      return parms;
    }
  }
}
6
задан Chilledrat 2 May 2012 в 12:21
поделиться

1 ответ

The key to making libssh2 port forwarding work was discovering that it basically just gives you the data that came in to that port. You have to actually send the data onto a local port that you open:

(Note, this code is not yet complete, there is no error checking, and the thread yielding isn't correct, but it gives a general outline of how to accomplish this.)

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
}

P.S. To make this work requires the latest SVN builds of libssh2. There were bugs in prior versions that kept port forwarding from being usable.

7
ответ дан 8 December 2019 в 18:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: