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/sshdirecttcpiptunnel.cpp \
 | 
			
		||||
    $$PWD/sshlogging.cpp \
 | 
			
		||||
    $$PWD/sshhostkeydatabase.cpp
 | 
			
		||||
    $$PWD/sshhostkeydatabase.cpp \
 | 
			
		||||
    $$PWD/sshtcpipforwardserver.cpp \
 | 
			
		||||
    $$PWD/sshtcpiptunnel.cpp \
 | 
			
		||||
    $$PWD/sshforwardedtcpiptunnel.cpp
 | 
			
		||||
 | 
			
		||||
HEADERS = $$PWD/sshsendfacility_p.h \
 | 
			
		||||
    $$PWD/sshremoteprocess.h \
 | 
			
		||||
@@ -68,7 +71,12 @@ HEADERS = $$PWD/sshsendfacility_p.h \
 | 
			
		||||
    $$PWD/sshinit_p.h \
 | 
			
		||||
    $$PWD/sshdirecttcpiptunnel.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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ QtcLibrary {
 | 
			
		||||
        "sshdirecttcpiptunnel.h", "sshdirecttcpiptunnel_p.h", "sshdirecttcpiptunnel.cpp",
 | 
			
		||||
        "ssherrors.h",
 | 
			
		||||
        "sshexception_p.h",
 | 
			
		||||
        "sshforwardedtcpiptunnel.cpp", "sshforwardedtcpiptunnel.h", "sshforwardedtcpiptunnel_p.h",
 | 
			
		||||
        "sshhostkeydatabase.cpp",
 | 
			
		||||
        "sshhostkeydatabase.h",
 | 
			
		||||
        "sshincomingpacket_p.h", "sshincomingpacket.cpp",
 | 
			
		||||
@@ -46,6 +47,8 @@ QtcLibrary {
 | 
			
		||||
        "sshremoteprocess.cpp", "sshremoteprocess.h", "sshremoteprocess_p.h",
 | 
			
		||||
        "sshremoteprocessrunner.cpp", "sshremoteprocessrunner.h",
 | 
			
		||||
        "sshsendfacility.cpp", "sshsendfacility_p.h",
 | 
			
		||||
        "sshtcpipforwardserver.cpp", "sshtcpipforwardserver.h", "sshtcpipforwardserver_p.h",
 | 
			
		||||
        "sshtcpiptunnel.cpp", "sshtcpiptunnel_p.h",
 | 
			
		||||
    ].concat(botanFiles)
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
    default:
 | 
			
		||||
        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();
 | 
			
		||||
 
 | 
			
		||||
@@ -29,10 +29,15 @@
 | 
			
		||||
#include "sftpchannel_p.h"
 | 
			
		||||
#include "sshdirecttcpiptunnel.h"
 | 
			
		||||
#include "sshdirecttcpiptunnel_p.h"
 | 
			
		||||
#include "sshforwardedtcpiptunnel.h"
 | 
			
		||||
#include "sshforwardedtcpiptunnel_p.h"
 | 
			
		||||
#include "sshincomingpacket_p.h"
 | 
			
		||||
#include "sshlogging_p.h"
 | 
			
		||||
#include "sshremoteprocess.h"
 | 
			
		||||
#include "sshremoteprocess_p.h"
 | 
			
		||||
#include "sshsendfacility_p.h"
 | 
			
		||||
#include "sshtcpipforwardserver.h"
 | 
			
		||||
#include "sshtcpipforwardserver_p.h"
 | 
			
		||||
 | 
			
		||||
#include <QList>
 | 
			
		||||
 | 
			
		||||
@@ -51,10 +56,54 @@ void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet)
 | 
			
		||||
        ->handleChannelRequest(packet);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &)
 | 
			
		||||
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet)
 | 
			
		||||
{
 | 
			
		||||
    throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
 | 
			
		||||
        "Server tried to open channel on client.");
 | 
			
		||||
    SshChannelOpen channelOpen = packet.extractChannelOpen();
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
@@ -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,
 | 
			
		||||
    bool allowNotFound)
 | 
			
		||||
{
 | 
			
		||||
@@ -165,7 +247,7 @@ QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
 | 
			
		||||
    return sftp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(const QString &originatingHost,
 | 
			
		||||
SshDirectTcpIpTunnel::Ptr SshChannelManager::createDirectTunnel(const QString &originatingHost,
 | 
			
		||||
        quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
 | 
			
		||||
{
 | 
			
		||||
    SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
 | 
			
		||||
@@ -174,6 +256,28 @@ SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(const QString &origina
 | 
			
		||||
    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,
 | 
			
		||||
    const QSharedPointer<QObject> &pub)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ namespace QSsh {
 | 
			
		||||
class SftpChannel;
 | 
			
		||||
class SshDirectTcpIpTunnel;
 | 
			
		||||
class SshRemoteProcess;
 | 
			
		||||
class SshTcpIpForwardServer;
 | 
			
		||||
 | 
			
		||||
namespace Internal {
 | 
			
		||||
 | 
			
		||||
@@ -49,8 +50,10 @@ public:
 | 
			
		||||
    QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
 | 
			
		||||
    QSharedPointer<SshRemoteProcess> createRemoteShell();
 | 
			
		||||
    QSharedPointer<SftpChannel> createSftpChannel();
 | 
			
		||||
    QSharedPointer<SshDirectTcpIpTunnel> createTunnel(const QString &originatingHost,
 | 
			
		||||
    QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
 | 
			
		||||
            quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
 | 
			
		||||
    QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
 | 
			
		||||
            quint16 remotePort);
 | 
			
		||||
 | 
			
		||||
    int channelCount() const;
 | 
			
		||||
    enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
 | 
			
		||||
@@ -67,6 +70,8 @@ public:
 | 
			
		||||
    void handleChannelExtendedData(const SshIncomingPacket &packet);
 | 
			
		||||
    void handleChannelEof(const SshIncomingPacket &packet);
 | 
			
		||||
    void handleChannelClose(const SshIncomingPacket &packet);
 | 
			
		||||
    void handleRequestSuccess(const SshIncomingPacket &packet);
 | 
			
		||||
    void handleRequestFailure(const SshIncomingPacket &packet);
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void timeout();
 | 
			
		||||
@@ -86,6 +91,8 @@ private:
 | 
			
		||||
    QHash<quint32, AbstractSshChannel *> m_channels;
 | 
			
		||||
    QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions;
 | 
			
		||||
    quint32 m_nextLocalChannelId;
 | 
			
		||||
    QList<QSharedPointer<SshTcpIpForwardServer>> m_waitingForwardServers;
 | 
			
		||||
    QList<QSharedPointer<SshTcpIpForwardServer>> m_listeningForwardServers;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#include "sshchannelmanager_p.h"
 | 
			
		||||
#include "sshcryptofacility_p.h"
 | 
			
		||||
#include "sshdirecttcpiptunnel.h"
 | 
			
		||||
#include "sshtcpipforwardserver.h"
 | 
			
		||||
#include "sshexception_p.h"
 | 
			
		||||
#include "sshinit_p.h"
 | 
			
		||||
#include "sshkeyexchange_p.h"
 | 
			
		||||
@@ -180,11 +181,18 @@ QSharedPointer<SftpChannel> SshConnection::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)
 | 
			
		||||
{
 | 
			
		||||
    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()
 | 
			
		||||
@@ -296,6 +304,11 @@ void SshConnectionPrivate::setupPacketHandlers()
 | 
			
		||||
 | 
			
		||||
    setupPacketHandler(SSH_MSG_UNIMPLEMENTED,
 | 
			
		||||
        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,
 | 
			
		||||
@@ -680,7 +693,15 @@ void SshConnectionPrivate::handleDisconnect()
 | 
			
		||||
        "", 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)
 | 
			
		||||
{
 | 
			
		||||
@@ -820,10 +841,17 @@ QSharedPointer<SftpChannel> SshConnectionPrivate::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)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@ namespace QSsh {
 | 
			
		||||
class SftpChannel;
 | 
			
		||||
class SshDirectTcpIpTunnel;
 | 
			
		||||
class SshRemoteProcess;
 | 
			
		||||
class SshTcpIpForwardServer;
 | 
			
		||||
 | 
			
		||||
namespace Internal { class SshConnectionPrivate; }
 | 
			
		||||
 | 
			
		||||
@@ -121,8 +122,10 @@ public:
 | 
			
		||||
    QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
 | 
			
		||||
    QSharedPointer<SshRemoteProcess> createRemoteShell();
 | 
			
		||||
    QSharedPointer<SftpChannel> createSftpChannel();
 | 
			
		||||
    QSharedPointer<SshDirectTcpIpTunnel> createTunnel(const QString &originatingHost,
 | 
			
		||||
    QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
 | 
			
		||||
            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.
 | 
			
		||||
    int closeAllChannels();
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@ namespace QSsh {
 | 
			
		||||
class SftpChannel;
 | 
			
		||||
class SshRemoteProcess;
 | 
			
		||||
class SshDirectTcpIpTunnel;
 | 
			
		||||
class SshTcpIpForwardServer;
 | 
			
		||||
 | 
			
		||||
namespace Internal {
 | 
			
		||||
class SshChannelManager;
 | 
			
		||||
@@ -83,8 +84,10 @@ public:
 | 
			
		||||
    QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
 | 
			
		||||
    QSharedPointer<SshRemoteProcess> createRemoteShell();
 | 
			
		||||
    QSharedPointer<SftpChannel> createSftpChannel();
 | 
			
		||||
    QSharedPointer<SshDirectTcpIpTunnel> createTunnel(const QString &originatingHost,
 | 
			
		||||
    QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
 | 
			
		||||
            quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
 | 
			
		||||
    QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
 | 
			
		||||
            quint16 remotePort);
 | 
			
		||||
 | 
			
		||||
    SshStateInternal state() const { return m_state; }
 | 
			
		||||
    SshError error() const { return m_error; }
 | 
			
		||||
@@ -132,6 +135,9 @@ private:
 | 
			
		||||
    void handleChannelEof();
 | 
			
		||||
    void handleChannelClose();
 | 
			
		||||
    void handleDisconnect();
 | 
			
		||||
    void handleRequestSuccess();
 | 
			
		||||
    void handleRequestFailure();
 | 
			
		||||
 | 
			
		||||
    bool canUseSocket() const;
 | 
			
		||||
    void createPrivateKey();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,25 +38,12 @@ namespace Internal {
 | 
			
		||||
SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId,
 | 
			
		||||
        const QString &originatingHost, quint16 originatingPort, const QString &remoteHost,
 | 
			
		||||
        quint16 remotePort, SshSendFacility &sendFacility)
 | 
			
		||||
    : AbstractSshChannel(channelId, sendFacility),
 | 
			
		||||
    : SshTcpIpTunnelPrivate(channelId, sendFacility),
 | 
			
		||||
      m_originatingHost(originatingHost),
 | 
			
		||||
      m_originatingPort(originatingPort),
 | 
			
		||||
      m_remoteHost(remoteHost),
 | 
			
		||||
      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()
 | 
			
		||||
@@ -64,50 +51,6 @@ void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
using namespace Internal;
 | 
			
		||||
@@ -118,15 +61,13 @@ SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, const QString &ori
 | 
			
		||||
    : d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost,
 | 
			
		||||
                                        remotePort, sendFacility))
 | 
			
		||||
{
 | 
			
		||||
    connect(d, SIGNAL(initialized()), SIGNAL(initialized()), Qt::QueuedConnection);
 | 
			
		||||
    connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::QueuedConnection);
 | 
			
		||||
    connect(d, SIGNAL(closed()), SIGNAL(tunnelClosed()), Qt::QueuedConnection);
 | 
			
		||||
    connect(d, SIGNAL(error(QString)), SLOT(handleError(QString)), Qt::QueuedConnection);
 | 
			
		||||
    d->init(this);
 | 
			
		||||
    connect(d, &SshDirectTcpIpTunnelPrivate::initialized,
 | 
			
		||||
            this, &SshDirectTcpIpTunnel::initialized, Qt::QueuedConnection);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel()
 | 
			
		||||
{
 | 
			
		||||
    d->closeChannel();
 | 
			
		||||
    delete d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -170,24 +111,12 @@ void SshDirectTcpIpTunnel::initialize()
 | 
			
		||||
 | 
			
		||||
qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen)
 | 
			
		||||
{
 | 
			
		||||
    const qint64 bytesRead = qMin(qint64(d->m_data.count()), maxlen);
 | 
			
		||||
    memcpy(data, d->m_data.constData(), bytesRead);
 | 
			
		||||
    d->m_data.remove(0, bytesRead);
 | 
			
		||||
    return bytesRead;
 | 
			
		||||
    return d->readData(data, maxlen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len)
 | 
			
		||||
{
 | 
			
		||||
    QSSH_ASSERT_AND_RETURN_VALUE(d->channelState() == AbstractSshChannel::SessionEstablished, 0);
 | 
			
		||||
 | 
			
		||||
    d->sendData(QByteArray(data, len));
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SshDirectTcpIpTunnel::handleError(const QString &reason)
 | 
			
		||||
{
 | 
			
		||||
    setErrorString(reason);
 | 
			
		||||
    emit error(reason);
 | 
			
		||||
    return d->writeData(data, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace QSsh
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@ namespace Internal {
 | 
			
		||||
class SshChannelManager;
 | 
			
		||||
class SshDirectTcpIpTunnelPrivate;
 | 
			
		||||
class SshSendFacility;
 | 
			
		||||
class SshTcpIpTunnelPrivate;
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
 | 
			
		||||
class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
 | 
			
		||||
@@ -43,6 +44,7 @@ class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
    friend class Internal::SshChannelManager;
 | 
			
		||||
    friend class Internal::SshTcpIpTunnelPrivate;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    typedef QSharedPointer<SshDirectTcpIpTunnel> Ptr;
 | 
			
		||||
@@ -61,7 +63,6 @@ public:
 | 
			
		||||
signals:
 | 
			
		||||
    void initialized();
 | 
			
		||||
    void error(const QString &reason);
 | 
			
		||||
    void tunnelClosed();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
 | 
			
		||||
@@ -72,8 +73,6 @@ private:
 | 
			
		||||
    qint64 readData(char *data, qint64 maxlen);
 | 
			
		||||
    qint64 writeData(const char *data, qint64 len);
 | 
			
		||||
 | 
			
		||||
    Q_SLOT void handleError(const QString &reason);
 | 
			
		||||
 | 
			
		||||
    Internal::SshDirectTcpIpTunnelPrivate * const d;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,14 +25,14 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "sshchannel_p.h"
 | 
			
		||||
#include "sshtcpiptunnel_p.h"
 | 
			
		||||
 | 
			
		||||
namespace QSsh {
 | 
			
		||||
class SshDirectTcpIpTunnel;
 | 
			
		||||
 | 
			
		||||
namespace Internal {
 | 
			
		||||
 | 
			
		||||
class SshDirectTcpIpTunnelPrivate : public AbstractSshChannel
 | 
			
		||||
class SshDirectTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
@@ -45,31 +45,14 @@ public:
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void initialized();
 | 
			
		||||
    void readyRead();
 | 
			
		||||
    void error(const QString &reason);
 | 
			
		||||
    void closed();
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void handleEof();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void handleChannelSuccess();
 | 
			
		||||
    void handleChannelFailure();
 | 
			
		||||
 | 
			
		||||
    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 quint16 m_originatingPort;
 | 
			
		||||
    const QString m_remoteHost;
 | 
			
		||||
    const quint16 m_remotePort;
 | 
			
		||||
    QByteArray m_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // 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::ExitSignalType("exit-signal");
 | 
			
		||||
const QByteArray SshIncomingPacket::ForwardedTcpIpType("forwarded-tcpip");
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
{
 | 
			
		||||
    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
 | 
			
		||||
{
 | 
			
		||||
    Q_ASSERT(isComplete());
 | 
			
		||||
 
 | 
			
		||||
@@ -97,6 +97,20 @@ struct SshUnimplemented
 | 
			
		||||
    quint32 invalidMsgSeqNr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SshRequestSuccess
 | 
			
		||||
{
 | 
			
		||||
    quint32 bindPort;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SshChannelOpen
 | 
			
		||||
{
 | 
			
		||||
    quint32 remoteChannel;
 | 
			
		||||
    quint32 remoteWindowSize;
 | 
			
		||||
    quint32 remoteMaxPacketSize;
 | 
			
		||||
    QByteArray remoteAddress;
 | 
			
		||||
    quint32 remotePort;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SshChannelOpenFailure
 | 
			
		||||
{
 | 
			
		||||
    quint32 localChannel;
 | 
			
		||||
@@ -147,7 +161,6 @@ struct SshChannelExitSignal
 | 
			
		||||
    QByteArray language;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SshIncomingPacket : public AbstractSshPacket
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
@@ -164,8 +177,10 @@ public:
 | 
			
		||||
    SshUserAuthBanner extractUserAuthBanner() const;
 | 
			
		||||
    SshUserAuthInfoRequestPacket extractUserAuthInfoRequest() const;
 | 
			
		||||
    SshDebug extractDebug() const;
 | 
			
		||||
    SshRequestSuccess extractRequestSuccess() const;
 | 
			
		||||
    SshUnimplemented extractUnimplemented() const;
 | 
			
		||||
 | 
			
		||||
    SshChannelOpen extractChannelOpen() const;
 | 
			
		||||
    SshChannelOpenFailure extractChannelOpenFailure() const;
 | 
			
		||||
    SshChannelOpenConfirmation extractChannelOpenConfirmation() const;
 | 
			
		||||
    SshChannelWindowAdjust extractWindowAdjust() const;
 | 
			
		||||
@@ -180,6 +195,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    static const QByteArray ExitStatusType;
 | 
			
		||||
    static const QByteArray ExitSignalType;
 | 
			
		||||
    static const QByteArray ForwardedTcpIpType;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    virtual quint32 cipherBlockSize() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -179,6 +179,19 @@ void SshOutgoingPacket::generateDirectTcpIpPacket(quint32 channelId, quint32 win
 | 
			
		||||
            .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,
 | 
			
		||||
    const QByteArray &var, const QByteArray &value)
 | 
			
		||||
{
 | 
			
		||||
@@ -255,6 +268,22 @@ void SshOutgoingPacket::generateChannelClosePacket(quint32 remoteChannel)
 | 
			
		||||
    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,
 | 
			
		||||
    const QByteArray &reasonString)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,8 @@ public:
 | 
			
		||||
    void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
 | 
			
		||||
        quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
 | 
			
		||||
        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,
 | 
			
		||||
        const QByteArray &value);
 | 
			
		||||
    void generatePtyRequestPacket(quint32 remoteChannel,
 | 
			
		||||
@@ -79,6 +81,10 @@ public:
 | 
			
		||||
        const QByteArray &signalName);
 | 
			
		||||
    void generateChannelEofPacket(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:
 | 
			
		||||
    virtual quint32 cipherBlockSize() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,13 @@ enum SshPacketType {
 | 
			
		||||
    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 };
 | 
			
		||||
 | 
			
		||||
class SshAbstractCryptoFacility;
 | 
			
		||||
 
 | 
			
		||||
@@ -172,6 +172,18 @@ void SshSendFacility::sendDirectTcpIpPacket(quint32 channelId, quint32 windowSiz
 | 
			
		||||
    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,
 | 
			
		||||
    const SshPseudoTerminal &terminal)
 | 
			
		||||
{
 | 
			
		||||
@@ -238,5 +250,20 @@ void SshSendFacility::sendChannelClosePacket(quint32 remoteChannel)
 | 
			
		||||
    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 QSsh
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,8 @@ public:
 | 
			
		||||
    void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize,
 | 
			
		||||
        const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress,
 | 
			
		||||
        quint32 localPort);
 | 
			
		||||
    void sendTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
 | 
			
		||||
    void sendCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
 | 
			
		||||
    void sendPtyRequestPacket(quint32 remoteChannel,
 | 
			
		||||
        const SshPseudoTerminal &terminal);
 | 
			
		||||
    void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
 | 
			
		||||
@@ -85,6 +87,10 @@ public:
 | 
			
		||||
        const QByteArray &signalName);
 | 
			
		||||
    void sendChannelEofPacket(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; }
 | 
			
		||||
 | 
			
		||||
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/sshdirecttcpiptunnel.h>
 | 
			
		||||
@@ -41,7 +41,7 @@ const QByteArray TestData("Urgsblubb?");
 | 
			
		||||
 | 
			
		||||
using namespace QSsh;
 | 
			
		||||
 | 
			
		||||
Tunnel::Tunnel(const SshConnectionParameters ¶meters, QObject *parent)
 | 
			
		||||
DirectTunnel::DirectTunnel(const SshConnectionParameters ¶meters, QObject *parent)
 | 
			
		||||
    : QObject(parent),
 | 
			
		||||
      m_connection(new SshConnection(parameters, 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()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Tunnel::~Tunnel()
 | 
			
		||||
DirectTunnel::~DirectTunnel()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::run()
 | 
			
		||||
void DirectTunnel::run()
 | 
			
		||||
{
 | 
			
		||||
    std::cout << "Connecting to SSH server..." << std::endl;
 | 
			
		||||
    m_connection->connectToHost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::handleConnectionError()
 | 
			
		||||
void DirectTunnel::handleConnectionError()
 | 
			
		||||
{
 | 
			
		||||
    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;
 | 
			
		||||
    if (!m_targetServer->listen(QHostAddress::LocalHost)) {
 | 
			
		||||
        std::cerr << "Error opening port: "
 | 
			
		||||
                << m_targetServer->errorString().toLocal8Bit().constData() << std::endl;
 | 
			
		||||
        qApp->exit(EXIT_FAILURE);
 | 
			
		||||
        emit finished(EXIT_FAILURE);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    m_targetPort = m_targetServer->serverPort();
 | 
			
		||||
    connect(m_targetServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
 | 
			
		||||
 | 
			
		||||
    m_tunnel = m_connection->createTunnel(QLatin1String("localhost"), 1024, // made-up values
 | 
			
		||||
                                          QLatin1String("localhost"), m_targetPort);
 | 
			
		||||
    m_tunnel = m_connection->createDirectTunnel(QLatin1String("localhost"), 1024, // made-up values
 | 
			
		||||
                                                QLatin1String("localhost"), m_targetPort);
 | 
			
		||||
    connect(m_tunnel.data(), SIGNAL(initialized()), SLOT(handleInitialized()));
 | 
			
		||||
    connect(m_tunnel.data(), SIGNAL(error(QString)), SLOT(handleTunnelError(QString)));
 | 
			
		||||
    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;
 | 
			
		||||
    m_tunnel->initialize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::handleInitialized()
 | 
			
		||||
void DirectTunnel::handleInitialized()
 | 
			
		||||
{
 | 
			
		||||
    std::cout << "Writing data into the tunnel..." << std::endl;
 | 
			
		||||
    m_tunnel->write(TestData);
 | 
			
		||||
@@ -99,7 +99,7 @@ void Tunnel::handleInitialized()
 | 
			
		||||
    timeoutTimer->start(10000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::handleServerData()
 | 
			
		||||
void DirectTunnel::handleServerData()
 | 
			
		||||
{
 | 
			
		||||
    m_dataReceivedFromServer += m_tunnel->readAll();
 | 
			
		||||
    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;
 | 
			
		||||
    qApp->exit(EXIT_FAILURE);
 | 
			
		||||
    emit finished(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::handleTunnelClosed()
 | 
			
		||||
void DirectTunnel::handleTunnelClosed()
 | 
			
		||||
{
 | 
			
		||||
    if (m_expectingChannelClose) {
 | 
			
		||||
        std::cout << "Successfully detected channel close." << std::endl;
 | 
			
		||||
        std::cout << "Test finished successfully." << std::endl;
 | 
			
		||||
        qApp->quit();
 | 
			
		||||
        emit finished(EXIT_SUCCESS);
 | 
			
		||||
    } else {
 | 
			
		||||
        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_targetServer->close();
 | 
			
		||||
@@ -136,14 +136,14 @@ void Tunnel::handleNewConnection()
 | 
			
		||||
    handleClientData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::handleSocketError()
 | 
			
		||||
void DirectTunnel::handleSocketError()
 | 
			
		||||
{
 | 
			
		||||
    std::cerr << "Socket error: " << m_targetSocket->errorString().toLocal8Bit().constData()
 | 
			
		||||
            << std::endl;
 | 
			
		||||
    qApp->exit(EXIT_FAILURE);
 | 
			
		||||
    emit finished(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tunnel::handleClientData()
 | 
			
		||||
void DirectTunnel::handleClientData()
 | 
			
		||||
{
 | 
			
		||||
    m_dataReceivedFromClient += m_targetSocket->readAll();
 | 
			
		||||
    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;
 | 
			
		||||
    qApp->exit(EXIT_FAILURE);
 | 
			
		||||
    emit finished(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
@@ -39,15 +39,18 @@ class SshConnectionParameters;
 | 
			
		||||
class SshDirectTcpIpTunnel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Tunnel : public QObject
 | 
			
		||||
class DirectTunnel : public QObject
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
    Tunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent = 0);
 | 
			
		||||
    ~Tunnel();
 | 
			
		||||
    DirectTunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent = 0);
 | 
			
		||||
    ~DirectTunnel();
 | 
			
		||||
 | 
			
		||||
    void run();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void finished(int errorCode);
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void handleConnected();
 | 
			
		||||
    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 "tunnel.h"
 | 
			
		||||
#include "directtunnel.h"
 | 
			
		||||
#include "forwardtunnel.h"
 | 
			
		||||
 | 
			
		||||
#include <ssh/sshconnection.h>
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +45,15 @@ int main(int argc, char *argv[])
 | 
			
		||||
    parameters.host = QLatin1String("127.0.0.1");
 | 
			
		||||
    if (!parseSuccess)
 | 
			
		||||
        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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,12 @@
 | 
			
		||||
include(../ssh.pri)
 | 
			
		||||
 | 
			
		||||
TARGET=tunnel
 | 
			
		||||
SOURCES=main.cpp tunnel.cpp argumentscollector.cpp
 | 
			
		||||
HEADERS=tunnel.h argumentscollector.h
 | 
			
		||||
TARGET =tunnel
 | 
			
		||||
SOURCES = \
 | 
			
		||||
    main.cpp \
 | 
			
		||||
    argumentscollector.cpp \
 | 
			
		||||
    directtunnel.cpp \
 | 
			
		||||
    forwardtunnel.cpp
 | 
			
		||||
HEADERS = \
 | 
			
		||||
    argumentscollector.h \
 | 
			
		||||
    directtunnel.h \
 | 
			
		||||
    forwardtunnel.h
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user