Phase 8d: daemon binds a second QuicServer on the tailnet interface #66
@@ -197,6 +197,16 @@ impl ClusterServices {
|
|||||||
.rpc_lan()
|
.rpc_lan()
|
||||||
.or_else(|| cluster.rpc_tailscale())
|
.or_else(|| cluster.rpc_tailscale())
|
||||||
.context("no RPC bind address (need bind_lan or bind_tailscale)")?;
|
.context("no RPC bind address (need bind_lan or bind_tailscale)")?;
|
||||||
|
// Phase 8d (2026-07-14): when BOTH LAN and tailnet
|
||||||
|
// addresses are configured, we also bind a second
|
||||||
|
// QuicServer on the tailnet interface. The gossip
|
||||||
|
// layer already publishes `rpc_tailscale` so peers
|
||||||
|
// learn to dial it; without the second bind the
|
||||||
|
// advertised address just refuses connections.
|
||||||
|
let bind_tailnet = match (cluster.rpc_lan(), cluster.rpc_tailscale()) {
|
||||||
|
(Some(lan), Some(ts)) if lan != ts => Some(ts),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
let outbound_client = crate::cluster::transport::QuicClient::new(
|
let outbound_client = crate::cluster::transport::QuicClient::new(
|
||||||
"0.0.0.0:0".parse().expect("literal 0.0.0.0:0 parses"),
|
"0.0.0.0:0".parse().expect("literal 0.0.0.0:0 parses"),
|
||||||
client_identity,
|
client_identity,
|
||||||
@@ -228,6 +238,34 @@ impl ClusterServices {
|
|||||||
let task = tokio::spawn(async move {
|
let task = tokio::spawn(async move {
|
||||||
accept_forever(server, router_for_accept).await;
|
accept_forever(server, router_for_accept).await;
|
||||||
});
|
});
|
||||||
|
// Phase 8d: second bind for the tailnet interface,
|
||||||
|
// when configured. Shares the same identity + router
|
||||||
|
// as the LAN listener — connections from either side
|
||||||
|
// hit the same handlers.
|
||||||
|
if let Some(ts_addr) = bind_tailnet {
|
||||||
|
let ts_identity =
|
||||||
|
NodeIdentity::from_pem_files(&tls.ca_cert, &tls.node_cert, &tls.node_key)
|
||||||
|
.context(
|
||||||
|
"loading node identity for tailnet QUIC server",
|
||||||
|
)?;
|
||||||
|
match QuicServer::bind(ts_addr, ts_identity) {
|
||||||
|
Ok(ts_server) => {
|
||||||
|
tracing::info!(
|
||||||
|
"cluster RPC server also listening on {} (tailnet)",
|
||||||
|
ts_addr
|
||||||
|
);
|
||||||
|
let router_for_ts = router.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
accept_forever(ts_server, router_for_ts).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => tracing::warn!(
|
||||||
|
error = %e,
|
||||||
|
addr = %ts_addr,
|
||||||
|
"tailnet RPC bind failed; LAN listener still active"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
(Some(router), Some(task))
|
(Some(router), Some(task))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
Reference in New Issue
Block a user