Skip to content

Commit 227fb0d

Browse files
authored
Merge pull request #152 from pomerium/kralicky/fix-reverse-tunnel-connection-open
ssh: improve socket connect semantics to fix very short lived connections
2 parents 7615dfd + 31e1c29 commit 227fb0d

File tree

9 files changed

+726
-226
lines changed

9 files changed

+726
-226
lines changed

patches/envoy/0007-user-space-io-handle.patch

Lines changed: 318 additions & 45 deletions
Large diffs are not rendered by default.

source/extensions/filters/network/ssh/reverse_tunnel.cc

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
#include "source/extensions/filters/network/ssh/filter_state_objects.h"
99
#include "source/extensions/filters/network/ssh/wire/common.h"
1010
#include "source/extensions/filters/network/ssh/wire/messages.h"
11-
#include <cstddef>
1211

1312
#pragma clang unsafe_buffer_usage begin
1413
#include "envoy/config/endpoint/v3/endpoint.pb.h"
1514
#include "envoy/config/endpoint/v3/endpoint.pb.validate.h"
1615
#include "source/common/network/connection_impl.h"
16+
#include "source/extensions/io_socket/user_space/io_handle_impl.h"
1717
#include "source/common/network/connection_socket_impl.h"
1818
#include "envoy/network/client_connection_factory.h"
1919
#include "source/common/grpc/common.h"
@@ -87,6 +87,8 @@ class RemoteStreamHandler : public Logger::Loggable<Logger::Id::filter>,
8787
};
8888
*local_queue = &local_queue_;
8989

90+
remote_stream_handler_sync.syncPoint("initialize");
91+
9092
// The remote dispatcher could be running concurrently, but it won't pick up this callback
9193
// until after the next time it acquires post_lock_ (see dispatcher_impl.cc). Because this call
9294
// to post() adds the callback to the queue while holding post_lock_, the write to peer_state_
@@ -97,13 +99,16 @@ class RemoteStreamHandler : public Logger::Loggable<Logger::Id::filter>,
9799
remote_dispatcher_.post([this] {
98100
initialized_ = true;
99101
// First check if the socket has been closed
102+
bool isDynamic = metadata_->server_port().is_dynamic();
100103
if (socket_closed_) {
101-
ENVOY_LOG(debug, "channel {}: downstream closed before initialization");
102-
onError(absl::CancelledError("downstream closed"));
104+
ENVOY_LOG(debug, "channel {}: downstream closed before initialization", peer_state_.id);
105+
// If the downstream closes before sending any data, and the upstream is expecting a SOCKS
106+
// handshake, we have to send it an EOF before closing the channel because openssh client
107+
// can become stuck
108+
onError(absl::CancelledError("downstream closed"), isDynamic);
103109
return;
104110
}
105111
ENVOY_LOG(debug, "channel {}: remote stream handler initialized", peer_state_.id);
106-
bool isDynamic = metadata_->server_port().is_dynamic();
107112
if (isDynamic) {
108113
ENVOY_LOG(debug, "channel {}: starting socks5 handshake", peer_state_.id);
109114
startSocks5Handshake();
@@ -145,13 +150,15 @@ class RemoteStreamHandler : public Logger::Loggable<Logger::Id::filter>,
145150
private:
146151
// Network::ConnectionCallbacks
147152
void onEvent(Network::ConnectionEvent event) override {
153+
ENVOY_LOG(debug, "downstream connection event: {}", std::to_underlying(event));
148154
// These events are from the perspective of the downstream client connection, so LocalClose
149155
// means the downstream closed the connection, and RemoteClose means the upstream (us) closed
150156
// the connection.
151157
if (event == Network::ConnectionEvent::LocalClose ||
152158
event == Network::ConnectionEvent::RemoteClose) {
153159
// This is the last event received; the downstream connection will be destroyed and it is
154160
// safe to delete this object.
161+
remote_stream_handler_sync.syncPoint("downstream_closed");
155162
socket_closed_ = true;
156163
if (!initialized_) {
157164
// Downstream closed before initialization
@@ -253,11 +260,12 @@ class RemoteStreamHandler : public Logger::Loggable<Logger::Id::filter>,
253260
onRemoteQueueReadyRead();
254261
if (!received_channel_close_) {
255262
// If we didn't see a channel close, then shutdown() has not yet been called on the io handle.
256-
ENVOY_LOG(debug, "channel {}: local peer exited without sending a ChannelClose message");
263+
ENVOY_LOG(debug, "channel {}: local peer exited without sending a ChannelClose message", peer_state_.id);
257264
}
258265
// Close it for reading and writing, since reads are impossible
259-
ENVOY_BUG(io_handle_->isOpen(), "bug: io handle is closed");
260-
io_handle_->close();
266+
if (io_handle_->isOpen()) {
267+
io_handle_->close();
268+
}
261269

262270
// If we did receive a channel close, allow the response to be received by the downstream.
263271
// Once that happens, we will receive the socket close event, where the deferred deletion is
@@ -1068,7 +1076,6 @@ class SshTunnelClientConnectionFactory : public ClientConnectionFactory,
10681076
auto& hostContext = streamAddress->hostContext();
10691077
auto upstreamAddr = hostContext.clusterContext().chooseUpstreamAddress();
10701078

1071-
ENVOY_LOG(debug, "channel {}: starting remote stream handler");
10721079
using Extensions::NetworkFilters::GenericProxy::Codec::RemoteStreamHandler;
10731080
auto remoteStreamHandler = std::make_unique<RemoteStreamHandler>(std::move(local),
10741081
dispatcher,

source/extensions/filters/network/ssh/reverse_tunnel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,6 @@ class SshReverseTunnelClusterFactory : public ConfigurableClusterFactoryBase<pom
160160
DECLARE_FACTORY(SshReverseTunnelClusterFactory);
161161

162162
} // namespace Upstream
163-
} // namespace Envoy
163+
} // namespace Envoy
164+
165+
inline Envoy::Thread::ThreadSynchronizer remote_stream_handler_sync;

test/extensions/filters/network/ssh/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ envoy_cc_test_library(
438438

439439
envoy_cc_test(
440440
name = "reverse_tunnel_test",
441+
size = "large",
441442
srcs = [
442443
"reverse_tunnel_test.cc",
443444
],

0 commit comments

Comments
 (0)