SSH: Fix TCP/IP forwarding support.

We hardcoded the remote host to the SSH server for some reason, and the
originating port was bogus as well.

Change-Id: I8f6700bc12f4374302dd3bfc035c9c9f060f56ef
Reviewed-by: Caspar Romot <cro@icd.ee>
Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
This commit is contained in:
Christian Kandeler
2015-04-14 15:47:55 +02:00
parent aee5668b62
commit bde83c30bf
10 changed files with 57 additions and 48 deletions

View File

@@ -170,11 +170,11 @@ QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
return sftp; return sftp;
} }
SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(quint16 remotePort, SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(const QString &originatingHost,
const SshConnectionInfo &connectionInfo) quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
{ {
SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++, remotePort, SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
connectionInfo, m_sendFacility)); originatingHost, originatingPort, remoteHost, remotePort, m_sendFacility));
insertChannel(tunnel->d, tunnel); insertChannel(tunnel->d, tunnel);
return tunnel; return tunnel;
} }

View File

@@ -37,7 +37,6 @@
namespace QSsh { namespace QSsh {
class SftpChannel; class SftpChannel;
class SshConnectionInfo;
class SshDirectTcpIpTunnel; class SshDirectTcpIpTunnel;
class SshRemoteProcess; class SshRemoteProcess;
@@ -56,8 +55,8 @@ public:
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command); QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell(); QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel(); QSharedPointer<SftpChannel> createSftpChannel();
QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort, QSharedPointer<SshDirectTcpIpTunnel> createTunnel(const QString &originatingHost,
const SshConnectionInfo &connectionInfo); quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
int channelCount() const; int channelCount() const;
enum CloseAllMode { CloseAllRegular, CloseAllAndReset }; enum CloseAllMode { CloseAllRegular, CloseAllAndReset };

View File

@@ -184,10 +184,11 @@ QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
return d->createSftpChannel(); return d->createSftpChannel();
} }
SshDirectTcpIpTunnel::Ptr SshConnection::createTunnel(quint16 remotePort) SshDirectTcpIpTunnel::Ptr SshConnection::createTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
{ {
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshDirectTcpIpTunnel::Ptr()); QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshDirectTcpIpTunnel::Ptr());
return d->createTunnel(remotePort); return d->createTunnel(originatingHost, originatingPort, remoteHost, remotePort);
} }
int SshConnection::closeAllChannels() int SshConnection::closeAllChannels()
@@ -828,9 +829,10 @@ QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
return m_channelManager->createSftpChannel(); return m_channelManager->createSftpChannel();
} }
SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createTunnel(quint16 remotePort) SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
{ {
return m_channelManager->createTunnel(remotePort, m_conn->connectionInfo()); return m_channelManager->createTunnel(originatingHost, originatingPort, remoteHost, remotePort);
} }
const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1); const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);

View File

@@ -127,7 +127,8 @@ public:
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command); QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell(); QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel(); QSharedPointer<SftpChannel> createSftpChannel();
QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort); QSharedPointer<SshDirectTcpIpTunnel> createTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
// -1 if an error occurred, number of channels closed otherwise. // -1 if an error occurred, number of channels closed otherwise.
int closeAllChannels(); int closeAllChannels();

View File

@@ -89,7 +89,8 @@ public:
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command); QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell(); QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel(); QSharedPointer<SftpChannel> createSftpChannel();
QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort); QSharedPointer<SshDirectTcpIpTunnel> createTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
SshStateInternal state() const { return m_state; } SshStateInternal state() const { return m_state; }
SshError error() const { return m_error; } SshError error() const { return m_error; }

View File

@@ -38,11 +38,14 @@
namespace QSsh { namespace QSsh {
namespace Internal { namespace Internal {
SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId, quint16 remotePort, SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId,
const SshConnectionInfo &connectionInfo, SshSendFacility &sendFacility) const QString &originatingHost, quint16 originatingPort, const QString &remoteHost,
quint16 remotePort, SshSendFacility &sendFacility)
: AbstractSshChannel(channelId, sendFacility), : AbstractSshChannel(channelId, sendFacility),
m_remotePort(remotePort), m_originatingHost(originatingHost),
m_connectionInfo(connectionInfo) m_originatingPort(originatingPort),
m_remoteHost(remoteHost),
m_remotePort(remotePort)
{ {
connect(this, SIGNAL(eof()), SLOT(handleEof())); connect(this, SIGNAL(eof()), SLOT(handleEof()));
} }
@@ -112,9 +115,11 @@ void SshDirectTcpIpTunnelPrivate::handleEof()
using namespace Internal; using namespace Internal;
SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, quint16 remotePort, SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
const SshConnectionInfo &connectionInfo, SshSendFacility &sendFacility) quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
: d(new SshDirectTcpIpTunnelPrivate(channelId, remotePort, connectionInfo, sendFacility)) SshSendFacility &sendFacility)
: d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost,
remotePort, sendFacility))
{ {
connect(d, SIGNAL(initialized()), SIGNAL(initialized()), Qt::QueuedConnection); connect(d, SIGNAL(initialized()), SIGNAL(initialized()), Qt::QueuedConnection);
connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::QueuedConnection); connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::QueuedConnection);
@@ -156,9 +161,8 @@ void SshDirectTcpIpTunnel::initialize()
try { try {
QIODevice::open(QIODevice::ReadWrite); QIODevice::open(QIODevice::ReadWrite);
d->m_sendFacility.sendDirectTcpIpPacket(d->localChannelId(), d->initialWindowSize(), d->m_sendFacility.sendDirectTcpIpPacket(d->localChannelId(), d->initialWindowSize(),
d->maxPacketSize(), d->m_connectionInfo.peerAddress.toString().toUtf8(), d->maxPacketSize(), d->m_remoteHost.toUtf8(), d->m_remotePort,
d->m_remotePort, d->m_connectionInfo.localAddress.toString().toUtf8(), d->m_originatingHost.toUtf8(), d->m_originatingPort);
d->m_connectionInfo.localPort);
d->setChannelState(AbstractSshChannel::SessionRequested); d->setChannelState(AbstractSshChannel::SessionRequested);
d->m_timeoutTimer.start(d->ReplyTimeout); d->m_timeoutTimer.start(d->ReplyTimeout);
} catch (const Botan::Exception &e) { // Won't happen, but let's play it safe. } catch (const Botan::Exception &e) { // Won't happen, but let's play it safe.

View File

@@ -37,7 +37,6 @@
#include <QSharedPointer> #include <QSharedPointer>
namespace QSsh { namespace QSsh {
class SshConnectionInfo;
namespace Internal { namespace Internal {
class SshChannelManager; class SshChannelManager;
@@ -71,8 +70,9 @@ signals:
void tunnelClosed(); void tunnelClosed();
private: private:
SshDirectTcpIpTunnel(quint32 channelId, quint16 remotePort, SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
const SshConnectionInfo &connectionInfo, Internal::SshSendFacility &sendFacility); quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
Internal::SshSendFacility &sendFacility);
// QIODevice stuff // QIODevice stuff
qint64 readData(char *data, qint64 maxlen); qint64 readData(char *data, qint64 maxlen);

View File

@@ -32,8 +32,6 @@
#include "sshchannel_p.h" #include "sshchannel_p.h"
#include "sshconnection.h"
namespace QSsh { namespace QSsh {
class SshDirectTcpIpTunnel; class SshDirectTcpIpTunnel;
@@ -46,8 +44,9 @@ class SshDirectTcpIpTunnelPrivate : public AbstractSshChannel
friend class QSsh::SshDirectTcpIpTunnel; friend class QSsh::SshDirectTcpIpTunnel;
public: public:
explicit SshDirectTcpIpTunnelPrivate(quint32 channelId, quint16 remotePort, explicit SshDirectTcpIpTunnelPrivate(quint32 channelId, const QString &originatingHost,
const SshConnectionInfo &connectionInfo, SshSendFacility &sendFacility); quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
SshSendFacility &sendFacility);
signals: signals:
void initialized(); void initialized();
@@ -71,8 +70,10 @@ private:
void closeHook(); void closeHook();
const QString m_originatingHost;
const quint16 m_originatingPort;
const QString m_remoteHost;
const quint16 m_remotePort; const quint16 m_remotePort;
const SshConnectionInfo m_connectionInfo;
QByteArray m_data; QByteArray m_data;
}; };

View File

@@ -48,7 +48,7 @@ using namespace QSsh;
Tunnel::Tunnel(const SshConnectionParameters &parameters, QObject *parent) Tunnel::Tunnel(const SshConnectionParameters &parameters, QObject *parent)
: QObject(parent), : QObject(parent),
m_connection(new SshConnection(parameters, this)), m_connection(new SshConnection(parameters, this)),
m_tunnelServer(new QTcpServer(this)), m_targetServer(new QTcpServer(this)),
m_expectingChannelClose(false) m_expectingChannelClose(false)
{ {
connect(m_connection, SIGNAL(connected()), SLOT(handleConnected())); connect(m_connection, SIGNAL(connected()), SLOT(handleConnected()));
@@ -74,16 +74,17 @@ void Tunnel::handleConnectionError()
void Tunnel::handleConnected() void Tunnel::handleConnected()
{ {
std::cout << "Opening server side..." << std::endl; std::cout << "Opening server side..." << std::endl;
if (!m_tunnelServer->listen(QHostAddress::LocalHost)) { if (!m_targetServer->listen(QHostAddress::LocalHost)) {
std::cerr << "Error opening port: " std::cerr << "Error opening port: "
<< m_tunnelServer->errorString().toLocal8Bit().constData() << std::endl; << m_targetServer->errorString().toLocal8Bit().constData() << std::endl;
qApp->exit(EXIT_FAILURE); qApp->exit(EXIT_FAILURE);
return; return;
} }
m_forwardedPort = m_tunnelServer->serverPort(); m_targetPort = m_targetServer->serverPort();
connect(m_tunnelServer, SIGNAL(newConnection()), SLOT(handleNewConnection())); connect(m_targetServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
m_tunnel = m_connection->createTunnel(m_forwardedPort); m_tunnel = m_connection->createTunnel(QLatin1String("localhost"), 1024, // made-up values
QLatin1String("localhost"), m_targetPort);
connect(m_tunnel.data(), SIGNAL(initialized()), SLOT(handleInitialized())); connect(m_tunnel.data(), SIGNAL(initialized()), SLOT(handleInitialized()));
connect(m_tunnel.data(), SIGNAL(error(QString)), SLOT(handleTunnelError(QString))); connect(m_tunnel.data(), SIGNAL(error(QString)), SLOT(handleTunnelError(QString)));
connect(m_tunnel.data(), SIGNAL(readyRead()), SLOT(handleServerData())); connect(m_tunnel.data(), SIGNAL(readyRead()), SLOT(handleServerData()));
@@ -108,7 +109,7 @@ void Tunnel::handleServerData()
if (m_dataReceivedFromServer == ServerDataPrefix + TestData) { if (m_dataReceivedFromServer == ServerDataPrefix + TestData) {
std::cout << "Data exchange successful. Closing server socket..." << std::endl; std::cout << "Data exchange successful. Closing server socket..." << std::endl;
m_expectingChannelClose = true; m_expectingChannelClose = true;
m_tunnelSocket->close(); m_targetSocket->close();
} }
} }
@@ -132,27 +133,27 @@ void Tunnel::handleTunnelClosed()
void Tunnel::handleNewConnection() void Tunnel::handleNewConnection()
{ {
m_tunnelSocket = m_tunnelServer->nextPendingConnection(); m_targetSocket = m_targetServer->nextPendingConnection();
m_tunnelServer->close(); m_targetServer->close();
connect(m_tunnelSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(handleSocketError())); connect(m_targetSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(handleSocketError()));
connect(m_tunnelSocket, SIGNAL(readyRead()), SLOT(handleClientData())); connect(m_targetSocket, SIGNAL(readyRead()), SLOT(handleClientData()));
handleClientData(); handleClientData();
} }
void Tunnel::handleSocketError() void Tunnel::handleSocketError()
{ {
std::cerr << "Socket error: " << m_tunnelSocket->errorString().toLocal8Bit().constData() std::cerr << "Socket error: " << m_targetSocket->errorString().toLocal8Bit().constData()
<< std::endl; << std::endl;
qApp->exit(EXIT_FAILURE); qApp->exit(EXIT_FAILURE);
} }
void Tunnel::handleClientData() void Tunnel::handleClientData()
{ {
m_dataReceivedFromClient += m_tunnelSocket->readAll(); m_dataReceivedFromClient += m_targetSocket->readAll();
if (m_dataReceivedFromClient == TestData) { if (m_dataReceivedFromClient == TestData) {
std::cout << "Client data successfully received by server, now sending data to client..." std::cout << "Client data successfully received by server, now sending data to client..."
<< std::endl; << std::endl;
m_tunnelSocket->write(ServerDataPrefix + m_dataReceivedFromClient); m_targetSocket->write(ServerDataPrefix + m_dataReceivedFromClient);
} }
} }

View File

@@ -68,9 +68,9 @@ private slots:
private: private:
QSsh::SshConnection * const m_connection; QSsh::SshConnection * const m_connection;
QSharedPointer<QSsh::SshDirectTcpIpTunnel> m_tunnel; QSharedPointer<QSsh::SshDirectTcpIpTunnel> m_tunnel;
QTcpServer * const m_tunnelServer; QTcpServer * const m_targetServer;
QTcpSocket *m_tunnelSocket; QTcpSocket *m_targetSocket;
quint16 m_forwardedPort; quint16 m_targetPort;
QByteArray m_dataReceivedFromServer; QByteArray m_dataReceivedFromServer;
QByteArray m_dataReceivedFromClient; QByteArray m_dataReceivedFromClient;
bool m_expectingChannelClose; bool m_expectingChannelClose;