forked from qt-creator/qt-creator
Ssh: Implement tcp/ip forward tunneling
Change-Id: I529b3392ea7e4cbae2c736c9f55352ef6b19da98 Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
This commit is contained in:
@@ -30,7 +30,10 @@ SOURCES = $$PWD/sshsendfacility.cpp \
|
|||||||
$$PWD/sshinit.cpp \
|
$$PWD/sshinit.cpp \
|
||||||
$$PWD/sshdirecttcpiptunnel.cpp \
|
$$PWD/sshdirecttcpiptunnel.cpp \
|
||||||
$$PWD/sshlogging.cpp \
|
$$PWD/sshlogging.cpp \
|
||||||
$$PWD/sshhostkeydatabase.cpp
|
$$PWD/sshhostkeydatabase.cpp \
|
||||||
|
$$PWD/sshtcpipforwardserver.cpp \
|
||||||
|
$$PWD/sshtcpiptunnel.cpp \
|
||||||
|
$$PWD/sshforwardedtcpiptunnel.cpp
|
||||||
|
|
||||||
HEADERS = $$PWD/sshsendfacility_p.h \
|
HEADERS = $$PWD/sshsendfacility_p.h \
|
||||||
$$PWD/sshremoteprocess.h \
|
$$PWD/sshremoteprocess.h \
|
||||||
@@ -68,7 +71,12 @@ HEADERS = $$PWD/sshsendfacility_p.h \
|
|||||||
$$PWD/sshinit_p.h \
|
$$PWD/sshinit_p.h \
|
||||||
$$PWD/sshdirecttcpiptunnel.h \
|
$$PWD/sshdirecttcpiptunnel.h \
|
||||||
$$PWD/sshlogging_p.h \
|
$$PWD/sshlogging_p.h \
|
||||||
$$PWD/sshhostkeydatabase.h
|
$$PWD/sshhostkeydatabase.h \
|
||||||
|
$$PWD/sshtcpipforwardserver.h \
|
||||||
|
$$PWD/sshtcpipforwardserver_p.h \
|
||||||
|
$$PWD/sshtcpiptunnel_p.h \
|
||||||
|
$$PWD/sshforwardedtcpiptunnel.h \
|
||||||
|
$$PWD/sshforwardedtcpiptunnel_p.h
|
||||||
|
|
||||||
FORMS = $$PWD/sshkeycreationdialog.ui
|
FORMS = $$PWD/sshkeycreationdialog.ui
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ QtcLibrary {
|
|||||||
"sshdirecttcpiptunnel.h", "sshdirecttcpiptunnel_p.h", "sshdirecttcpiptunnel.cpp",
|
"sshdirecttcpiptunnel.h", "sshdirecttcpiptunnel_p.h", "sshdirecttcpiptunnel.cpp",
|
||||||
"ssherrors.h",
|
"ssherrors.h",
|
||||||
"sshexception_p.h",
|
"sshexception_p.h",
|
||||||
|
"sshforwardedtcpiptunnel.cpp", "sshforwardedtcpiptunnel.h", "sshforwardedtcpiptunnel_p.h",
|
||||||
"sshhostkeydatabase.cpp",
|
"sshhostkeydatabase.cpp",
|
||||||
"sshhostkeydatabase.h",
|
"sshhostkeydatabase.h",
|
||||||
"sshincomingpacket_p.h", "sshincomingpacket.cpp",
|
"sshincomingpacket_p.h", "sshincomingpacket.cpp",
|
||||||
@@ -46,6 +47,8 @@ QtcLibrary {
|
|||||||
"sshremoteprocess.cpp", "sshremoteprocess.h", "sshremoteprocess_p.h",
|
"sshremoteprocess.cpp", "sshremoteprocess.h", "sshremoteprocess_p.h",
|
||||||
"sshremoteprocessrunner.cpp", "sshremoteprocessrunner.h",
|
"sshremoteprocessrunner.cpp", "sshremoteprocessrunner.h",
|
||||||
"sshsendfacility.cpp", "sshsendfacility_p.h",
|
"sshsendfacility.cpp", "sshsendfacility_p.h",
|
||||||
|
"sshtcpipforwardserver.cpp", "sshtcpipforwardserver.h", "sshtcpipforwardserver_p.h",
|
||||||
|
"sshtcpiptunnel.cpp", "sshtcpiptunnel_p.h",
|
||||||
].concat(botanFiles)
|
].concat(botanFiles)
|
||||||
|
|
||||||
property var useSystemBotan: Environment.getEnv("USE_SYSTEM_BOTAN") === "1"
|
property var useSystemBotan: Environment.getEnv("USE_SYSTEM_BOTAN") === "1"
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ void AbstractSshChannel::handleOpenFailure(const QString &reason)
|
|||||||
return; // Late server reply; we requested a channel close in the meantime.
|
return; // Late server reply; we requested a channel close in the meantime.
|
||||||
default:
|
default:
|
||||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
"Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
|
"Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_timeoutTimer.stop();
|
m_timeoutTimer.stop();
|
||||||
|
|||||||
@@ -29,10 +29,15 @@
|
|||||||
#include "sftpchannel_p.h"
|
#include "sftpchannel_p.h"
|
||||||
#include "sshdirecttcpiptunnel.h"
|
#include "sshdirecttcpiptunnel.h"
|
||||||
#include "sshdirecttcpiptunnel_p.h"
|
#include "sshdirecttcpiptunnel_p.h"
|
||||||
|
#include "sshforwardedtcpiptunnel.h"
|
||||||
|
#include "sshforwardedtcpiptunnel_p.h"
|
||||||
#include "sshincomingpacket_p.h"
|
#include "sshincomingpacket_p.h"
|
||||||
|
#include "sshlogging_p.h"
|
||||||
#include "sshremoteprocess.h"
|
#include "sshremoteprocess.h"
|
||||||
#include "sshremoteprocess_p.h"
|
#include "sshremoteprocess_p.h"
|
||||||
#include "sshsendfacility_p.h"
|
#include "sshsendfacility_p.h"
|
||||||
|
#include "sshtcpipforwardserver.h"
|
||||||
|
#include "sshtcpipforwardserver_p.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
@@ -51,10 +56,54 @@ void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet)
|
|||||||
->handleChannelRequest(packet);
|
->handleChannelRequest(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &)
|
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet)
|
||||||
{
|
{
|
||||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
SshChannelOpen channelOpen = packet.extractChannelOpen();
|
||||||
"Server tried to open channel on client.");
|
|
||||||
|
SshTcpIpForwardServer::Ptr server;
|
||||||
|
|
||||||
|
foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
|
||||||
|
if (candidate->port() == channelOpen.remotePort
|
||||||
|
&& candidate->bindAddress().toUtf8() == channelOpen.remoteAddress) {
|
||||||
|
server = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (server.isNull()) {
|
||||||
|
// Apparently the server knows a remoteAddress we are not aware of. There are plenty of ways
|
||||||
|
// to make that happen: /etc/hosts on the server, different writings for localhost,
|
||||||
|
// different DNS servers, ...
|
||||||
|
// Rather than trying to figure that out, we just use the first listening forwarder with the
|
||||||
|
// same port.
|
||||||
|
foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
|
||||||
|
if (candidate->port() == channelOpen.remotePort) {
|
||||||
|
server = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server.isNull()) {
|
||||||
|
SshOpenFailureType reason = (channelOpen.remotePort == 0) ?
|
||||||
|
SSH_OPEN_UNKNOWN_CHANNEL_TYPE : SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||||
|
try {
|
||||||
|
m_sendFacility.sendChannelOpenFailurePacket(channelOpen.remoteChannel, reason,
|
||||||
|
QByteArray());
|
||||||
|
} catch (const Botan::Exception &e) {
|
||||||
|
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SshForwardedTcpIpTunnel::Ptr tunnel(new SshForwardedTcpIpTunnel(m_nextLocalChannelId++,
|
||||||
|
m_sendFacility));
|
||||||
|
tunnel->d->handleOpenSuccess(channelOpen.remoteChannel, channelOpen.remoteWindowSize,
|
||||||
|
channelOpen.remoteMaxPacketSize);
|
||||||
|
tunnel->open(QIODevice::ReadWrite);
|
||||||
|
server->setNewConnection(tunnel);
|
||||||
|
insertChannel(tunnel->d, tunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet)
|
void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet)
|
||||||
@@ -125,6 +174,39 @@ void SshChannelManager::handleChannelClose(const SshIncomingPacket &packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshChannelManager::handleRequestSuccess(const SshIncomingPacket &packet)
|
||||||
|
{
|
||||||
|
if (m_waitingForwardServers.isEmpty()) {
|
||||||
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
|
"Unexpected request success packet.",
|
||||||
|
tr("Unexpected request success packet."));
|
||||||
|
}
|
||||||
|
SshTcpIpForwardServer::Ptr server = m_waitingForwardServers.takeFirst();
|
||||||
|
if (server->state() == SshTcpIpForwardServer::Closing) {
|
||||||
|
server->setClosed();
|
||||||
|
} else if (server->state() == SshTcpIpForwardServer::Initializing) {
|
||||||
|
quint16 port = server->port();
|
||||||
|
if (port == 0)
|
||||||
|
port = packet.extractRequestSuccess().bindPort;
|
||||||
|
server->setListening(port);
|
||||||
|
m_listeningForwardServers.append(server);
|
||||||
|
} else {
|
||||||
|
QSSH_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshChannelManager::handleRequestFailure(const SshIncomingPacket &packet)
|
||||||
|
{
|
||||||
|
Q_UNUSED(packet);
|
||||||
|
if (m_waitingForwardServers.isEmpty()) {
|
||||||
|
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
|
"Unexpected request failure packet.",
|
||||||
|
tr("Unexpected request failure packet."));
|
||||||
|
}
|
||||||
|
SshTcpIpForwardServer::Ptr tunnel = m_waitingForwardServers.takeFirst();
|
||||||
|
tunnel->setClosed();
|
||||||
|
}
|
||||||
|
|
||||||
SshChannelManager::ChannelIterator SshChannelManager::lookupChannelAsIterator(quint32 channelId,
|
SshChannelManager::ChannelIterator SshChannelManager::lookupChannelAsIterator(quint32 channelId,
|
||||||
bool allowNotFound)
|
bool allowNotFound)
|
||||||
{
|
{
|
||||||
@@ -165,7 +247,7 @@ QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
|
|||||||
return sftp;
|
return sftp;
|
||||||
}
|
}
|
||||||
|
|
||||||
SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(const QString &originatingHost,
|
SshDirectTcpIpTunnel::Ptr SshChannelManager::createDirectTunnel(const QString &originatingHost,
|
||||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
||||||
{
|
{
|
||||||
SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
|
SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
|
||||||
@@ -174,6 +256,28 @@ SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(const QString &origina
|
|||||||
return tunnel;
|
return tunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SshTcpIpForwardServer::Ptr SshChannelManager::createForwardServer(const QString &remoteHost,
|
||||||
|
quint16 remotePort)
|
||||||
|
{
|
||||||
|
SshTcpIpForwardServer::Ptr server(new SshTcpIpForwardServer(remoteHost, remotePort,
|
||||||
|
m_sendFacility));
|
||||||
|
connect(server.data(), &SshTcpIpForwardServer::stateChanged,
|
||||||
|
this, [this, server](SshTcpIpForwardServer::State state) {
|
||||||
|
switch (state) {
|
||||||
|
case SshTcpIpForwardServer::Closing:
|
||||||
|
m_listeningForwardServers.removeOne(server);
|
||||||
|
// fall through
|
||||||
|
case SshTcpIpForwardServer::Initializing:
|
||||||
|
m_waitingForwardServers.append(server);
|
||||||
|
break;
|
||||||
|
case SshTcpIpForwardServer::Listening:
|
||||||
|
case SshTcpIpForwardServer::Inactive:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
void SshChannelManager::insertChannel(AbstractSshChannel *priv,
|
void SshChannelManager::insertChannel(AbstractSshChannel *priv,
|
||||||
const QSharedPointer<QObject> &pub)
|
const QSharedPointer<QObject> &pub)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ namespace QSsh {
|
|||||||
class SftpChannel;
|
class SftpChannel;
|
||||||
class SshDirectTcpIpTunnel;
|
class SshDirectTcpIpTunnel;
|
||||||
class SshRemoteProcess;
|
class SshRemoteProcess;
|
||||||
|
class SshTcpIpForwardServer;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -49,8 +50,10 @@ 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(const QString &originatingHost,
|
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
|
||||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
||||||
|
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
|
||||||
|
quint16 remotePort);
|
||||||
|
|
||||||
int channelCount() const;
|
int channelCount() const;
|
||||||
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
|
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
|
||||||
@@ -67,6 +70,8 @@ public:
|
|||||||
void handleChannelExtendedData(const SshIncomingPacket &packet);
|
void handleChannelExtendedData(const SshIncomingPacket &packet);
|
||||||
void handleChannelEof(const SshIncomingPacket &packet);
|
void handleChannelEof(const SshIncomingPacket &packet);
|
||||||
void handleChannelClose(const SshIncomingPacket &packet);
|
void handleChannelClose(const SshIncomingPacket &packet);
|
||||||
|
void handleRequestSuccess(const SshIncomingPacket &packet);
|
||||||
|
void handleRequestFailure(const SshIncomingPacket &packet);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void timeout();
|
void timeout();
|
||||||
@@ -86,6 +91,8 @@ private:
|
|||||||
QHash<quint32, AbstractSshChannel *> m_channels;
|
QHash<quint32, AbstractSshChannel *> m_channels;
|
||||||
QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions;
|
QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions;
|
||||||
quint32 m_nextLocalChannelId;
|
quint32 m_nextLocalChannelId;
|
||||||
|
QList<QSharedPointer<SshTcpIpForwardServer>> m_waitingForwardServers;
|
||||||
|
QList<QSharedPointer<SshTcpIpForwardServer>> m_listeningForwardServers;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "sshchannelmanager_p.h"
|
#include "sshchannelmanager_p.h"
|
||||||
#include "sshcryptofacility_p.h"
|
#include "sshcryptofacility_p.h"
|
||||||
#include "sshdirecttcpiptunnel.h"
|
#include "sshdirecttcpiptunnel.h"
|
||||||
|
#include "sshtcpipforwardserver.h"
|
||||||
#include "sshexception_p.h"
|
#include "sshexception_p.h"
|
||||||
#include "sshinit_p.h"
|
#include "sshinit_p.h"
|
||||||
#include "sshkeyexchange_p.h"
|
#include "sshkeyexchange_p.h"
|
||||||
@@ -180,11 +181,18 @@ QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
|
|||||||
return d->createSftpChannel();
|
return d->createSftpChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
SshDirectTcpIpTunnel::Ptr SshConnection::createTunnel(const QString &originatingHost,
|
SshDirectTcpIpTunnel::Ptr SshConnection::createDirectTunnel(const QString &originatingHost,
|
||||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
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(originatingHost, originatingPort, remoteHost, remotePort);
|
return d->createDirectTunnel(originatingHost, originatingPort, remoteHost, remotePort);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<SshTcpIpForwardServer> SshConnection::createForwardServer(const QString &remoteHost,
|
||||||
|
quint16 remotePort)
|
||||||
|
{
|
||||||
|
QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshTcpIpForwardServer::Ptr());
|
||||||
|
return d->createForwardServer(remoteHost, remotePort);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshConnection::closeAllChannels()
|
int SshConnection::closeAllChannels()
|
||||||
@@ -296,6 +304,11 @@ void SshConnectionPrivate::setupPacketHandlers()
|
|||||||
|
|
||||||
setupPacketHandler(SSH_MSG_UNIMPLEMENTED,
|
setupPacketHandler(SSH_MSG_UNIMPLEMENTED,
|
||||||
StateList() << ConnectionEstablished, &This::handleUnimplementedPacket);
|
StateList() << ConnectionEstablished, &This::handleUnimplementedPacket);
|
||||||
|
|
||||||
|
setupPacketHandler(SSH_MSG_REQUEST_SUCCESS, connectedList,
|
||||||
|
&This::handleRequestSuccess);
|
||||||
|
setupPacketHandler(SSH_MSG_REQUEST_FAILURE, connectedList,
|
||||||
|
&This::handleRequestFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshConnectionPrivate::setupPacketHandler(SshPacketType type,
|
void SshConnectionPrivate::setupPacketHandler(SshPacketType type,
|
||||||
@@ -680,7 +693,15 @@ void SshConnectionPrivate::handleDisconnect()
|
|||||||
"", tr("Server closed connection: %1").arg(msg.description));
|
"", tr("Server closed connection: %1").arg(msg.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshConnectionPrivate::handleRequestSuccess()
|
||||||
|
{
|
||||||
|
m_channelManager->handleRequestSuccess(m_incomingPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshConnectionPrivate::handleRequestFailure()
|
||||||
|
{
|
||||||
|
m_channelManager->handleRequestFailure(m_incomingPacket);
|
||||||
|
}
|
||||||
|
|
||||||
void SshConnectionPrivate::sendData(const QByteArray &data)
|
void SshConnectionPrivate::sendData(const QByteArray &data)
|
||||||
{
|
{
|
||||||
@@ -820,10 +841,17 @@ QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
|
|||||||
return m_channelManager->createSftpChannel();
|
return m_channelManager->createSftpChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createTunnel(const QString &originatingHost,
|
SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createDirectTunnel(const QString &originatingHost,
|
||||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
|
||||||
{
|
{
|
||||||
return m_channelManager->createTunnel(originatingHost, originatingPort, remoteHost, remotePort);
|
return m_channelManager->createDirectTunnel(originatingHost, originatingPort, remoteHost,
|
||||||
|
remotePort);
|
||||||
|
}
|
||||||
|
|
||||||
|
SshTcpIpForwardServer::Ptr SshConnectionPrivate::createForwardServer(const QString &bindAddress,
|
||||||
|
quint16 bindPort)
|
||||||
|
{
|
||||||
|
return m_channelManager->createForwardServer(bindAddress, bindPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);
|
const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace QSsh {
|
|||||||
class SftpChannel;
|
class SftpChannel;
|
||||||
class SshDirectTcpIpTunnel;
|
class SshDirectTcpIpTunnel;
|
||||||
class SshRemoteProcess;
|
class SshRemoteProcess;
|
||||||
|
class SshTcpIpForwardServer;
|
||||||
|
|
||||||
namespace Internal { class SshConnectionPrivate; }
|
namespace Internal { class SshConnectionPrivate; }
|
||||||
|
|
||||||
@@ -121,8 +122,10 @@ 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(const QString &originatingHost,
|
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
|
||||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
||||||
|
QSharedPointer<SshTcpIpForwardServer> createForwardServer(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();
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ namespace QSsh {
|
|||||||
class SftpChannel;
|
class SftpChannel;
|
||||||
class SshRemoteProcess;
|
class SshRemoteProcess;
|
||||||
class SshDirectTcpIpTunnel;
|
class SshDirectTcpIpTunnel;
|
||||||
|
class SshTcpIpForwardServer;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class SshChannelManager;
|
class SshChannelManager;
|
||||||
@@ -83,8 +84,10 @@ 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(const QString &originatingHost,
|
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
|
||||||
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
|
||||||
|
QSharedPointer<SshTcpIpForwardServer> createForwardServer(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; }
|
||||||
@@ -132,6 +135,9 @@ private:
|
|||||||
void handleChannelEof();
|
void handleChannelEof();
|
||||||
void handleChannelClose();
|
void handleChannelClose();
|
||||||
void handleDisconnect();
|
void handleDisconnect();
|
||||||
|
void handleRequestSuccess();
|
||||||
|
void handleRequestFailure();
|
||||||
|
|
||||||
bool canUseSocket() const;
|
bool canUseSocket() const;
|
||||||
void createPrivateKey();
|
void createPrivateKey();
|
||||||
|
|
||||||
|
|||||||
@@ -38,25 +38,12 @@ namespace Internal {
|
|||||||
SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId,
|
SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId,
|
||||||
const QString &originatingHost, quint16 originatingPort, const QString &remoteHost,
|
const QString &originatingHost, quint16 originatingPort, const QString &remoteHost,
|
||||||
quint16 remotePort, SshSendFacility &sendFacility)
|
quint16 remotePort, SshSendFacility &sendFacility)
|
||||||
: AbstractSshChannel(channelId, sendFacility),
|
: SshTcpIpTunnelPrivate(channelId, sendFacility),
|
||||||
m_originatingHost(originatingHost),
|
m_originatingHost(originatingHost),
|
||||||
m_originatingPort(originatingPort),
|
m_originatingPort(originatingPort),
|
||||||
m_remoteHost(remoteHost),
|
m_remoteHost(remoteHost),
|
||||||
m_remotePort(remotePort)
|
m_remotePort(remotePort)
|
||||||
{
|
{
|
||||||
connect(this, SIGNAL(eof()), SLOT(handleEof()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleChannelSuccess()
|
|
||||||
{
|
|
||||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
||||||
"Unexpected SSH_MSG_CHANNEL_SUCCESS message.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleChannelFailure()
|
|
||||||
{
|
|
||||||
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
|
||||||
"Unexpected SSH_MSG_CHANNEL_FAILURE message.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
|
void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
|
||||||
@@ -64,50 +51,6 @@ void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
|
|||||||
emit initialized();
|
emit initialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleOpenFailureInternal(const QString &reason)
|
|
||||||
{
|
|
||||||
emit error(reason);
|
|
||||||
closeChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleChannelDataInternal(const QByteArray &data)
|
|
||||||
{
|
|
||||||
m_data += data;
|
|
||||||
emit readyRead();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleChannelExtendedDataInternal(quint32 type,
|
|
||||||
const QByteArray &data)
|
|
||||||
{
|
|
||||||
qCWarning(sshLog, "%s: Unexpected extended channel data. Type is %u, content is '%s'.",
|
|
||||||
Q_FUNC_INFO, type, data.constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus)
|
|
||||||
{
|
|
||||||
qCWarning(sshLog, "%s: Unexpected exit status %d.", Q_FUNC_INFO, exitStatus.exitStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleExitSignal(const SshChannelExitSignal &signal)
|
|
||||||
{
|
|
||||||
qCWarning(sshLog, "%s: Unexpected exit signal %s.", Q_FUNC_INFO, signal.signal.constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::closeHook()
|
|
||||||
{
|
|
||||||
emit closed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnelPrivate::handleEof()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* For some reason, the OpenSSH server only sends EOF when the remote port goes away,
|
|
||||||
* but does not close the channel, even though it becomes useless in that case.
|
|
||||||
* So we close it ourselves.
|
|
||||||
*/
|
|
||||||
closeChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
using namespace Internal;
|
using namespace Internal;
|
||||||
@@ -118,15 +61,13 @@ SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, const QString &ori
|
|||||||
: d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost,
|
: d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost,
|
||||||
remotePort, sendFacility))
|
remotePort, sendFacility))
|
||||||
{
|
{
|
||||||
connect(d, SIGNAL(initialized()), SIGNAL(initialized()), Qt::QueuedConnection);
|
d->init(this);
|
||||||
connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::QueuedConnection);
|
connect(d, &SshDirectTcpIpTunnelPrivate::initialized,
|
||||||
connect(d, SIGNAL(closed()), SIGNAL(tunnelClosed()), Qt::QueuedConnection);
|
this, &SshDirectTcpIpTunnel::initialized, Qt::QueuedConnection);
|
||||||
connect(d, SIGNAL(error(QString)), SLOT(handleError(QString)), Qt::QueuedConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel()
|
SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel()
|
||||||
{
|
{
|
||||||
d->closeChannel();
|
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,24 +111,12 @@ void SshDirectTcpIpTunnel::initialize()
|
|||||||
|
|
||||||
qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen)
|
qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen)
|
||||||
{
|
{
|
||||||
const qint64 bytesRead = qMin(qint64(d->m_data.count()), maxlen);
|
return d->readData(data, maxlen);
|
||||||
memcpy(data, d->m_data.constData(), bytesRead);
|
|
||||||
d->m_data.remove(0, bytesRead);
|
|
||||||
return bytesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len)
|
qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len)
|
||||||
{
|
{
|
||||||
QSSH_ASSERT_AND_RETURN_VALUE(d->channelState() == AbstractSshChannel::SessionEstablished, 0);
|
return d->writeData(data, len);
|
||||||
|
|
||||||
d->sendData(QByteArray(data, len));
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SshDirectTcpIpTunnel::handleError(const QString &reason)
|
|
||||||
{
|
|
||||||
setErrorString(reason);
|
|
||||||
emit error(reason);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QSsh
|
} // namespace QSsh
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace Internal {
|
|||||||
class SshChannelManager;
|
class SshChannelManager;
|
||||||
class SshDirectTcpIpTunnelPrivate;
|
class SshDirectTcpIpTunnelPrivate;
|
||||||
class SshSendFacility;
|
class SshSendFacility;
|
||||||
|
class SshTcpIpTunnelPrivate;
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
|
class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
|
||||||
@@ -43,6 +44,7 @@ class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
friend class Internal::SshChannelManager;
|
friend class Internal::SshChannelManager;
|
||||||
|
friend class Internal::SshTcpIpTunnelPrivate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef QSharedPointer<SshDirectTcpIpTunnel> Ptr;
|
typedef QSharedPointer<SshDirectTcpIpTunnel> Ptr;
|
||||||
@@ -61,7 +63,6 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void initialized();
|
void initialized();
|
||||||
void error(const QString &reason);
|
void error(const QString &reason);
|
||||||
void tunnelClosed();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
|
SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
|
||||||
@@ -72,8 +73,6 @@ private:
|
|||||||
qint64 readData(char *data, qint64 maxlen);
|
qint64 readData(char *data, qint64 maxlen);
|
||||||
qint64 writeData(const char *data, qint64 len);
|
qint64 writeData(const char *data, qint64 len);
|
||||||
|
|
||||||
Q_SLOT void handleError(const QString &reason);
|
|
||||||
|
|
||||||
Internal::SshDirectTcpIpTunnelPrivate * const d;
|
Internal::SshDirectTcpIpTunnelPrivate * const d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sshchannel_p.h"
|
#include "sshtcpiptunnel_p.h"
|
||||||
|
|
||||||
namespace QSsh {
|
namespace QSsh {
|
||||||
class SshDirectTcpIpTunnel;
|
class SshDirectTcpIpTunnel;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class SshDirectTcpIpTunnelPrivate : public AbstractSshChannel
|
class SshDirectTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -45,31 +45,14 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initialized();
|
void initialized();
|
||||||
void readyRead();
|
|
||||||
void error(const QString &reason);
|
|
||||||
void closed();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void handleEof();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleChannelSuccess();
|
|
||||||
void handleChannelFailure();
|
|
||||||
|
|
||||||
void handleOpenSuccessInternal();
|
void handleOpenSuccessInternal();
|
||||||
void handleOpenFailureInternal(const QString &reason);
|
|
||||||
void handleChannelDataInternal(const QByteArray &data);
|
|
||||||
void handleChannelExtendedDataInternal(quint32 type, const QByteArray &data);
|
|
||||||
void handleExitStatus(const SshChannelExitStatus &exitStatus);
|
|
||||||
void handleExitSignal(const SshChannelExitSignal &signal);
|
|
||||||
|
|
||||||
void closeHook();
|
|
||||||
|
|
||||||
const QString m_originatingHost;
|
const QString m_originatingHost;
|
||||||
const quint16 m_originatingPort;
|
const quint16 m_originatingPort;
|
||||||
const QString m_remoteHost;
|
const QString m_remoteHost;
|
||||||
const quint16 m_remotePort;
|
const quint16 m_remotePort;
|
||||||
QByteArray m_data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
100
src/libs/ssh/sshforwardedtcpiptunnel.cpp
Normal file
100
src/libs/ssh/sshforwardedtcpiptunnel.cpp
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "sshforwardedtcpiptunnel.h"
|
||||||
|
#include "sshforwardedtcpiptunnel_p.h"
|
||||||
|
#include "sshlogging_p.h"
|
||||||
|
#include "sshsendfacility_p.h"
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
SshForwardedTcpIpTunnelPrivate::SshForwardedTcpIpTunnelPrivate(quint32 channelId,
|
||||||
|
SshSendFacility &sendFacility) :
|
||||||
|
SshTcpIpTunnelPrivate(channelId, sendFacility)
|
||||||
|
{
|
||||||
|
setChannelState(SessionRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshForwardedTcpIpTunnelPrivate::handleOpenSuccessInternal()
|
||||||
|
{
|
||||||
|
QSSH_ASSERT_AND_RETURN(channelState() == AbstractSshChannel::SessionEstablished);
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(),
|
||||||
|
initialWindowSize(), maxPacketSize());
|
||||||
|
} catch (const Botan::Exception &e) { // Won't happen, but let's play it safe.
|
||||||
|
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||||
|
closeChannel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
using namespace Internal;
|
||||||
|
|
||||||
|
SshForwardedTcpIpTunnel::SshForwardedTcpIpTunnel(quint32 channelId, SshSendFacility &sendFacility) :
|
||||||
|
d(new SshForwardedTcpIpTunnelPrivate(channelId, sendFacility))
|
||||||
|
{
|
||||||
|
d->init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
SshForwardedTcpIpTunnel::~SshForwardedTcpIpTunnel()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SshForwardedTcpIpTunnel::atEnd() const
|
||||||
|
{
|
||||||
|
return QIODevice::atEnd() && d->m_data.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SshForwardedTcpIpTunnel::bytesAvailable() const
|
||||||
|
{
|
||||||
|
return QIODevice::bytesAvailable() + d->m_data.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SshForwardedTcpIpTunnel::canReadLine() const
|
||||||
|
{
|
||||||
|
return QIODevice::canReadLine() || d->m_data.contains('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshForwardedTcpIpTunnel::close()
|
||||||
|
{
|
||||||
|
d->closeChannel();
|
||||||
|
QIODevice::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SshForwardedTcpIpTunnel::readData(char *data, qint64 maxlen)
|
||||||
|
{
|
||||||
|
return d->readData(data, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SshForwardedTcpIpTunnel::writeData(const char *data, qint64 len)
|
||||||
|
{
|
||||||
|
return d->writeData(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QSsh
|
||||||
70
src/libs/ssh/sshforwardedtcpiptunnel.h
Normal file
70
src/libs/ssh/sshforwardedtcpiptunnel.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ssh_global.h"
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
class SshChannelManager;
|
||||||
|
class SshForwardedTcpIpTunnelPrivate;
|
||||||
|
class SshSendFacility;
|
||||||
|
class SshTcpIpTunnelPrivate;
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
class QSSH_EXPORT SshForwardedTcpIpTunnel : public QIODevice
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class Internal::SshChannelManager;
|
||||||
|
friend class Internal::SshTcpIpTunnelPrivate;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef QSharedPointer<SshForwardedTcpIpTunnel> Ptr;
|
||||||
|
~SshForwardedTcpIpTunnel();
|
||||||
|
|
||||||
|
// QIODevice stuff
|
||||||
|
bool atEnd() const;
|
||||||
|
qint64 bytesAvailable() const;
|
||||||
|
bool canReadLine() const;
|
||||||
|
void close();
|
||||||
|
bool isSequential() const { return true; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void error(const QString &reason);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SshForwardedTcpIpTunnel(quint32 channelId, Internal::SshSendFacility &sendFacility);
|
||||||
|
|
||||||
|
// QIODevice stuff
|
||||||
|
qint64 readData(char *data, qint64 maxlen) override;
|
||||||
|
qint64 writeData(const char *data, qint64 len) override;
|
||||||
|
|
||||||
|
Internal::SshForwardedTcpIpTunnelPrivate * const d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QSsh
|
||||||
44
src/libs/ssh/sshforwardedtcpiptunnel_p.h
Normal file
44
src/libs/ssh/sshforwardedtcpiptunnel_p.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sshforwardedtcpiptunnel.h"
|
||||||
|
#include "sshtcpiptunnel_p.h"
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class SshForwardedTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class QSsh::SshForwardedTcpIpTunnel;
|
||||||
|
public:
|
||||||
|
SshForwardedTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility);
|
||||||
|
void handleOpenSuccessInternal() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QSsh
|
||||||
@@ -35,6 +35,7 @@ namespace Internal {
|
|||||||
|
|
||||||
const QByteArray SshIncomingPacket::ExitStatusType("exit-status");
|
const QByteArray SshIncomingPacket::ExitStatusType("exit-status");
|
||||||
const QByteArray SshIncomingPacket::ExitSignalType("exit-signal");
|
const QByteArray SshIncomingPacket::ExitSignalType("exit-signal");
|
||||||
|
const QByteArray SshIncomingPacket::ForwardedTcpIpType("forwarded-tcpip");
|
||||||
|
|
||||||
SshIncomingPacket::SshIncomingPacket() : m_serverSeqNr(0) { }
|
SshIncomingPacket::SshIncomingPacket() : m_serverSeqNr(0) { }
|
||||||
|
|
||||||
@@ -313,6 +314,22 @@ SshDebug SshIncomingPacket::extractDebug() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SshRequestSuccess SshIncomingPacket::extractRequestSuccess() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(isComplete());
|
||||||
|
Q_ASSERT(type() == SSH_MSG_REQUEST_SUCCESS);
|
||||||
|
|
||||||
|
try {
|
||||||
|
SshRequestSuccess msg;
|
||||||
|
quint32 offset = TypeOffset + 1;
|
||||||
|
msg.bindPort = SshPacketParser::asUint32(m_data, &offset);
|
||||||
|
return msg;
|
||||||
|
} catch (const SshPacketParseException &) {
|
||||||
|
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
|
"Invalid SSH_MSG_REQUEST_SUCCESS.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SshUnimplemented SshIncomingPacket::extractUnimplemented() const
|
SshUnimplemented SshIncomingPacket::extractUnimplemented() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(isComplete());
|
Q_ASSERT(isComplete());
|
||||||
@@ -329,6 +346,31 @@ SshUnimplemented SshIncomingPacket::extractUnimplemented() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SshChannelOpen SshIncomingPacket::extractChannelOpen() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(isComplete());
|
||||||
|
Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN);
|
||||||
|
|
||||||
|
SshChannelOpen open;
|
||||||
|
try {
|
||||||
|
quint32 offset = TypeOffset + 1;
|
||||||
|
QByteArray type = SshPacketParser::asString(m_data, &offset);
|
||||||
|
open.remoteChannel = SshPacketParser::asUint32(m_data, &offset);
|
||||||
|
open.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset);
|
||||||
|
open.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset);
|
||||||
|
if (type == ForwardedTcpIpType) {
|
||||||
|
open.remoteAddress = SshPacketParser::asString(m_data, &offset);
|
||||||
|
open.remotePort = SshPacketParser::asUint32(m_data, &offset);
|
||||||
|
} else {
|
||||||
|
open.remotePort = 0;
|
||||||
|
}
|
||||||
|
} catch (const SshPacketParseException &) {
|
||||||
|
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
|
"Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
|
||||||
|
}
|
||||||
|
return open;
|
||||||
|
}
|
||||||
|
|
||||||
SshChannelOpenFailure SshIncomingPacket::extractChannelOpenFailure() const
|
SshChannelOpenFailure SshIncomingPacket::extractChannelOpenFailure() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(isComplete());
|
Q_ASSERT(isComplete());
|
||||||
|
|||||||
@@ -97,6 +97,20 @@ struct SshUnimplemented
|
|||||||
quint32 invalidMsgSeqNr;
|
quint32 invalidMsgSeqNr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SshRequestSuccess
|
||||||
|
{
|
||||||
|
quint32 bindPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SshChannelOpen
|
||||||
|
{
|
||||||
|
quint32 remoteChannel;
|
||||||
|
quint32 remoteWindowSize;
|
||||||
|
quint32 remoteMaxPacketSize;
|
||||||
|
QByteArray remoteAddress;
|
||||||
|
quint32 remotePort;
|
||||||
|
};
|
||||||
|
|
||||||
struct SshChannelOpenFailure
|
struct SshChannelOpenFailure
|
||||||
{
|
{
|
||||||
quint32 localChannel;
|
quint32 localChannel;
|
||||||
@@ -147,7 +161,6 @@ struct SshChannelExitSignal
|
|||||||
QByteArray language;
|
QByteArray language;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SshIncomingPacket : public AbstractSshPacket
|
class SshIncomingPacket : public AbstractSshPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -164,8 +177,10 @@ public:
|
|||||||
SshUserAuthBanner extractUserAuthBanner() const;
|
SshUserAuthBanner extractUserAuthBanner() const;
|
||||||
SshUserAuthInfoRequestPacket extractUserAuthInfoRequest() const;
|
SshUserAuthInfoRequestPacket extractUserAuthInfoRequest() const;
|
||||||
SshDebug extractDebug() const;
|
SshDebug extractDebug() const;
|
||||||
|
SshRequestSuccess extractRequestSuccess() const;
|
||||||
SshUnimplemented extractUnimplemented() const;
|
SshUnimplemented extractUnimplemented() const;
|
||||||
|
|
||||||
|
SshChannelOpen extractChannelOpen() const;
|
||||||
SshChannelOpenFailure extractChannelOpenFailure() const;
|
SshChannelOpenFailure extractChannelOpenFailure() const;
|
||||||
SshChannelOpenConfirmation extractChannelOpenConfirmation() const;
|
SshChannelOpenConfirmation extractChannelOpenConfirmation() const;
|
||||||
SshChannelWindowAdjust extractWindowAdjust() const;
|
SshChannelWindowAdjust extractWindowAdjust() const;
|
||||||
@@ -180,6 +195,7 @@ public:
|
|||||||
|
|
||||||
static const QByteArray ExitStatusType;
|
static const QByteArray ExitStatusType;
|
||||||
static const QByteArray ExitSignalType;
|
static const QByteArray ExitSignalType;
|
||||||
|
static const QByteArray ForwardedTcpIpType;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual quint32 cipherBlockSize() const;
|
virtual quint32 cipherBlockSize() const;
|
||||||
|
|||||||
@@ -179,6 +179,19 @@ void SshOutgoingPacket::generateDirectTcpIpPacket(quint32 channelId, quint32 win
|
|||||||
.appendInt(remotePort).appendString(localIpAddress).appendInt(localPort).finalize();
|
.appendInt(remotePort).appendString(localIpAddress).appendInt(localPort).finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshOutgoingPacket::generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
|
||||||
|
{
|
||||||
|
init(SSH_MSG_GLOBAL_REQUEST).appendString("tcpip-forward").appendBool(true)
|
||||||
|
.appendString(bindAddress).appendInt(bindPort).finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshOutgoingPacket::generateCancelTcpIpForwardPacket(const QByteArray &bindAddress,
|
||||||
|
quint32 bindPort)
|
||||||
|
{
|
||||||
|
init(SSH_MSG_GLOBAL_REQUEST).appendString("cancel-tcpip-forward").appendBool(true)
|
||||||
|
.appendString(bindAddress).appendInt(bindPort).finalize();
|
||||||
|
}
|
||||||
|
|
||||||
void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel,
|
void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel,
|
||||||
const QByteArray &var, const QByteArray &value)
|
const QByteArray &var, const QByteArray &value)
|
||||||
{
|
{
|
||||||
@@ -255,6 +268,22 @@ void SshOutgoingPacket::generateChannelClosePacket(quint32 remoteChannel)
|
|||||||
init(SSH_MSG_CHANNEL_CLOSE).appendInt(remoteChannel).finalize();
|
init(SSH_MSG_CHANNEL_CLOSE).appendInt(remoteChannel).finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshOutgoingPacket::generateChannelOpenConfirmationPacket(quint32 remoteChannel,
|
||||||
|
quint32 localChannel,
|
||||||
|
quint32 localWindowSize,
|
||||||
|
quint32 maxPacketSize)
|
||||||
|
{
|
||||||
|
init(SSH_MSG_CHANNEL_OPEN_CONFIRMATION).appendInt(remoteChannel).appendInt(localChannel)
|
||||||
|
.appendInt(localWindowSize).appendInt(maxPacketSize).finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshOutgoingPacket::generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
|
||||||
|
const QByteArray &reasonString)
|
||||||
|
{
|
||||||
|
init(SSH_MSG_CHANNEL_OPEN_FAILURE).appendInt(remoteChannel).appendInt(reason)
|
||||||
|
.appendString(reasonString).appendString(QByteArray()).finalize();
|
||||||
|
}
|
||||||
|
|
||||||
void SshOutgoingPacket::generateDisconnectPacket(SshErrorCode reason,
|
void SshOutgoingPacket::generateDisconnectPacket(SshErrorCode reason,
|
||||||
const QByteArray &reasonString)
|
const QByteArray &reasonString)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ public:
|
|||||||
void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
|
void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
|
||||||
quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
|
quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
|
||||||
const QByteArray &localIpAddress, quint32 localPort);
|
const QByteArray &localIpAddress, quint32 localPort);
|
||||||
|
void generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
|
||||||
|
void generateCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
|
||||||
void generateEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
void generateEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
||||||
const QByteArray &value);
|
const QByteArray &value);
|
||||||
void generatePtyRequestPacket(quint32 remoteChannel,
|
void generatePtyRequestPacket(quint32 remoteChannel,
|
||||||
@@ -79,6 +81,10 @@ public:
|
|||||||
const QByteArray &signalName);
|
const QByteArray &signalName);
|
||||||
void generateChannelEofPacket(quint32 remoteChannel);
|
void generateChannelEofPacket(quint32 remoteChannel);
|
||||||
void generateChannelClosePacket(quint32 remoteChannel);
|
void generateChannelClosePacket(quint32 remoteChannel);
|
||||||
|
void generateChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
|
||||||
|
quint32 localWindowSize, quint32 maxPackeSize);
|
||||||
|
void generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
|
||||||
|
const QByteArray &reasonString);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual quint32 cipherBlockSize() const;
|
virtual quint32 cipherBlockSize() const;
|
||||||
|
|||||||
@@ -84,6 +84,13 @@ enum SshPacketType {
|
|||||||
SSH_MSG_INVALID = 128
|
SSH_MSG_INVALID = 128
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SshOpenFailureType {
|
||||||
|
SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1,
|
||||||
|
SSH_OPEN_CONNECT_FAILED = 2,
|
||||||
|
SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3,
|
||||||
|
SSH_OPEN_RESOURCE_SHORTAGE = 4
|
||||||
|
};
|
||||||
|
|
||||||
enum SshExtendedDataType { SSH_EXTENDED_DATA_STDERR = 1 };
|
enum SshExtendedDataType { SSH_EXTENDED_DATA_STDERR = 1 };
|
||||||
|
|
||||||
class SshAbstractCryptoFacility;
|
class SshAbstractCryptoFacility;
|
||||||
|
|||||||
@@ -172,6 +172,18 @@ void SshSendFacility::sendDirectTcpIpPacket(quint32 channelId, quint32 windowSiz
|
|||||||
sendPacket();
|
sendPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshSendFacility::sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
|
||||||
|
{
|
||||||
|
m_outgoingPacket.generateTcpIpForwardPacket(bindAddress, bindPort);
|
||||||
|
sendPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshSendFacility::sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
|
||||||
|
{
|
||||||
|
m_outgoingPacket.generateCancelTcpIpForwardPacket(bindAddress, bindPort);
|
||||||
|
sendPacket();
|
||||||
|
}
|
||||||
|
|
||||||
void SshSendFacility::sendPtyRequestPacket(quint32 remoteChannel,
|
void SshSendFacility::sendPtyRequestPacket(quint32 remoteChannel,
|
||||||
const SshPseudoTerminal &terminal)
|
const SshPseudoTerminal &terminal)
|
||||||
{
|
{
|
||||||
@@ -238,5 +250,20 @@ void SshSendFacility::sendChannelClosePacket(quint32 remoteChannel)
|
|||||||
sendPacket();
|
sendPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshSendFacility::sendChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
|
||||||
|
quint32 localWindowSize, quint32 maxPacketSize)
|
||||||
|
{
|
||||||
|
m_outgoingPacket.generateChannelOpenConfirmationPacket(remoteChannel, localChannel,
|
||||||
|
localWindowSize, maxPacketSize);
|
||||||
|
sendPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshSendFacility::sendChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
|
||||||
|
const QByteArray &reasonString)
|
||||||
|
{
|
||||||
|
m_outgoingPacket.generateChannelOpenFailurePacket(remoteChannel, reason, reasonString);
|
||||||
|
sendPacket();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace QSsh
|
} // namespace QSsh
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ public:
|
|||||||
void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize,
|
void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize,
|
||||||
const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress,
|
const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress,
|
||||||
quint32 localPort);
|
quint32 localPort);
|
||||||
|
void sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
|
||||||
|
void sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
|
||||||
void sendPtyRequestPacket(quint32 remoteChannel,
|
void sendPtyRequestPacket(quint32 remoteChannel,
|
||||||
const SshPseudoTerminal &terminal);
|
const SshPseudoTerminal &terminal);
|
||||||
void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
||||||
@@ -85,6 +87,10 @@ public:
|
|||||||
const QByteArray &signalName);
|
const QByteArray &signalName);
|
||||||
void sendChannelEofPacket(quint32 remoteChannel);
|
void sendChannelEofPacket(quint32 remoteChannel);
|
||||||
void sendChannelClosePacket(quint32 remoteChannel);
|
void sendChannelClosePacket(quint32 remoteChannel);
|
||||||
|
void sendChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
|
||||||
|
quint32 localWindowSize, quint32 maxPackeSize);
|
||||||
|
void sendChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
|
||||||
|
const QByteArray &reasonString);
|
||||||
quint32 nextClientSeqNr() const { return m_clientSeqNr; }
|
quint32 nextClientSeqNr() const { return m_clientSeqNr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
136
src/libs/ssh/sshtcpipforwardserver.cpp
Normal file
136
src/libs/ssh/sshtcpipforwardserver.cpp
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "sshtcpipforwardserver.h"
|
||||||
|
#include "sshtcpipforwardserver_p.h"
|
||||||
|
|
||||||
|
#include "sshlogging_p.h"
|
||||||
|
#include "sshsendfacility_p.h"
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
SshTcpIpForwardServerPrivate::SshTcpIpForwardServerPrivate(const QString &bindAddress,
|
||||||
|
quint16 bindPort, SshSendFacility &sendFacility)
|
||||||
|
: m_sendFacility(sendFacility),
|
||||||
|
m_bindAddress(bindAddress),
|
||||||
|
m_bindPort(bindPort),
|
||||||
|
m_state(SshTcpIpForwardServer::Inactive)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
using namespace Internal;
|
||||||
|
|
||||||
|
SshTcpIpForwardServer::SshTcpIpForwardServer(const QString &bindAddress, quint16 bindPort,
|
||||||
|
SshSendFacility &sendFacility)
|
||||||
|
: d(new SshTcpIpForwardServerPrivate(bindAddress, bindPort, sendFacility))
|
||||||
|
{
|
||||||
|
connect(&d->m_timeoutTimer, &QTimer::timeout, this, &SshTcpIpForwardServer::setClosed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpForwardServer::setListening(quint16 port)
|
||||||
|
{
|
||||||
|
QSSH_ASSERT_AND_RETURN(d->m_state != Listening);
|
||||||
|
d->m_bindPort = port;
|
||||||
|
d->m_state = Listening;
|
||||||
|
emit stateChanged(Listening);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpForwardServer::setClosed()
|
||||||
|
{
|
||||||
|
QSSH_ASSERT_AND_RETURN(d->m_state != Inactive);
|
||||||
|
d->m_state = Inactive;
|
||||||
|
emit stateChanged(Inactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpForwardServer::setNewConnection(const SshForwardedTcpIpTunnel::Ptr &connection)
|
||||||
|
{
|
||||||
|
d->m_pendingConnections.append(connection);
|
||||||
|
emit newConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
SshTcpIpForwardServer::~SshTcpIpForwardServer()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpForwardServer::initialize()
|
||||||
|
{
|
||||||
|
if (d->m_state == Inactive || d->m_state == Closing) {
|
||||||
|
try {
|
||||||
|
d->m_state = Initializing;
|
||||||
|
emit stateChanged(Initializing);
|
||||||
|
d->m_sendFacility.sendTcpIpForwardPacket(d->m_bindAddress.toUtf8(), d->m_bindPort);
|
||||||
|
d->m_timeoutTimer.start(d->ReplyTimeout);
|
||||||
|
} catch (const Botan::Exception &e) {
|
||||||
|
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||||
|
d->m_timeoutTimer.stop();
|
||||||
|
setClosed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpForwardServer::close()
|
||||||
|
{
|
||||||
|
d->m_timeoutTimer.stop();
|
||||||
|
|
||||||
|
if (d->m_state == Initializing || d->m_state == Listening) {
|
||||||
|
try {
|
||||||
|
d->m_state = Closing;
|
||||||
|
emit stateChanged(Closing);
|
||||||
|
d->m_sendFacility.sendCancelTcpIpForwardPacket(d->m_bindAddress.toUtf8(),
|
||||||
|
d->m_bindPort);
|
||||||
|
d->m_timeoutTimer.start(d->ReplyTimeout);
|
||||||
|
} catch (const Botan::Exception &e) {
|
||||||
|
qCWarning(sshLog, "Botan error: %s", e.what());
|
||||||
|
d->m_timeoutTimer.stop();
|
||||||
|
setClosed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &SshTcpIpForwardServer::bindAddress() const
|
||||||
|
{
|
||||||
|
return d->m_bindAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 SshTcpIpForwardServer::port() const
|
||||||
|
{
|
||||||
|
return d->m_bindPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
SshTcpIpForwardServer::State SshTcpIpForwardServer::state() const
|
||||||
|
{
|
||||||
|
return d->m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
SshForwardedTcpIpTunnel::Ptr SshTcpIpForwardServer::nextPendingConnection()
|
||||||
|
{
|
||||||
|
return d->m_pendingConnections.takeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QSsh
|
||||||
81
src/libs/ssh/sshtcpipforwardserver.h
Normal file
81
src/libs/ssh/sshtcpipforwardserver.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ssh_global.h"
|
||||||
|
#include "sshforwardedtcpiptunnel.h"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
class SshChannelManager;
|
||||||
|
class SshTcpIpForwardServerPrivate;
|
||||||
|
class SshSendFacility;
|
||||||
|
class SshConnectionPrivate;
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
class QSSH_EXPORT SshTcpIpForwardServer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class Internal::SshChannelManager;
|
||||||
|
friend class Internal::SshConnectionPrivate;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum State {
|
||||||
|
Inactive,
|
||||||
|
Initializing,
|
||||||
|
Listening,
|
||||||
|
Closing
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QSharedPointer<SshTcpIpForwardServer> Ptr;
|
||||||
|
~SshTcpIpForwardServer();
|
||||||
|
|
||||||
|
const QString &bindAddress() const;
|
||||||
|
quint16 port() const;
|
||||||
|
State state() const;
|
||||||
|
void initialize();
|
||||||
|
void close();
|
||||||
|
|
||||||
|
SshForwardedTcpIpTunnel::Ptr nextPendingConnection();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void error(const QString &reason);
|
||||||
|
void newConnection();
|
||||||
|
void stateChanged(State state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SshTcpIpForwardServer(const QString &bindAddress, quint16 bindPort,
|
||||||
|
Internal::SshSendFacility &sendFacility);
|
||||||
|
void setListening(quint16 port);
|
||||||
|
void setClosed();
|
||||||
|
void setNewConnection(const SshForwardedTcpIpTunnel::Ptr &connection);
|
||||||
|
|
||||||
|
Internal::SshTcpIpForwardServerPrivate * const d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QSsh
|
||||||
54
src/libs/ssh/sshtcpipforwardserver_p.h
Normal file
54
src/libs/ssh/sshtcpipforwardserver_p.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sshtcpipforwardserver.h"
|
||||||
|
#include <QList>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class SshTcpIpForwardServerPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int ReplyTimeout = 10000; // milli seconds
|
||||||
|
|
||||||
|
SshTcpIpForwardServerPrivate(const QString &bindAddress, quint16 bindPort,
|
||||||
|
SshSendFacility &sendFacility);
|
||||||
|
|
||||||
|
SshSendFacility &m_sendFacility;
|
||||||
|
QTimer m_timeoutTimer;
|
||||||
|
|
||||||
|
const QString m_bindAddress;
|
||||||
|
quint16 m_bindPort;
|
||||||
|
SshTcpIpForwardServer::State m_state;
|
||||||
|
|
||||||
|
QList<SshForwardedTcpIpTunnel::Ptr> m_pendingConnections;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QSsh
|
||||||
123
src/libs/ssh/sshtcpiptunnel.cpp
Normal file
123
src/libs/ssh/sshtcpiptunnel.cpp
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "sshsendfacility_p.h"
|
||||||
|
#include "sshtcpiptunnel_p.h"
|
||||||
|
|
||||||
|
#include "sshincomingpacket_p.h"
|
||||||
|
#include "sshexception_p.h"
|
||||||
|
#include "sshlogging_p.h"
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
SshTcpIpTunnelPrivate::SshTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility)
|
||||||
|
: AbstractSshChannel(channelId, sendFacility)
|
||||||
|
{
|
||||||
|
connect(this, &AbstractSshChannel::eof, this, &SshTcpIpTunnelPrivate::handleEof);
|
||||||
|
}
|
||||||
|
|
||||||
|
SshTcpIpTunnelPrivate::~SshTcpIpTunnelPrivate()
|
||||||
|
{
|
||||||
|
closeChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleChannelSuccess()
|
||||||
|
{
|
||||||
|
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
|
"Unexpected SSH_MSG_CHANNEL_SUCCESS message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleChannelFailure()
|
||||||
|
{
|
||||||
|
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
|
||||||
|
"Unexpected SSH_MSG_CHANNEL_FAILURE message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleOpenFailureInternal(const QString &reason)
|
||||||
|
{
|
||||||
|
emit error(reason);
|
||||||
|
closeChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleChannelDataInternal(const QByteArray &data)
|
||||||
|
{
|
||||||
|
m_data += data;
|
||||||
|
emit readyRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleChannelExtendedDataInternal(quint32 type,
|
||||||
|
const QByteArray &data)
|
||||||
|
{
|
||||||
|
qCWarning(sshLog, "%s: Unexpected extended channel data. Type is %u, content is '%s'.",
|
||||||
|
Q_FUNC_INFO, type, data.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus)
|
||||||
|
{
|
||||||
|
qCWarning(sshLog, "%s: Unexpected exit status %d.", Q_FUNC_INFO, exitStatus.exitStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleExitSignal(const SshChannelExitSignal &signal)
|
||||||
|
{
|
||||||
|
qCWarning(sshLog, "%s: Unexpected exit signal %s.", Q_FUNC_INFO, signal.signal.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::closeHook()
|
||||||
|
{
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SshTcpIpTunnelPrivate::handleEof()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* For some reason, the OpenSSH server only sends EOF when the remote port goes away,
|
||||||
|
* but does not close the channel, even though it becomes useless in that case.
|
||||||
|
* So we close it ourselves.
|
||||||
|
*/
|
||||||
|
closeChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SshTcpIpTunnelPrivate::readData(char *data, qint64 maxlen)
|
||||||
|
{
|
||||||
|
const qint64 bytesRead = qMin(qint64(m_data.count()), maxlen);
|
||||||
|
memcpy(data, m_data.constData(), bytesRead);
|
||||||
|
m_data.remove(0, bytesRead);
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SshTcpIpTunnelPrivate::writeData(const char *data, qint64 len)
|
||||||
|
{
|
||||||
|
QSSH_ASSERT_AND_RETURN_VALUE(channelState() == AbstractSshChannel::SessionEstablished, 0);
|
||||||
|
|
||||||
|
sendData(QByteArray(data, len));
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
} // namespace QSsh
|
||||||
82
src/libs/ssh/sshtcpiptunnel_p.h
Normal file
82
src/libs/ssh/sshtcpiptunnel_p.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sshchannel_p.h"
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class SshTcpIpTunnelPrivate : public AbstractSshChannel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SshTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility);
|
||||||
|
~SshTcpIpTunnelPrivate();
|
||||||
|
|
||||||
|
template<class SshTcpIpTunnel>
|
||||||
|
void init(SshTcpIpTunnel *q)
|
||||||
|
{
|
||||||
|
connect(this, &SshTcpIpTunnelPrivate::closed,
|
||||||
|
q, &SshTcpIpTunnel::close, Qt::QueuedConnection);
|
||||||
|
connect(this, &SshTcpIpTunnelPrivate::readyRead,
|
||||||
|
q, &SshTcpIpTunnel::readyRead, Qt::QueuedConnection);
|
||||||
|
connect(this, &SshTcpIpTunnelPrivate::error, q, [q](const QString &reason) {
|
||||||
|
q->setErrorString(reason);
|
||||||
|
emit q->error(reason);
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleChannelSuccess() override;
|
||||||
|
void handleChannelFailure() override;
|
||||||
|
|
||||||
|
qint64 readData(char *data, qint64 maxlen);
|
||||||
|
qint64 writeData(const char *data, qint64 len);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void readyRead();
|
||||||
|
void error(const QString &reason);
|
||||||
|
void closed();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleEof();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void handleOpenFailureInternal(const QString &reason) override;
|
||||||
|
void handleChannelDataInternal(const QByteArray &data) override;
|
||||||
|
void handleChannelExtendedDataInternal(quint32 type, const QByteArray &data) override;
|
||||||
|
void handleExitStatus(const SshChannelExitStatus &exitStatus) override;
|
||||||
|
void handleExitSignal(const SshChannelExitSignal &signal) override;
|
||||||
|
void closeHook() override;
|
||||||
|
|
||||||
|
QByteArray m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace QSsh
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "tunnel.h"
|
#include "directtunnel.h"
|
||||||
|
|
||||||
#include <ssh/sshconnection.h>
|
#include <ssh/sshconnection.h>
|
||||||
#include <ssh/sshdirecttcpiptunnel.h>
|
#include <ssh/sshdirecttcpiptunnel.h>
|
||||||
@@ -41,7 +41,7 @@ const QByteArray TestData("Urgsblubb?");
|
|||||||
|
|
||||||
using namespace QSsh;
|
using namespace QSsh;
|
||||||
|
|
||||||
Tunnel::Tunnel(const SshConnectionParameters ¶meters, QObject *parent)
|
DirectTunnel::DirectTunnel(const SshConnectionParameters ¶meters, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
m_connection(new SshConnection(parameters, this)),
|
m_connection(new SshConnection(parameters, this)),
|
||||||
m_targetServer(new QTcpServer(this)),
|
m_targetServer(new QTcpServer(this)),
|
||||||
@@ -51,46 +51,46 @@ Tunnel::Tunnel(const SshConnectionParameters ¶meters, QObject *parent)
|
|||||||
connect(m_connection, SIGNAL(error(QSsh::SshError)), SLOT(handleConnectionError()));
|
connect(m_connection, SIGNAL(error(QSsh::SshError)), SLOT(handleConnectionError()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Tunnel::~Tunnel()
|
DirectTunnel::~DirectTunnel()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::run()
|
void DirectTunnel::run()
|
||||||
{
|
{
|
||||||
std::cout << "Connecting to SSH server..." << std::endl;
|
std::cout << "Connecting to SSH server..." << std::endl;
|
||||||
m_connection->connectToHost();
|
m_connection->connectToHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleConnectionError()
|
void DirectTunnel::handleConnectionError()
|
||||||
{
|
{
|
||||||
std::cerr << "SSH connection error: " << qPrintable(m_connection->errorString()) << std::endl;
|
std::cerr << "SSH connection error: " << qPrintable(m_connection->errorString()) << std::endl;
|
||||||
qApp->exit(EXIT_FAILURE);
|
emit finished(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleConnected()
|
void DirectTunnel::handleConnected()
|
||||||
{
|
{
|
||||||
std::cout << "Opening server side..." << std::endl;
|
std::cout << "Opening server side..." << std::endl;
|
||||||
if (!m_targetServer->listen(QHostAddress::LocalHost)) {
|
if (!m_targetServer->listen(QHostAddress::LocalHost)) {
|
||||||
std::cerr << "Error opening port: "
|
std::cerr << "Error opening port: "
|
||||||
<< m_targetServer->errorString().toLocal8Bit().constData() << std::endl;
|
<< m_targetServer->errorString().toLocal8Bit().constData() << std::endl;
|
||||||
qApp->exit(EXIT_FAILURE);
|
emit finished(EXIT_FAILURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_targetPort = m_targetServer->serverPort();
|
m_targetPort = m_targetServer->serverPort();
|
||||||
connect(m_targetServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
|
connect(m_targetServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
|
||||||
|
|
||||||
m_tunnel = m_connection->createTunnel(QLatin1String("localhost"), 1024, // made-up values
|
m_tunnel = m_connection->createDirectTunnel(QLatin1String("localhost"), 1024, // made-up values
|
||||||
QLatin1String("localhost"), m_targetPort);
|
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()));
|
||||||
connect(m_tunnel.data(), SIGNAL(tunnelClosed()), SLOT(handleTunnelClosed()));
|
connect(m_tunnel.data(), SIGNAL(aboutToClose()), SLOT(handleTunnelClosed()));
|
||||||
|
|
||||||
std::cout << "Initializing tunnel..." << std::endl;
|
std::cout << "Initializing tunnel..." << std::endl;
|
||||||
m_tunnel->initialize();
|
m_tunnel->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleInitialized()
|
void DirectTunnel::handleInitialized()
|
||||||
{
|
{
|
||||||
std::cout << "Writing data into the tunnel..." << std::endl;
|
std::cout << "Writing data into the tunnel..." << std::endl;
|
||||||
m_tunnel->write(TestData);
|
m_tunnel->write(TestData);
|
||||||
@@ -99,7 +99,7 @@ void Tunnel::handleInitialized()
|
|||||||
timeoutTimer->start(10000);
|
timeoutTimer->start(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleServerData()
|
void DirectTunnel::handleServerData()
|
||||||
{
|
{
|
||||||
m_dataReceivedFromServer += m_tunnel->readAll();
|
m_dataReceivedFromServer += m_tunnel->readAll();
|
||||||
if (m_dataReceivedFromServer == ServerDataPrefix + TestData) {
|
if (m_dataReceivedFromServer == ServerDataPrefix + TestData) {
|
||||||
@@ -109,25 +109,25 @@ void Tunnel::handleServerData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleTunnelError(const QString &reason)
|
void DirectTunnel::handleTunnelError(const QString &reason)
|
||||||
{
|
{
|
||||||
std::cerr << "Tunnel error: " << reason.toLocal8Bit().constData() << std::endl;
|
std::cerr << "Tunnel error: " << reason.toLocal8Bit().constData() << std::endl;
|
||||||
qApp->exit(EXIT_FAILURE);
|
emit finished(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleTunnelClosed()
|
void DirectTunnel::handleTunnelClosed()
|
||||||
{
|
{
|
||||||
if (m_expectingChannelClose) {
|
if (m_expectingChannelClose) {
|
||||||
std::cout << "Successfully detected channel close." << std::endl;
|
std::cout << "Successfully detected channel close." << std::endl;
|
||||||
std::cout << "Test finished successfully." << std::endl;
|
std::cout << "Test finished successfully." << std::endl;
|
||||||
qApp->quit();
|
emit finished(EXIT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Error: Remote host closed channel." << std::endl;
|
std::cerr << "Error: Remote host closed channel." << std::endl;
|
||||||
qApp->exit(EXIT_FAILURE);
|
emit finished(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleNewConnection()
|
void DirectTunnel::handleNewConnection()
|
||||||
{
|
{
|
||||||
m_targetSocket = m_targetServer->nextPendingConnection();
|
m_targetSocket = m_targetServer->nextPendingConnection();
|
||||||
m_targetServer->close();
|
m_targetServer->close();
|
||||||
@@ -136,14 +136,14 @@ void Tunnel::handleNewConnection()
|
|||||||
handleClientData();
|
handleClientData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleSocketError()
|
void DirectTunnel::handleSocketError()
|
||||||
{
|
{
|
||||||
std::cerr << "Socket error: " << m_targetSocket->errorString().toLocal8Bit().constData()
|
std::cerr << "Socket error: " << m_targetSocket->errorString().toLocal8Bit().constData()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
qApp->exit(EXIT_FAILURE);
|
emit finished(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleClientData()
|
void DirectTunnel::handleClientData()
|
||||||
{
|
{
|
||||||
m_dataReceivedFromClient += m_targetSocket->readAll();
|
m_dataReceivedFromClient += m_targetSocket->readAll();
|
||||||
if (m_dataReceivedFromClient == TestData) {
|
if (m_dataReceivedFromClient == TestData) {
|
||||||
@@ -153,8 +153,8 @@ void Tunnel::handleClientData()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnel::handleTimeout()
|
void DirectTunnel::handleTimeout()
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Timeout waiting for test completion." << std::endl;
|
std::cerr << "Error: Timeout waiting for test completion." << std::endl;
|
||||||
qApp->exit(EXIT_FAILURE);
|
emit finished(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -39,15 +39,18 @@ class SshConnectionParameters;
|
|||||||
class SshDirectTcpIpTunnel;
|
class SshDirectTcpIpTunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Tunnel : public QObject
|
class DirectTunnel : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Tunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent = 0);
|
DirectTunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent = 0);
|
||||||
~Tunnel();
|
~DirectTunnel();
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(int errorCode);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleConnected();
|
void handleConnected();
|
||||||
void handleConnectionError();
|
void handleConnectionError();
|
||||||
146
tests/manual/ssh/tunnel/forwardtunnel.cpp
Normal file
146
tests/manual/ssh/tunnel/forwardtunnel.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "forwardtunnel.h"
|
||||||
|
|
||||||
|
#include <ssh/sshconnection.h>
|
||||||
|
#include <ssh/sshtcpipforwardserver.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
const QByteArray ClientDataPrefix("Received the following data: ");
|
||||||
|
const QByteArray TestData("Urgsblubb?");
|
||||||
|
|
||||||
|
ForwardTunnel::ForwardTunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent)
|
||||||
|
: QObject(parent),
|
||||||
|
m_connection(new QSsh::SshConnection(parameters, this)),
|
||||||
|
m_targetSocket(0),
|
||||||
|
m_targetPort(0)
|
||||||
|
{
|
||||||
|
connect(m_connection, &QSsh::SshConnection::connected, this, &ForwardTunnel::handleConnected);
|
||||||
|
connect(m_connection, &QSsh::SshConnection::error, this, &ForwardTunnel::handleConnectionError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::run()
|
||||||
|
{
|
||||||
|
std::cout << "Connecting to SSH server..." << std::endl;
|
||||||
|
m_connection->connectToHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleConnected()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
QTcpServer server;
|
||||||
|
if (server.listen(QHostAddress::LocalHost)) {
|
||||||
|
m_targetPort = server.serverPort();
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error while searching for free port: "
|
||||||
|
<< server.errorString().toLocal8Bit().constData() << std::endl;
|
||||||
|
emit finished(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Initializing tunnel..." << std::endl;
|
||||||
|
m_server = m_connection->createForwardServer(QLatin1String("localhost"), m_targetPort);
|
||||||
|
connect(m_server.data(), &QSsh::SshTcpIpForwardServer::newConnection,
|
||||||
|
this, &ForwardTunnel::handleNewConnection);
|
||||||
|
connect(m_server.data(), &QSsh::SshTcpIpForwardServer::stateChanged,
|
||||||
|
this, [this](QSsh::SshTcpIpForwardServer::State state) {
|
||||||
|
if (state == QSsh::SshTcpIpForwardServer::Listening)
|
||||||
|
handleInitialized();
|
||||||
|
else if (state == QSsh::SshTcpIpForwardServer::Inactive)
|
||||||
|
handleServerClosed();
|
||||||
|
});
|
||||||
|
connect(m_server.data(), &QSsh::SshTcpIpForwardServer::error,
|
||||||
|
this, &ForwardTunnel::handleServerError);
|
||||||
|
|
||||||
|
m_server->initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleConnectionError(QSsh::SshError error)
|
||||||
|
{
|
||||||
|
std::cout << "SSH connection error: " << error << " " << qPrintable(m_connection->errorString())
|
||||||
|
<< std::endl;
|
||||||
|
emit finished(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleInitialized()
|
||||||
|
{
|
||||||
|
std::cout << "Forward tunnel initialized, connecting ..." << std::endl;
|
||||||
|
m_targetSocket = new QTcpSocket(this);
|
||||||
|
connect(m_targetSocket, &QTcpSocket::connected, this, [this](){
|
||||||
|
m_targetSocket->write(ClientDataPrefix + TestData);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_targetSocket, &QTcpSocket::readyRead, this, [this](){
|
||||||
|
m_dataReceivedFromServer += m_targetSocket->readAll();
|
||||||
|
if (m_dataReceivedFromServer == ClientDataPrefix + TestData) {
|
||||||
|
std::cout << "Data exchange successful. Closing client socket..." << std::endl;
|
||||||
|
m_targetSocket->close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_targetSocket->connectToHost(QLatin1String("localhost"), m_targetPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleServerError(const QString &reason)
|
||||||
|
{
|
||||||
|
std::cerr << "Tunnel error:" << reason.toUtf8().constData() << std::endl;
|
||||||
|
emit finished(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleServerClosed()
|
||||||
|
{
|
||||||
|
std::cout << "Forward tunnel closed" << std::endl;
|
||||||
|
emit finished(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleNewConnection()
|
||||||
|
{
|
||||||
|
std::cout << "Connection established" << std::endl;
|
||||||
|
QSsh::SshForwardedTcpIpTunnel::Ptr tunnel = m_server->nextPendingConnection();
|
||||||
|
|
||||||
|
connect(tunnel.data(), &QIODevice::readyRead, this, [this, tunnel](){
|
||||||
|
m_dataReceivedFromClient += tunnel->readAll();
|
||||||
|
if (m_dataReceivedFromClient == ClientDataPrefix + TestData) {
|
||||||
|
std::cout << "Data received successful. Sending it back..." << std::endl;
|
||||||
|
tunnel->write(m_dataReceivedFromClient);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(tunnel.data(), &QIODevice::aboutToClose, this, [this](){
|
||||||
|
std::cout << "Server Connection closed, closing tunnel" << std::endl;
|
||||||
|
m_server->close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardTunnel::handleSocketError()
|
||||||
|
{
|
||||||
|
std::cerr << "Socket error" << std::endl;
|
||||||
|
emit finished(EXIT_FAILURE);
|
||||||
|
}
|
||||||
71
tests/manual/ssh/tunnel/forwardtunnel.h
Normal file
71
tests/manual/ssh/tunnel/forwardtunnel.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ssh/ssherrors.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QTcpSocket;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace QSsh {
|
||||||
|
class SshConnection;
|
||||||
|
class SshConnectionParameters;
|
||||||
|
class SshTcpIpForwardServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ForwardTunnel : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ForwardTunnel(const QSsh::SshConnectionParameters ¶meters,
|
||||||
|
QObject *parent = 0);
|
||||||
|
void run();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(int exitCode);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleConnected();
|
||||||
|
void handleConnectionError(QSsh::SshError error);
|
||||||
|
void handleInitialized();
|
||||||
|
void handleServerError(const QString &reason);
|
||||||
|
void handleServerClosed();
|
||||||
|
void handleNewConnection();
|
||||||
|
void handleSocketError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSsh::SshConnection * const m_connection;
|
||||||
|
QSharedPointer<QSsh::SshTcpIpForwardServer> m_server;
|
||||||
|
QTcpSocket *m_targetSocket;
|
||||||
|
quint16 m_targetPort;
|
||||||
|
|
||||||
|
QByteArray m_dataReceivedFromServer;
|
||||||
|
QByteArray m_dataReceivedFromClient;
|
||||||
|
};
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "../remoteprocess/argumentscollector.h"
|
#include "../remoteprocess/argumentscollector.h"
|
||||||
#include "tunnel.h"
|
#include "directtunnel.h"
|
||||||
|
#include "forwardtunnel.h"
|
||||||
|
|
||||||
#include <ssh/sshconnection.h>
|
#include <ssh/sshconnection.h>
|
||||||
|
|
||||||
@@ -44,7 +45,15 @@ int main(int argc, char *argv[])
|
|||||||
parameters.host = QLatin1String("127.0.0.1");
|
parameters.host = QLatin1String("127.0.0.1");
|
||||||
if (!parseSuccess)
|
if (!parseSuccess)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
Tunnel tunnel(parameters);
|
|
||||||
tunnel.run();
|
DirectTunnel direct(parameters);
|
||||||
|
|
||||||
|
parameters.host = QLatin1String("127.0.0.2");
|
||||||
|
ForwardTunnel forward(parameters);
|
||||||
|
forward.run();
|
||||||
|
|
||||||
|
QObject::connect(&forward, &ForwardTunnel::finished, &direct, &DirectTunnel::run);
|
||||||
|
QObject::connect(&direct, &DirectTunnel::finished, &app, &QCoreApplication::exit);
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
include(../ssh.pri)
|
include(../ssh.pri)
|
||||||
|
|
||||||
TARGET=tunnel
|
TARGET =tunnel
|
||||||
SOURCES=main.cpp tunnel.cpp argumentscollector.cpp
|
SOURCES = \
|
||||||
HEADERS=tunnel.h argumentscollector.h
|
main.cpp \
|
||||||
|
argumentscollector.cpp \
|
||||||
|
directtunnel.cpp \
|
||||||
|
forwardtunnel.cpp
|
||||||
|
HEADERS = \
|
||||||
|
argumentscollector.h \
|
||||||
|
directtunnel.h \
|
||||||
|
forwardtunnel.h
|
||||||
|
|||||||
Reference in New Issue
Block a user