summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2018-11-01 12:51:55 +0100
committerChristian Kandeler <christian.kandeler@qt.io>2018-11-13 09:08:17 +0000
commit34bf628d21534bc4b87270aa0a7bd8d15ef03373 (patch)
treed8f509c80b5154cd2958c3281e43109bfe194d3c
parent332b358db520203fd0a556ebbc096d690cf4c627 (diff)
downloadqt-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.cpp105
-rw-r--r--src/libs/ssh/sshchannelmanager_p.h2
-rw-r--r--src/libs/ssh/sshincomingpacket.cpp43
-rw-r--r--src/libs/ssh/sshincomingpacket_p.h20
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;