Advertise signed peer cards on LAN
This commit is contained in:
parent
b0f208b05a
commit
d5a548182b
10 changed files with 306 additions and 7 deletions
|
|
@ -13,7 +13,8 @@ use geth_control::{
|
|||
use geth_crypto::AgentKey;
|
||||
use geth_db::DbResource;
|
||||
use geth_discovery::{
|
||||
DiscoveredPeer, DiscoverySource, EndpointCandidate, PeerCard, discovery_is_untrusted_note,
|
||||
DiscoveredPeer, DiscoverySource, EndpointCandidate, PEER_CARD_LAN_DISCOVERY_SERVICE, PeerCard,
|
||||
discovery_is_untrusted_note, peer_card_from_txt_attributes, peer_card_txt_attributes,
|
||||
};
|
||||
use geth_document::{DocumentResource, DocumentState};
|
||||
use geth_iroh::{EndpointStatus, GethIrohConfig, GethIrohEndpoint, GethRelayMode};
|
||||
|
|
@ -193,6 +194,7 @@ pub async fn run_daemon(paths: GethPaths) -> Result<(), NodeError> {
|
|||
{
|
||||
spawn_iroh_control_accept_loop(node.clone(), endpoint);
|
||||
}
|
||||
let _peer_card_lan_discovery = start_peer_card_lan_discovery(&node).await;
|
||||
if Path::new(&paths.socket_path()).exists() {
|
||||
std::fs::remove_file(paths.socket_path())?;
|
||||
}
|
||||
|
|
@ -259,6 +261,121 @@ async fn handle_stream(node: LocalNode, stream: UnixStream) -> Result<(), NodeEr
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn start_peer_card_lan_discovery(node: &LocalNode) -> Option<swarm_discovery::DropGuard> {
|
||||
if !node.iroh_status.local_discovery || !node.iroh_status.enabled {
|
||||
return None;
|
||||
}
|
||||
|
||||
let card = match local_peer_card(node, DiscoverySource::Mdns, true).await {
|
||||
Ok(card) => card,
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "signed peer-card LAN discovery disabled");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let attributes = match peer_card_txt_attributes(&card) {
|
||||
Ok(attributes) => attributes,
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "could not encode peer-card LAN TXT payload");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let Some((port, addrs)) = lan_discovery_addrs(&card) else {
|
||||
tracing::warn!(
|
||||
"signed peer-card LAN discovery disabled because no direct Iroh address is known"
|
||||
);
|
||||
return None;
|
||||
};
|
||||
|
||||
let paths = node.paths.clone();
|
||||
let self_node_id = node.node_id.clone();
|
||||
let discoverer = match swarm_discovery::Discoverer::new_interactive(
|
||||
PEER_CARD_LAN_DISCOVERY_SERVICE.to_owned(),
|
||||
lan_discovery_peer_id(&node.agent_id),
|
||||
)
|
||||
.with_addrs(port, addrs)
|
||||
.with_txt_attributes(attributes)
|
||||
{
|
||||
Ok(discoverer) => discoverer,
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "could not build peer-card LAN discovery");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
.with_callback(move |_peer_id, peer| {
|
||||
if peer.is_expiry() {
|
||||
return;
|
||||
}
|
||||
let card = match peer_card_from_txt_attributes(peer.txt_attributes()) {
|
||||
Ok(card) => card,
|
||||
Err(error) => {
|
||||
tracing::debug!(%error, "ignoring invalid peer-card LAN discovery payload");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if card.node_id.as_str() == self_node_id {
|
||||
return;
|
||||
}
|
||||
let discovered = match DiscoveredPeer::candidate(
|
||||
card.clone(),
|
||||
UnixMillis(geth_store::now_ms()),
|
||||
DiscoverySource::Mdns,
|
||||
) {
|
||||
Ok(discovered) => discovered,
|
||||
Err(error) => {
|
||||
tracing::debug!(%error, "ignoring invalid LAN peer-card candidate");
|
||||
return;
|
||||
}
|
||||
};
|
||||
match Store::open(&paths.metadata_db()).and_then(|store| {
|
||||
store.upsert_peer_card(&StoredPeerCard {
|
||||
peer_id: card.node_id.to_string(),
|
||||
card_json: serde_json::to_string(&card).map_err(geth_store::StoreError::from)?,
|
||||
updated_at_ms: discovered.discovered_at.0,
|
||||
})
|
||||
}) {
|
||||
Ok(()) => tracing::debug!(node = %card.node_id, "stored LAN peer-card candidate"),
|
||||
Err(error) => tracing::warn!(%error, "could not store LAN peer-card candidate"),
|
||||
}
|
||||
});
|
||||
|
||||
match discoverer.spawn(&tokio::runtime::Handle::current()) {
|
||||
Ok(guard) => {
|
||||
tracing::info!(
|
||||
service = PEER_CARD_LAN_DISCOVERY_SERVICE,
|
||||
"signed peer-card LAN discovery running"
|
||||
);
|
||||
Some(guard)
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "could not start signed peer-card LAN discovery");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lan_discovery_peer_id(agent_id: &str) -> String {
|
||||
format!("geth-{}", geth_crypto::blake3_hex(agent_id.as_bytes()))
|
||||
}
|
||||
|
||||
fn lan_discovery_addrs(card: &PeerCard) -> Option<(u16, Vec<std::net::IpAddr>)> {
|
||||
let mut parsed = card
|
||||
.endpoints
|
||||
.iter()
|
||||
.flat_map(|endpoint| endpoint.direct_addresses.iter())
|
||||
.filter_map(|addr| addr.parse::<std::net::SocketAddr>().ok())
|
||||
.collect::<Vec<_>>();
|
||||
parsed.sort_unstable();
|
||||
parsed.dedup();
|
||||
let port = parsed.first()?.port();
|
||||
let addrs = parsed
|
||||
.into_iter()
|
||||
.filter(|addr| addr.port() == port)
|
||||
.map(|addr| addr.ip())
|
||||
.collect::<Vec<_>>();
|
||||
(!addrs.is_empty()).then_some((port, addrs))
|
||||
}
|
||||
|
||||
async fn export_peer_card(
|
||||
node: &LocalNode,
|
||||
out: Option<std::path::PathBuf>,
|
||||
|
|
@ -2143,6 +2260,32 @@ mod tests {
|
|||
.expect("write config");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lan_discovery_address_selection_uses_iroh_direct_addresses() {
|
||||
let key = AgentKey::generate();
|
||||
let card = PeerCard::signed(
|
||||
"node:test".into(),
|
||||
&key,
|
||||
vec![EndpointCandidate {
|
||||
endpoint_id: "endpoint:test".to_owned(),
|
||||
relay_url: None,
|
||||
direct_addresses: vec![
|
||||
"127.0.0.1:1111".to_owned(),
|
||||
"127.0.0.2:1111".to_owned(),
|
||||
"127.0.0.3:2222".to_owned(),
|
||||
],
|
||||
source: DiscoverySource::Mdns,
|
||||
}],
|
||||
UnixMillis(1),
|
||||
)
|
||||
.expect("peer card");
|
||||
|
||||
let (port, addrs) = lan_discovery_addrs(&card).expect("lan addresses");
|
||||
|
||||
assert_eq!(port, 1111);
|
||||
assert_eq!(addrs.len(), 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn peer_ping_uses_signed_peer_card_over_iroh() {
|
||||
let left_home = tempfile::tempdir().expect("left home");
|
||||
|
|
|
|||
Loading…
Reference in a new issue