diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2018-11-01 12:51:55 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2018-11-13 09:08:17 +0000 |
commit | 34bf628d21534bc4b87270aa0a7bd8d15ef03373 (patch) | |
tree | d8f509c80b5154cd2958c3281e43109bfe194d3c | |
parent | 332b358db520203fd0a556ebbc096d690cf4c627 (diff) | |
download | qt-creator-34bf628d21534bc4b87270aa0a7bd8d15ef03373.tar.gz |
SSH: Introduce and handle generic "channel open" packets
There are other "channel open" requests than the one for forwarded TCP/
IP. Factor out the generic parts.
Change-Id: I593a9a075d87d57850697459ab0814c07b75c4d4
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/libs/ssh/sshchannelmanager.cpp | 105 | ||||
-rw-r--r-- | src/libs/ssh/sshchannelmanager_p.h | 2 | ||||
-rw-r--r-- | src/libs/ssh/sshincomingpacket.cpp | 43 | ||||
-rw-r--r-- | src/libs/ssh/sshincomingpacket_p.h | 20 |
4 files changed, 111 insertions, 59 deletions
diff --git a/src/libs/ssh/sshchannelmanager.cpp b/src/libs/ssh/sshchannelmanager.cpp index 364d1dcfe2..78672d2549 100644 --- a/src/libs/ssh/sshchannelmanager.cpp +++ b/src/libs/ssh/sshchannelmanager.cpp @@ -58,52 +58,17 @@ void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet) void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet) { - 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 std::exception &e) { - qCWarning(sshLog, "Botan error: %s", e.what()); - } + const SshChannelOpenGeneric channelOpen = packet.extractChannelOpen(); + if (channelOpen.channelType == SshIncomingPacket::ForwardedTcpIpType) { + handleChannelOpenForwardedTcpIp(channelOpen); 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); + try { + m_sendFacility.sendChannelOpenFailurePacket(channelOpen.commonData.remoteChannel, + SSH_OPEN_UNKNOWN_CHANNEL_TYPE, QByteArray()); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + } } void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet) @@ -286,6 +251,58 @@ void SshChannelManager::insertChannel(AbstractSshChannel *priv, m_sessions.insert(priv, pub); } +void SshChannelManager::handleChannelOpenForwardedTcpIp( + const SshChannelOpenGeneric &channelOpenGeneric) +{ + const SshChannelOpenForwardedTcpIp channelOpen + = SshIncomingPacket::extractChannelOpenForwardedTcpIp(channelOpenGeneric); + + 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()) { + try { + m_sendFacility.sendChannelOpenFailurePacket(channelOpen.common.remoteChannel, + SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, + QByteArray()); + } catch (const std::exception &e) { + qCWarning(sshLog, "Botan error: %s", e.what()); + } + return; + } + + SshForwardedTcpIpTunnel::Ptr tunnel(new SshForwardedTcpIpTunnel(m_nextLocalChannelId++, + m_sendFacility)); + tunnel->d->handleOpenSuccess(channelOpen.common.remoteChannel, + channelOpen.common.remoteWindowSize, + channelOpen.common.remoteMaxPacketSize); + tunnel->open(QIODevice::ReadWrite); + server->setNewConnection(tunnel); + insertChannel(tunnel->d, tunnel); +} + int SshChannelManager::closeAllChannels(CloseAllMode mode) { int count = 0; diff --git a/src/libs/ssh/sshchannelmanager_p.h b/src/libs/ssh/sshchannelmanager_p.h index 413ed12c8c..33f7af9ef0 100644 --- a/src/libs/ssh/sshchannelmanager_p.h +++ b/src/libs/ssh/sshchannelmanager_p.h @@ -38,6 +38,7 @@ class SshTcpIpForwardServer; namespace Internal { class AbstractSshChannel; +struct SshChannelOpenGeneric; class SshIncomingPacket; class SshSendFacility; @@ -87,6 +88,7 @@ private: void insertChannel(AbstractSshChannel *priv, const QSharedPointer<QObject> &pub); + void handleChannelOpenForwardedTcpIp(const SshChannelOpenGeneric &channelOpenGeneric); SshSendFacility &m_sendFacility; QHash<quint32, AbstractSshChannel *> m_channels; QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions; diff --git a/src/libs/ssh/sshincomingpacket.cpp b/src/libs/ssh/sshincomingpacket.cpp index a105efb48f..c97e18c857 100644 --- a/src/libs/ssh/sshincomingpacket.cpp +++ b/src/libs/ssh/sshincomingpacket.cpp @@ -364,29 +364,46 @@ SshUnimplemented SshIncomingPacket::extractUnimplemented() const } } -SshChannelOpen SshIncomingPacket::extractChannelOpen() const +SshChannelOpenGeneric SshIncomingPacket::extractChannelOpen() const { Q_ASSERT(isComplete()); Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN); - SshChannelOpen open; try { + SshChannelOpenGeneric channelOpen; 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; - } + channelOpen.channelType = SshPacketParser::asString(m_data, &offset); + channelOpen.commonData.remoteChannel = SshPacketParser::asUint32(m_data, &offset); + channelOpen.commonData.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset); + channelOpen.commonData.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset); + channelOpen.typeSpecificData = m_data.mid(offset, length() - paddingLength() - offset + + int(sizeof m_length)); + return channelOpen; + } catch (const SshPacketParseException &) { + throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, + "Server sent invalid SSH_MSG_CHANNEL_OPEN packet."); + } +} + +SshChannelOpenForwardedTcpIp SshIncomingPacket::extractChannelOpenForwardedTcpIp( + const SshChannelOpenGeneric &genericData) +{ + try { + SshChannelOpenForwardedTcpIp specificData; + specificData.common = genericData.commonData; + quint32 offset = 0; + specificData.remoteAddress = SshPacketParser::asString(genericData.typeSpecificData, + &offset); + specificData.remotePort = SshPacketParser::asUint32(genericData.typeSpecificData, &offset); + specificData.originatorAddress = SshPacketParser::asString(genericData.typeSpecificData, + &offset); + specificData.originatorPort = SshPacketParser::asUint32(genericData.typeSpecificData, + &offset); + return specificData; } 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 diff --git a/src/libs/ssh/sshincomingpacket_p.h b/src/libs/ssh/sshincomingpacket_p.h index ab8be6aae3..6b3a54abf3 100644 --- a/src/libs/ssh/sshincomingpacket_p.h +++ b/src/libs/ssh/sshincomingpacket_p.h @@ -108,13 +108,27 @@ struct SshRequestSuccess quint32 bindPort; }; -struct SshChannelOpen +struct SshChannelOpenCommon { quint32 remoteChannel; quint32 remoteWindowSize; quint32 remoteMaxPacketSize; +}; + +struct SshChannelOpenGeneric +{ + QByteArray channelType; + SshChannelOpenCommon commonData; + QByteArray typeSpecificData; +}; + +struct SshChannelOpenForwardedTcpIp +{ + SshChannelOpenCommon common; QByteArray remoteAddress; quint32 remotePort; + QByteArray originatorAddress; + quint32 originatorPort; }; struct SshChannelOpenFailure @@ -187,7 +201,9 @@ public: SshRequestSuccess extractRequestSuccess() const; SshUnimplemented extractUnimplemented() const; - SshChannelOpen extractChannelOpen() const; + SshChannelOpenGeneric extractChannelOpen() const; + static SshChannelOpenForwardedTcpIp extractChannelOpenForwardedTcpIp( + const SshChannelOpenGeneric &genericData); SshChannelOpenFailure extractChannelOpenFailure() const; SshChannelOpenConfirmation extractChannelOpenConfirmation() const; SshChannelWindowAdjust extractWindowAdjust() const; |