Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8702bd2
double hbone (no inner encryption) working!!
Stevenjin8 Jan 14, 2025
e340d8c
hbone-ish
Stevenjin8 Jan 15, 2025
b381e34
cleanup
Stevenjin8 Jan 15, 2025
2192d67
graceful shutdowns
Stevenjin8 Jan 17, 2025
dff6c92
Some cleanup
Stevenjin8 Jan 17, 2025
f1cc535
Add some auth/tls logic back in
Stevenjin8 Jan 21, 2025
cab4849
inline double hbone code
Stevenjin8 Jan 21, 2025
565f41f
Use correct(?) identities
Stevenjin8 Jan 21, 2025
48fa773
Merge branch 'master' into feature/double-hbone
Stevenjin8 Mar 3, 2025
9f5609d
checkpoint
Stevenjin8 Mar 5, 2025
54dd3e3
another checkpoint
Stevenjin8 Mar 5, 2025
58399be
Use new xds
Stevenjin8 Mar 7, 2025
59eedf0
Merge branch 'master' into HEAD
Stevenjin8 Mar 7, 2025
89efd6c
Merge commit '59eedf0' into feature/double-hbone
Stevenjin8 Mar 7, 2025
b2a21bd
lint
Stevenjin8 Mar 7, 2025
896cef5
Fix type sizes
Stevenjin8 Mar 11, 2025
522fd35
Check workload potocol
Stevenjin8 Mar 11, 2025
a56b3ca
wip
Stevenjin8 Mar 14, 2025
b255c25
Merge branch 'master' into feature/double-hbone
Stevenjin8 Mar 24, 2025
08e7a58
initial impl of hostname
Stevenjin8 Mar 26, 2025
a4b8e4b
Merge branch 'master' into feature/double-hbone
Stevenjin8 Mar 27, 2025
4ef17cc
tests passing
Stevenjin8 Mar 28, 2025
11b4f87
svc addressing
Stevenjin8 Mar 28, 2025
8b506cb
Check workload network when using network gateways
Stevenjin8 Mar 28, 2025
862c6f8
Use dummy SNI
Stevenjin8 Mar 28, 2025
d54a820
remove extra derive
Stevenjin8 Mar 28, 2025
2d23fb0
Merge commit 'dc54d850a774e033cc0' into feature/double-hbone
Stevenjin8 Mar 31, 2025
6d398ef
lint
Stevenjin8 Mar 31, 2025
4874f08
more tests
Stevenjin8 Apr 1, 2025
00aa327
Merge branch 'master' into feature/double-hbone
Stevenjin8 Apr 2, 2025
d7cb313
Drop some uneeded changers
Stevenjin8 Apr 2, 2025
7cd4cf1
get rid of more stuff
Stevenjin8 Apr 2, 2025
fa46e46
lint
Stevenjin8 Apr 2, 2025
0638119
lint
Stevenjin8 Apr 2, 2025
04e7d30
Review:
Stevenjin8 Apr 7, 2025
0fbae22
Assume existing workload
Stevenjin8 Apr 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions src/proxy/outbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,40 +219,56 @@ impl OutboundConnection {
req: &Request,
connection_stats: &ConnectionResult,
) -> Result<(), Error> {
// Outer HBONE
let upgraded = Box::pin(self.send_hbone_request(remote_addr, req)).await?;

// Inner HBONE
let upgraded = TokioH2Stream::new(upgraded);
// TODO: dst should take a hostname? and upstream_sans currently contains E/W Gateway certs
let inner_workload = pool::WorkloadKey {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will reorganize later.

src_id: req.source.identity(),
dst_id: req.upstream_sans.clone(),
src: remote_addr.ip(),
dst: req.actual_destination,
};
let request = self.create_hbone_request(remote_addr, req);
let workload_key = &inner_workload;

let (_conn_client, inner_upgraded, drain_tx, driver_task) = self
.pool
.send_request_unpooled(upgraded, &inner_workload, request)
// To shut down inner HTTP2 connection
let (drain_tx, drain_rx) = tokio::sync::watch::channel(false);
let key = workload_key.clone();
let dest = rustls::pki_types::ServerName::IpAddress(key.dst.ip().into());
let cert = self
.pi
.local_workload_information
.fetch_certificate()
.await?;
let inner_upgraded = inner_upgraded?;
// FIXME The following isn't great because it will also contain the identity of the E/W gateways
let connector = cert.outbound_connector(req.upstream_sans.clone())?;

// Do actual IO as late as possible
// Outer HBONE
let upgraded = Box::pin(self.send_hbone_request(remote_addr, req)).await?;
// Wrap upgraded to implement tokio's Async{Write,Read}
let upgraded = TokioH2Stream::new(upgraded);
let tls_stream = connector.connect(upgraded, dest).await?;

let (sender, driver_task) =
super::h2::client::spawn_connection(self.pi.cfg.clone(), tls_stream, drain_rx).await?;
let mut connection = super::pool::ConnClient {
sender,
wl_key: key,
};
let inner_upgraded = connection.sender.send_request(request).await?;
let res = copy::copy_bidirectional(
copy::TcpStreamSplitter(stream),
inner_upgraded,
connection_stats,
)
.await;

// This always drops ungracefully
// drop(conn_client);
// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
// drain_tx.send(true).unwrap();
// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
drain_tx.send(true).unwrap();
let _ = drain_tx.send(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? Doesn't dropping all references to the connection already make it close?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It closes it, but in my testing, it was not graceful (e.g. the proper close notifies weren't sent). For example, if the outer connection http2 CONNECT stream closes before the inner TLS stream has a chance to send the close notify.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But since there have been some refactors, ill take another look.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@howardjohn I took another look at it seems like connections aren't being closed particularly gracefully. Namely, I'm seeing FIN being sent before close notifies, But I do have a janky setup. How do we generally test for this?

let _ = driver_task.await;
// this sleep is important, so we have a race condition somewhere
// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
// Here, there is an implicit, drop(conn_client).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no conn_client in scope so this is a bit confusing

// Its really important that this happens AFTER driver_task finishes.
// Otherwise, TLS connections do not terminate gracefully.
//
// drop(conn_client);
res
}

Expand Down
23 changes: 17 additions & 6 deletions src/proxy/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct PoolState {
// This is merely a counter to track the overall number of conns this pool spawns
// to ensure we get unique poolkeys-per-new-conn, it is not a limit
pool_global_conn_count: AtomicI32,
pub spawner: ConnSpawner,
spawner: ConnSpawner,
}

struct ConnSpawner {
Expand Down Expand Up @@ -413,17 +413,28 @@ impl WorkloadHBONEPool {
Error,
> {
let (tx, rx) = tokio::sync::watch::channel(false);
let (mut connection, driver_task) = self
let key = workload_key.clone();
let dest = rustls::pki_types::ServerName::IpAddress(key.dst.ip().into());
let cert = self
.state
.spawner
.new_unpooled_conn(workload_key.clone(), stream, rx)
.local_workload
.fetch_certificate()
.await?;
let connector = cert.outbound_connector(vec![])?;
let tls_stream = connector.connect(stream, dest).await?;
let (sender, driver_drain) =
h2::client::spawn_connection(self.state.spawner.cfg.clone(), tls_stream, rx).await?;
let mut connection = ConnClient {
sender,
wl_key: key,
};

Ok((
connection.clone(),
connection.sender.send_request(request).await,
tx,
driver_task,
driver_drain,
))
}

Expand Down Expand Up @@ -568,9 +579,9 @@ impl WorkloadHBONEPool {
// A sort of faux-client, that represents a single checked-out 'request sender' which might
// send requests over some underlying stream using some underlying http/2 client
pub struct ConnClient {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixme

sender: H2ConnectClient,
pub sender: H2ConnectClient,
// A WL key may have many clients, but every client has no more than one WL key
wl_key: WorkloadKey, // the WL key associated with this client.
pub wl_key: WorkloadKey, // the WL key associated with this client.
}

impl ConnClient {
Expand Down