diff --git a/iroh-base/src/endpoint_addr.rs b/iroh-base/src/endpoint_addr.rs index 342f472ec41..309d95c41ab 100644 --- a/iroh-base/src/endpoint_addr.rs +++ b/iroh-base/src/endpoint_addr.rs @@ -10,7 +10,7 @@ use std::{collections::BTreeSet, net::SocketAddr}; use serde::{Deserialize, Serialize}; -use crate::{EndpointId, PublicKey, RelayUrl}; +use crate::{EndpointId, RelayUrl}; /// Network-level addressing information for an iroh endpoint. /// @@ -59,7 +59,7 @@ impl EndpointAddr { /// /// This still is usable with e.g. a discovery service to establish a connection, /// depending on the situation. - pub fn new(id: PublicKey) -> Self { + pub fn new(id: EndpointId) -> Self { EndpointAddr { id, addrs: Default::default(), @@ -67,7 +67,7 @@ impl EndpointAddr { } /// Creates a new [`EndpointAddr`] from its parts. - pub fn from_parts(id: PublicKey, addrs: impl IntoIterator) -> Self { + pub fn from_parts(id: EndpointId, addrs: impl IntoIterator) -> Self { Self { id, addrs: addrs.into_iter().collect(), diff --git a/iroh-base/src/key.rs b/iroh-base/src/key.rs index 67328c10c68..de864b4c7a0 100644 --- a/iroh-base/src/key.rs +++ b/iroh-base/src/key.rs @@ -62,7 +62,65 @@ impl Ord for PublicKey { /// /// - `encrypt(key: PublicKey)` /// - `send_to(endpoint: EndpointId)` -pub type EndpointId = PublicKey; +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EndpointId { + /// An Ed25519 public key. + Ed25519(PublicKey), + /// A Secp256k1 public key. + Secp256k1(u128), +} + +impl EndpointId { + /// If this endpoint id is an ed25519 key, return it. + pub fn ed25519(&self) -> Option<&PublicKey> { + match self { + EndpointId::Ed25519(pk) => Some(pk), + EndpointId::Secp256k1(_) => None, + } + } + + /// If this endpoint id is an ed25519 key, return it. + pub fn to_ed25519(self) -> Option { + match self { + EndpointId::Ed25519(pk) => Some(pk), + EndpointId::Secp256k1(_) => None, + } + } +} + +impl FromStr for EndpointId { + type Err = KeyParsingError; + + fn from_str(s: &str) -> Result { + let pk = PublicKey::from_str(s)?; + Ok(EndpointId::Ed25519(pk)) + } +} + +impl Display for EndpointId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EndpointId::Ed25519(pk) => write!(f, "{}", pk), + EndpointId::Secp256k1(s) => write!(f, "secp256k1:{}", s), + } + } +} + +impl EndpointId { + /// Format a short version of the endpoint id for logging purposes. + pub fn fmt_short(&self) -> String { + match self { + EndpointId::Ed25519(pk) => pk.fmt_short().to_string(), + EndpointId::Secp256k1(s) => format!("secp256k1:{s:05x}"), + } + } +} + +impl From for EndpointId { + fn from(pk: PublicKey) -> Self { + EndpointId::Ed25519(pk) + } +} impl Hash for PublicKey { fn hash(&self, state: &mut H) { diff --git a/iroh-dns-server/benches/write.rs b/iroh-dns-server/benches/write.rs index 2e66db59578..5ecdfe18feb 100644 --- a/iroh-dns-server/benches/write.rs +++ b/iroh-dns-server/benches/write.rs @@ -33,7 +33,7 @@ fn benchmark_dns_server(c: &mut Criterion) { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42); let secret_key = SecretKey::generate(&mut rng); - let endpoint_id = secret_key.public(); + let endpoint_id = secret_key.public().into(); let pkarr_relay = LOCALHOST_PKARR.parse().expect("valid url"); let pkarr = PkarrRelayClient::new(pkarr_relay); diff --git a/iroh-dns-server/examples/convert.rs b/iroh-dns-server/examples/convert.rs index 765c809f16f..342b6ccc695 100644 --- a/iroh-dns-server/examples/convert.rs +++ b/iroh-dns-server/examples/convert.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use clap::Parser; -use iroh::EndpointId; +use iroh::{EndpointId, PublicKey}; use n0_snafu::{Result, ResultExt}; #[derive(Debug, Parser)] @@ -20,13 +20,13 @@ fn main() -> Result<()> { let args = Cli::parse(); match args.command { Command::EndpointToPkarr { endpoint_id } => { - let endpoint_id = EndpointId::from_str(&endpoint_id)?; + let endpoint_id = PublicKey::from_str(&endpoint_id)?; let public_key = pkarr::PublicKey::try_from(endpoint_id.as_bytes()).e()?; println!("{}", public_key.to_z32()) } Command::PkarrToEndpoint { z32_pubkey } => { let public_key = pkarr::PublicKey::try_from(z32_pubkey.as_str()).e()?; - let endpoint_id = EndpointId::from_bytes(public_key.as_bytes()).e()?; + let endpoint_id: EndpointId = PublicKey::from_bytes(public_key.as_bytes()).e()?.into(); println!("{endpoint_id}") } } diff --git a/iroh-dns-server/examples/publish.rs b/iroh-dns-server/examples/publish.rs index 99adec17cc0..1d9f4acc513 100644 --- a/iroh-dns-server/examples/publish.rs +++ b/iroh-dns-server/examples/publish.rs @@ -2,13 +2,9 @@ use std::{net::SocketAddr, str::FromStr}; use clap::{Parser, ValueEnum}; use iroh::{ - EndpointId, SecretKey, discovery::{ - UserData, - dns::{N0_DNS_ENDPOINT_ORIGIN_PROD, N0_DNS_ENDPOINT_ORIGIN_STAGING}, - pkarr::{N0_DNS_PKARR_RELAY_PROD, N0_DNS_PKARR_RELAY_STAGING, PkarrRelayClient}, - }, - endpoint_info::{EndpointIdExt, EndpointInfo, IROH_TXT_NAME}, + dns::{N0_DNS_ENDPOINT_ORIGIN_PROD, N0_DNS_ENDPOINT_ORIGIN_STAGING}, pkarr::{PkarrRelayClient, N0_DNS_PKARR_RELAY_PROD, N0_DNS_PKARR_RELAY_STAGING}, UserData + }, endpoint_info::{EndpointIdExt, EndpointInfo, IROH_TXT_NAME}, PublicKey, SecretKey }; use n0_snafu::{Result, ResultExt}; use url::Url; @@ -103,7 +99,7 @@ async fn main() -> Result<()> { println!("publish to {pkarr_relay_url} ..."); let pkarr = PkarrRelayClient::new(pkarr_relay_url); - let endpoint_info = EndpointInfo::new(endpoint_id) + let endpoint_info = EndpointInfo::new(endpoint_id.into()) .with_relay_url(relay_url.map(Into::into)) .with_ip_addrs(args.addr.into_iter().collect()) .with_user_data(args.user_data); @@ -140,6 +136,6 @@ async fn main() -> Result<()> { Ok(()) } -fn fmt_domain(endpoint_id: &EndpointId, origin: &str) -> String { +fn fmt_domain(endpoint_id: &PublicKey, origin: &str) -> String { format!("{IROH_TXT_NAME}.{}.{origin}", endpoint_id.to_z32()) } diff --git a/iroh-dns-server/examples/resolve.rs b/iroh-dns-server/examples/resolve.rs index 2f628585165..c5b5f8a65e6 100644 --- a/iroh-dns-server/examples/resolve.rs +++ b/iroh-dns-server/examples/resolve.rs @@ -73,7 +73,7 @@ async fn main() -> Result<()> { (None, Env::Dev) => DEV_DNS_ORIGIN_DOMAIN, }; resolver - .lookup_endpoint_by_id(&endpoint_id, origin_domain) + .lookup_endpoint_by_id(&endpoint_id.ed25519().unwrap(), origin_domain) .await? } Command::Domain { domain } => resolver.lookup_endpoint_by_domain_name(&domain).await?, diff --git a/iroh-dns-server/src/lib.rs b/iroh-dns-server/src/lib.rs index 17597273ee0..b1be49f496d 100644 --- a/iroh-dns-server/src/lib.rs +++ b/iroh-dns-server/src/lib.rs @@ -22,8 +22,7 @@ mod tests { }; use iroh::{ - RelayUrl, SecretKey, discovery::pkarr::PkarrRelayClient, dns::DnsResolver, - endpoint_info::EndpointInfo, + discovery::pkarr::PkarrRelayClient, dns::DnsResolver, endpoint_info::EndpointInfo, EndpointId, RelayUrl, SecretKey }; use n0_snafu::{Result, ResultExt}; use pkarr::{SignedPacket, Timestamp}; @@ -171,7 +170,7 @@ mod tests { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0u64); let secret_key = SecretKey::generate(&mut rng); - let endpoint_id = secret_key.public(); + let endpoint_id = secret_key.public().into(); let pkarr = PkarrRelayClient::new(pkarr_relay); let relay_url: RelayUrl = "https://relay.example.".parse()?; let endpoint_info = EndpointInfo::new(endpoint_id).with_relay_url(Some(relay_url.clone())); @@ -180,7 +179,7 @@ mod tests { pkarr.publish(&signed_packet).await?; let resolver = test_resolver(nameserver); - let res = resolver.lookup_endpoint_by_id(&endpoint_id, origin).await?; + let res = resolver.lookup_endpoint_by_id(endpoint_id.ed25519().unwrap(), origin).await?; assert_eq!(res.endpoint_id, endpoint_id); assert_eq!(res.relay_urls().next(), Some(&relay_url)); @@ -239,7 +238,7 @@ mod tests { // create a signed packet let secret_key = SecretKey::generate(&mut rng); - let endpoint_id = secret_key.public(); + let endpoint_id: EndpointId = secret_key.public().into(); let relay_url: RelayUrl = "https://relay.example.".parse()?; let endpoint_info = EndpointInfo::new(endpoint_id).with_relay_url(Some(relay_url.clone())); let signed_packet = endpoint_info.to_pkarr_signed_packet(&secret_key, 30)?; @@ -254,7 +253,7 @@ mod tests { // resolve via DNS from our server, which will lookup from our DHT let resolver = test_resolver(nameserver); - let res = resolver.lookup_endpoint_by_id(&endpoint_id, origin).await?; + let res = resolver.lookup_endpoint_by_id(endpoint_id.ed25519().unwrap(), origin).await?; assert_eq!(res.endpoint_id, endpoint_id); assert_eq!(res.relay_urls().next(), Some(&relay_url)); @@ -271,7 +270,7 @@ mod tests { let secret_key = SecretKey::generate(rng); let endpoint_id = secret_key.public(); let relay_url: RelayUrl = "https://relay.example.".parse()?; - let endpoint_info = EndpointInfo::new(endpoint_id).with_relay_url(Some(relay_url.clone())); + let endpoint_info = EndpointInfo::new(endpoint_id.into()).with_relay_url(Some(relay_url.clone())); let packet = endpoint_info.to_pkarr_signed_packet(&secret_key, 30)?; Ok(packet) } diff --git a/iroh-relay/src/dns.rs b/iroh-relay/src/dns.rs index d9bdfd13505..7fcc1e6cdc3 100644 --- a/iroh-relay/src/dns.rs +++ b/iroh-relay/src/dns.rs @@ -12,7 +12,6 @@ use hickory_resolver::{ config::{ResolverConfig, ResolverOpts}, name_server::TokioConnectionProvider, }; -use iroh_base::EndpointId; use n0_future::{ StreamExt, boxed::BoxFuture, @@ -25,6 +24,7 @@ use tracing::debug; use url::Url; use crate::{ + RelayEndpointId, defaults::timeouts::DNS_TIMEOUT, endpoint_info::{self, EndpointInfo, ParseError}, }; @@ -417,7 +417,7 @@ impl DnsResolver { /// pass [`N0_DNS_ENDPOINT_ORIGIN_PROD`] as `origin`. pub async fn lookup_endpoint_by_id( &self, - endpoint_id: &EndpointId, + endpoint_id: &RelayEndpointId, origin: &str, ) -> Result { let name = endpoint_info::endpoint_domain(endpoint_id, origin); @@ -467,7 +467,7 @@ impl DnsResolver { /// summary of all errors otherwise. pub async fn lookup_endpoint_by_id_staggered( &self, - endpoint_id: &EndpointId, + endpoint_id: &RelayEndpointId, origin: &str, delays_ms: &[u64], ) -> Result> { diff --git a/iroh-relay/src/endpoint_info.rs b/iroh-relay/src/endpoint_info.rs index 90ab090511d..28ac2f10087 100644 --- a/iroh-relay/src/endpoint_info.rs +++ b/iroh-relay/src/endpoint_info.rs @@ -45,6 +45,8 @@ use nested_enum_utils::common_fields; use snafu::{Backtrace, ResultExt, Snafu}; use url::Url; +use crate::RelayEndpointId; + /// The DNS name for the iroh TXT record. pub const IROH_TXT_NAME: &str = "_iroh"; @@ -98,20 +100,20 @@ pub trait EndpointIdExt { /// Parses a [`EndpointId`] from [`z-base-32`] encoding. /// /// [`z-base-32`]: https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt - fn from_z32(s: &str) -> Result; + fn from_z32(s: &str) -> Result; } -impl EndpointIdExt for EndpointId { +impl EndpointIdExt for RelayEndpointId { fn to_z32(&self) -> String { z32::encode(self.as_bytes()) } - fn from_z32(s: &str) -> Result { + fn from_z32(s: &str) -> Result { let bytes = z32::decode(s.as_bytes()).context(InvalidEncodingZ32Snafu)?; let bytes: &[u8; 32] = &bytes .try_into() .map_err(|_| InvalidLengthSnafu { len: s.len() }.build())?; - let endpoint_id = EndpointId::from_bytes(bytes).context(InvalidKeySnafu)?; + let endpoint_id = RelayEndpointId::from_bytes(bytes).context(InvalidKeySnafu)?; Ok(endpoint_id) } } @@ -331,7 +333,10 @@ impl From<&TxtAttrs> for EndpointInfo { data.set_user_data(user_data); data.add_addrs(relay_urls.chain(ip_addrs)); - Self { endpoint_id, data } + Self { + endpoint_id: endpoint_id.into(), + data, + } } } @@ -381,7 +386,7 @@ impl EndpointInfo { /// Converts into a [`EndpointAddr`] by cloning the needed fields. pub fn to_endpoint_addr(&self) -> EndpointAddr { EndpointAddr { - id: self.endpoint_id, + id: self.endpoint_id.into(), addrs: self.addrs.clone(), } } @@ -390,13 +395,13 @@ impl EndpointInfo { pub fn into_endpoint_addr(self) -> EndpointAddr { let Self { endpoint_id, data } = self; EndpointAddr { - id: endpoint_id, + id: endpoint_id.into(), addrs: data.addrs, } } - fn to_attrs(&self) -> TxtAttrs { - self.into() + fn to_attrs(&self) -> Result, &'static str> { + self.try_into() } #[cfg(not(wasm_browser))] @@ -423,12 +428,14 @@ impl EndpointInfo { secret_key: &SecretKey, ttl: u32, ) -> Result { - self.to_attrs().to_pkarr_signed_packet(secret_key, ttl) + self.to_attrs() + .unwrap() + .to_pkarr_signed_packet(secret_key, ttl) } /// Converts into a list of `{key}={value}` strings. pub fn to_txt_strings(&self) -> Vec { - self.to_attrs().to_txt_strings().collect() + self.to_attrs().unwrap().to_txt_strings().collect() } } @@ -478,7 +485,7 @@ impl std::ops::DerefMut for EndpointInfo { /// [`IROH_TXT_NAME`] and the second label to be a z32 encoded [`EndpointId`]. Ignores /// subsequent labels. #[cfg(not(wasm_browser))] -fn endpoint_id_from_txt_name(name: &str) -> Result { +fn endpoint_id_from_txt_name(name: &str) -> Result { let num_labels = name.split(".").count(); if num_labels < 2 { return Err(NumLabelsSnafu { num_labels }.build()); @@ -489,7 +496,7 @@ fn endpoint_id_from_txt_name(name: &str) -> Result { return Err(NotAnIrohRecordSnafu { label }.build()); } let label = labels.next().expect("checked above"); - let endpoint_id = EndpointId::from_z32(label)?; + let endpoint_id = RelayEndpointId::from_z32(label)?; Ok(endpoint_id) } @@ -516,12 +523,13 @@ pub(crate) enum IrohAttr { /// [`Display`]. #[derive(Debug)] pub(crate) struct TxtAttrs { - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, attrs: BTreeMap>, } -impl From<&EndpointInfo> for TxtAttrs { - fn from(info: &EndpointInfo) -> Self { +impl TryFrom<&EndpointInfo> for TxtAttrs { + type Error = &'static str; + fn try_from(info: &EndpointInfo) -> Result { let mut attrs = vec![]; for addr in &info.data.addrs { match addr { @@ -536,14 +544,17 @@ impl From<&EndpointInfo> for TxtAttrs { if let Some(user_data) = &info.data.user_data { attrs.push((IrohAttr::UserData, user_data.to_string())); } - Self::from_parts(info.endpoint_id, attrs.into_iter()) + let iroh_base::EndpointId::Ed25519(endpoint_id) = info.endpoint_id else { + return Err("Unsupported endpoint ID type"); + }; + Ok(Self::from_parts(endpoint_id, attrs.into_iter())) } } impl TxtAttrs { /// Creates [`TxtAttrs`] from an endpoint id and an iterator of key-value pairs. pub(crate) fn from_parts( - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, pairs: impl Iterator, ) -> Self { let mut attrs: BTreeMap> = BTreeMap::new(); @@ -555,7 +566,7 @@ impl TxtAttrs { /// Creates [`TxtAttrs`] from an endpoint id and an iterator of "{key}={value}" strings. pub(crate) fn from_strings( - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, strings: impl Iterator, ) -> Result { let mut attrs: BTreeMap> = BTreeMap::new(); @@ -576,7 +587,7 @@ impl TxtAttrs { } /// Returns the endpoint id. - pub(crate) fn endpoint_id(&self) -> EndpointId { + pub(crate) fn endpoint_id(&self) -> RelayEndpointId { self.endpoint_id } @@ -591,7 +602,7 @@ impl TxtAttrs { let pubkey = packet.public_key(); let pubkey_z32 = pubkey.to_z32(); let endpoint_id = - EndpointId::from_bytes(&pubkey.verifying_key().to_bytes()).expect("valid key"); + RelayEndpointId::from_bytes(&pubkey.verifying_key().to_bytes()).expect("valid key"); let zone = dns::Name::new(&pubkey_z32).expect("z32 encoding is valid"); let txt_data = packet .all_resource_records() @@ -659,8 +670,8 @@ pub(crate) fn ensure_iroh_txt_label(name: String) -> String { } #[cfg(not(wasm_browser))] -pub(crate) fn endpoint_domain(endpoint_id: &EndpointId, origin: &str) -> String { - format!("{}.{}", EndpointId::to_z32(endpoint_id), origin) +pub(crate) fn endpoint_domain(endpoint_id: &RelayEndpointId, origin: &str) -> String { + format!("{}.{}", RelayEndpointId::to_z32(endpoint_id), origin) } #[cfg(test)] @@ -678,11 +689,11 @@ mod tests { }, }, }; - use iroh_base::{EndpointId, SecretKey, TransportAddr}; + use iroh_base::{SecretKey, TransportAddr}; use n0_snafu::{Result, ResultExt}; use super::{EndpointData, EndpointIdExt, EndpointInfo}; - use crate::dns::TxtRecordData; + use crate::{RelayEndpointId, dns::TxtRecordData}; #[test] fn txt_attr_roundtrip() { @@ -695,7 +706,7 @@ mod tests { .parse() .unwrap(); let expected = EndpointInfo::from_parts(endpoint_id, endpoint_data); - let attrs = expected.to_attrs(); + let attrs = expected.to_attrs().unwrap(); let actual = EndpointInfo::from(&attrs); assert_eq!(expected, actual); } @@ -709,7 +720,7 @@ mod tests { TransportAddr::Ip("127.0.0.1:1234".parse().unwrap()), ]) .with_user_data(Some("foobar".parse().unwrap())); - let expected = EndpointInfo::from_parts(secret_key.public(), endpoint_data); + let expected = EndpointInfo::from_parts(secret_key.public().into(), endpoint_data); let packet = expected.to_pkarr_signed_packet(&secret_key, 30).unwrap(); let actual = EndpointInfo::from_pkarr_signed_packet(&packet).unwrap(); assert_eq!(expected, actual); @@ -745,7 +756,7 @@ mod tests { Record::from_rdata( Name::from_utf8(format!( "_iroh.{}.dns.iroh.link.", - EndpointId::from_str( + RelayEndpointId::from_str( // Another EndpointId "a55f26132e5e43de834d534332f66a20d480c3e50a13a312a071adea6569981e" )? @@ -781,7 +792,7 @@ mod tests { let endpoint_info = EndpointInfo::from_txt_lookup(name.to_string(), lookup)?; - let expected_endpoint_info = EndpointInfo::new(EndpointId::from_str( + let expected_endpoint_info = EndpointInfo::new(iroh_base::EndpointId::from_str( "1992d53c02cdc04566e5c0edb1ce83305cd550297953a047a445ea3264b54b18", )?) .with_relay_url(Some("https://euw1-1.relay.iroh.network./".parse()?)) diff --git a/iroh-relay/src/lib.rs b/iroh-relay/src/lib.rs index 6d6ecd1161e..1663887df47 100644 --- a/iroh-relay/src/lib.rs +++ b/iroh-relay/src/lib.rs @@ -82,3 +82,6 @@ pub(crate) trait ExportKeyingMaterial { context: Option<&[u8]>, ) -> Option; } + +/// The endpoint id for iroh-relay is always an ed25519 public key. +pub type RelayEndpointId = iroh_base::PublicKey; diff --git a/iroh-relay/src/main.rs b/iroh-relay/src/main.rs index ef68a6e855d..e66adcbacb3 100644 --- a/iroh-relay/src/main.rs +++ b/iroh-relay/src/main.rs @@ -12,8 +12,8 @@ use std::{ use clap::Parser; use http::StatusCode; -use iroh_base::EndpointId; use iroh_relay::{ + RelayEndpointId, defaults::{ DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT, DEFAULT_METRICS_PORT, DEFAULT_RELAY_QUIC_PORT, }, @@ -178,9 +178,9 @@ enum AccessConfig { #[default] Everyone, /// Allows only these endpoints. - Allowlist(Vec), + Allowlist(Vec), /// Allows everyone, except these endpoints. - Denylist(Vec), + Denylist(Vec), /// Performs a HTTP POST request to determine access for each endpoint that connects to the relay. /// /// The request will have a header `X-Iroh-Endpoint-Id` set to the hex-encoded endpoint id attempting @@ -260,7 +260,7 @@ impl From for iroh_relay::server::AccessConfig { async fn http_access_check( client: &reqwest::Client, config: &HttpAccessConfig, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, ) -> iroh_relay::server::Access { use iroh_relay::server::Access; debug!(url=%config.url, "Check relay access via HTTP POST"); @@ -280,7 +280,7 @@ async fn http_access_check( async fn http_access_check_inner( client: &reqwest::Client, config: &HttpAccessConfig, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, ) -> Result<()> { let mut request = client .post(config.url.clone()) diff --git a/iroh-relay/src/protos/relay.rs b/iroh-relay/src/protos/relay.rs index 26e60e0e669..a082457dac8 100644 --- a/iroh-relay/src/protos/relay.rs +++ b/iroh-relay/src/protos/relay.rs @@ -10,13 +10,13 @@ use std::num::NonZeroU16; use bytes::{Buf, BufMut, Bytes, BytesMut}; -use iroh_base::{EndpointId, KeyParsingError}; +use iroh_base::KeyParsingError; use n0_future::time::Duration; use nested_enum_utils::common_fields; use snafu::{Backtrace, ResultExt, Snafu}; use super::common::{FrameType, FrameTypeError}; -use crate::KeyCache; +use crate::{KeyCache, RelayEndpointId}; /// The maximum size of a packet sent over relay. /// (This only includes the data bytes visible to magicsock, not @@ -76,13 +76,13 @@ pub enum RelayToClientMsg { /// Represents datagrams sent from relays (originally sent to them by another client). Datagrams { /// The [`EndpointId`] of the original sender. - remote_endpoint_id: EndpointId, + remote_endpoint_id: RelayEndpointId, /// The datagrams and related metadata. datagrams: Datagrams, }, /// Indicates that the client identified by the underlying public key had previously sent you a /// packet but has now disconnected from the relay. - EndpointGone(EndpointId), + EndpointGone(RelayEndpointId), /// A one-way message from relay to client, declaring the connection health state. Health { /// If set, is a description of why the connection is unhealthy. @@ -124,7 +124,7 @@ pub enum ClientToRelayMsg { /// Request from the client to relay datagrams to given remote endpoint. Datagrams { /// The remote endpoint to relay to. - dst_endpoint_id: EndpointId, + dst_endpoint_id: RelayEndpointId, /// The datagrams and related metadata to relay. datagrams: Datagrams, }, @@ -336,13 +336,13 @@ impl RelayToClientMsg { let res = match frame_type { FrameType::RelayToClientDatagram | FrameType::RelayToClientDatagramBatch => { - snafu::ensure!(content.len() >= EndpointId::LENGTH, InvalidFrameSnafu); + snafu::ensure!(content.len() >= RelayEndpointId::LENGTH, InvalidFrameSnafu); let remote_endpoint_id = cache - .key_from_slice(&content[..EndpointId::LENGTH]) + .key_from_slice(&content[..RelayEndpointId::LENGTH]) .context(InvalidPublicKeySnafu)?; let datagrams = Datagrams::from_bytes( - content.slice(EndpointId::LENGTH..), + content.slice(RelayEndpointId::LENGTH..), frame_type == FrameType::RelayToClientDatagramBatch, )?; Self::Datagrams { @@ -351,7 +351,7 @@ impl RelayToClientMsg { } } FrameType::EndpointGone => { - snafu::ensure!(content.len() == EndpointId::LENGTH, InvalidFrameSnafu); + snafu::ensure!(content.len() == RelayEndpointId::LENGTH, InvalidFrameSnafu); let endpoint_id = cache .key_from_slice(content.as_ref()) .context(InvalidPublicKeySnafu)?; @@ -471,10 +471,10 @@ impl ClientToRelayMsg { let res = match frame_type { FrameType::ClientToRelayDatagram | FrameType::ClientToRelayDatagramBatch => { let dst_endpoint_id = cache - .key_from_slice(&content[..EndpointId::LENGTH]) + .key_from_slice(&content[..RelayEndpointId::LENGTH]) .context(InvalidPublicKeySnafu)?; let datagrams = Datagrams::from_bytes( - content.slice(EndpointId::LENGTH..), + content.slice(RelayEndpointId::LENGTH..), frame_type == FrameType::ClientToRelayDatagramBatch, )?; Self::Datagrams { @@ -686,7 +686,7 @@ mod proptests { prop::array::uniform32(any::()).prop_map(SecretKey::from) } - fn key() -> impl Strategy { + fn key() -> impl Strategy { secret_key().prop_map(|key| key.public()) } @@ -701,7 +701,7 @@ mod proptests { fn datagrams() -> impl Strategy { // The max payload size (conservatively, since with segment_size = 0 we'd have slightly more space) - const MAX_PAYLOAD_SIZE: usize = MAX_PACKET_SIZE - EndpointId::LENGTH - 1 /* ECN bytes */ - 2 /* segment size */; + const MAX_PAYLOAD_SIZE: usize = MAX_PACKET_SIZE - RelayEndpointId::LENGTH - 1 /* ECN bytes */ - 2 /* segment size */; ( ecn(), prop::option::of(MAX_PAYLOAD_SIZE / 20..MAX_PAYLOAD_SIZE), diff --git a/iroh-relay/src/server.rs b/iroh-relay/src/server.rs index 034ac46cac7..b7d43c99c97 100644 --- a/iroh-relay/src/server.rs +++ b/iroh-relay/src/server.rs @@ -23,7 +23,6 @@ use http::{ response::Builder as ResponseBuilder, }; use hyper::body::Incoming; -use iroh_base::EndpointId; #[cfg(feature = "test-utils")] use iroh_base::RelayUrl; use n0_future::{StreamExt, future::Boxed}; @@ -37,6 +36,7 @@ use tokio_util::task::AbortOnDropHandle; use tracing::{Instrument, debug, error, info, info_span, instrument}; use crate::{ + RelayEndpointId, defaults::DEFAULT_KEY_CACHE_CAPACITY, http::RELAY_PROBE_PATH, quic::server::{QuicServer, QuicSpawnError, ServerHandle as QuicServerHandle}, @@ -135,12 +135,12 @@ pub enum AccessConfig { Everyone, /// Only endpoints for which the function returns `Access::Allow`. #[debug("restricted")] - Restricted(Box Boxed + Send + Sync + 'static>), + Restricted(Box Boxed + Send + Sync + 'static>), } impl AccessConfig { /// Is this endpoint allowed? - pub async fn is_allowed(&self, endpoint: EndpointId) -> bool { + pub async fn is_allowed(&self, endpoint: RelayEndpointId) -> bool { match self { Self::Everyone => true, Self::Restricted(check) => { @@ -749,7 +749,7 @@ mod tests { use std::{net::Ipv4Addr, time::Duration}; use http::StatusCode; - use iroh_base::{EndpointId, RelayUrl, SecretKey}; + use iroh_base::{RelayUrl, SecretKey}; use n0_future::{FutureExt, SinkExt, StreamExt}; use n0_snafu::Result; use rand::SeedableRng; @@ -761,6 +761,7 @@ mod tests { Server, ServerConfig, SpawnError, }; use crate::{ + RelayEndpointId, client::{ClientBuilder, ConnectError}, dns::DnsResolver, protos::{ @@ -788,7 +789,7 @@ mod tests { async fn try_send_recv( client_a: &mut crate::client::Client, client_b: &mut crate::client::Client, - b_key: EndpointId, + b_key: RelayEndpointId, msg: Datagrams, ) -> Result { // try resend 10 times diff --git a/iroh-relay/src/server/client.rs b/iroh-relay/src/server/client.rs index 21ec13bb634..14352a692b7 100644 --- a/iroh-relay/src/server/client.rs +++ b/iroh-relay/src/server/client.rs @@ -2,7 +2,6 @@ use std::{collections::HashSet, sync::Arc, time::Duration}; -use iroh_base::EndpointId; use n0_future::{SinkExt, StreamExt}; use nested_enum_utils::common_fields; use rand::Rng; @@ -16,7 +15,7 @@ use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle}; use tracing::{Instrument, debug, trace, warn}; use crate::{ - PingTracker, + PingTracker, RelayEndpointId, protos::{ disco, relay::{ClientToRelayMsg, Datagrams, PING_INTERVAL, RelayToClientMsg}, @@ -32,7 +31,7 @@ use crate::{ #[derive(Debug, Clone)] pub(super) struct Packet { /// The sender of the packet - src: EndpointId, + src: RelayEndpointId, /// The data packet bytes. data: Datagrams, } @@ -40,7 +39,7 @@ pub(super) struct Packet { /// Configuration for a [`Client`]. #[derive(Debug)] pub(super) struct Config { - pub(super) endpoint_id: EndpointId, + pub(super) endpoint_id: RelayEndpointId, pub(super) stream: RelayedStream, pub(super) write_timeout: Duration, pub(super) channel_capacity: usize, @@ -53,7 +52,7 @@ pub(super) struct Config { #[derive(Debug)] pub(super) struct Client { /// Identity of the connected peer. - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, /// Connection identifier. connection_id: u64, /// Used to close the connection loop. @@ -65,7 +64,7 @@ pub(super) struct Client { /// Queue of disco packets intended for the client. disco_send_queue: mpsc::Sender, /// Channel to notify the client that a previous sender has disconnected. - peer_gone: mpsc::Sender, + peer_gone: mpsc::Sender, } impl Client { @@ -148,7 +147,7 @@ impl Client { pub(super) fn try_send_packet( &self, - src: EndpointId, + src: RelayEndpointId, data: Datagrams, ) -> Result<(), TrySendError> { self.send_queue.try_send(Packet { src, data }) @@ -156,7 +155,7 @@ impl Client { pub(super) fn try_send_disco_packet( &self, - src: EndpointId, + src: RelayEndpointId, data: Datagrams, ) -> Result<(), TrySendError> { self.disco_send_queue.try_send(Packet { src, data }) @@ -164,8 +163,8 @@ impl Client { pub(super) fn try_send_peer_gone( &self, - key: EndpointId, - ) -> Result<(), TrySendError> { + key: RelayEndpointId, + ) -> Result<(), TrySendError> { self.peer_gone.try_send(key) } } @@ -293,9 +292,9 @@ struct Actor { /// Important packets queued to send to the client disco_send_queue: mpsc::Receiver, /// Notify the client that a previous sender has disconnected - endpoint_gone: mpsc::Receiver, + endpoint_gone: mpsc::Receiver, /// [`EndpointId`] of this client - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, /// Connection identifier. connection_id: u64, /// Reference to the other connected clients. @@ -488,7 +487,7 @@ impl Actor { fn handle_frame_send_packet( &self, - dst: EndpointId, + dst: RelayEndpointId, data: Datagrams, ) -> Result<(), ForwardPacketError> { if disco::looks_like_disco_wrapper(&data.contents) { @@ -537,7 +536,7 @@ impl ForwardPacketError { /// Tracks how many unique endpoints have been seen during the last day. #[derive(Debug)] struct ClientCounter { - clients: HashSet, + clients: HashSet, last_clear_date: Date, } @@ -560,7 +559,7 @@ impl ClientCounter { } /// Marks this endpoint as seen, returns whether it is new today or not. - fn update(&mut self, client: EndpointId) -> bool { + fn update(&mut self, client: RelayEndpointId) -> bool { self.check_and_clear(); self.clients.insert(client) } diff --git a/iroh-relay/src/server/clients.rs b/iroh-relay/src/server/clients.rs index fe92439db1d..b20515d9810 100644 --- a/iroh-relay/src/server/clients.rs +++ b/iroh-relay/src/server/clients.rs @@ -10,12 +10,12 @@ use std::{ }; use dashmap::DashMap; -use iroh_base::EndpointId; use tokio::sync::mpsc::error::TrySendError; use tracing::{debug, trace}; use super::client::{Client, Config, ForwardPacketError}; use crate::{ + RelayEndpointId, protos::relay::Datagrams, server::{ client::{PacketScope, SendError}, @@ -30,9 +30,9 @@ pub(super) struct Clients(Arc); #[derive(Debug, Default)] struct Inner { /// The list of all currently connected clients. - clients: DashMap, + clients: DashMap, /// Map of which client has sent where - sent_to: DashMap>, + sent_to: DashMap>, /// Connection ID Counter next_connection_id: AtomicU64, } @@ -72,7 +72,7 @@ impl Clients { /// peer is gone from the network. /// /// Must be passed a matching connection_id. - pub(super) fn unregister(&self, connection_id: u64, endpoint_id: EndpointId) { + pub(super) fn unregister(&self, connection_id: u64, endpoint_id: RelayEndpointId) { trace!( endpoint_id = %endpoint_id.fmt_short(), connection_id, "unregistering client" @@ -108,9 +108,9 @@ impl Clients { /// Attempt to send a packet to client with [`EndpointId`] `dst`. pub(super) fn send_packet( &self, - dst: EndpointId, + dst: RelayEndpointId, data: Datagrams, - src: EndpointId, + src: RelayEndpointId, metrics: &Metrics, ) -> Result<(), ForwardPacketError> { let Some(client) = self.0.clients.get(&dst) else { @@ -148,9 +148,9 @@ impl Clients { /// Attempt to send a disco packet to client with [`EndpointId`] `dst`. pub(super) fn send_disco_packet( &self, - dst: EndpointId, + dst: RelayEndpointId, data: Datagrams, - src: EndpointId, + src: RelayEndpointId, metrics: &Metrics, ) -> Result<(), ForwardPacketError> { let Some(client) = self.0.clients.get(&dst) else { @@ -228,7 +228,7 @@ mod tests { } } - fn test_client_builder(key: EndpointId) -> (Config, Conn) { + fn test_client_builder(key: RelayEndpointId) -> (Config, Conn) { let (server, client) = tokio::io::duplex(1024); ( Config { diff --git a/iroh/src/discovery.rs b/iroh/src/discovery.rs index d2a27c7caac..5a5236097d5 100644 --- a/iroh/src/discovery.rs +++ b/iroh/src/discovery.rs @@ -113,6 +113,7 @@ use std::sync::{Arc, RwLock}; use iroh_base::{EndpointAddr, EndpointId}; +use iroh_relay::RelayEndpointId; use n0_future::{ boxed::BoxStream, stream::StreamExt, @@ -504,7 +505,7 @@ pub(super) struct DiscoveryTask { impl DiscoveryTask { /// Starts a discovery task. - pub(super) fn start(ep: Endpoint, endpoint_id: EndpointId) -> Result { + pub(super) fn start(ep: Endpoint, endpoint_id: RelayEndpointId) -> Result { ensure!(!ep.discovery().is_empty(), NoServiceConfiguredSnafu); let (on_first_tx, on_first_rx) = oneshot::channel(); let me = ep.id(); @@ -529,7 +530,7 @@ impl DiscoveryTask { /// Otherwise, or if no `delay` is set, the discovery will be started. pub(super) fn maybe_start_after_delay( ep: &Endpoint, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, delay: Option, ) -> Result, DiscoveryError> { // If discovery is not needed, don't even spawn a task. @@ -572,19 +573,19 @@ impl DiscoveryTask { fn create_stream( ep: &Endpoint, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, ) -> Result>, DiscoveryError> { ensure!(!ep.discovery().is_empty(), NoServiceConfiguredSnafu); let stream = ep .discovery() - .resolve(endpoint_id) + .resolve(endpoint_id.into()) .ok_or(NoResultsSnafu { endpoint_id }.build())?; Ok(stream) } async fn run( ep: Endpoint, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, on_first_tx: oneshot::Sender>, ) { let mut stream = match Self::create_stream(&ep, endpoint_id) { @@ -987,7 +988,7 @@ mod test_dns_pkarr { .context("Running DNS server")?; let secret_key = SecretKey::generate(&mut rng); - let endpoint_info = EndpointInfo::new(secret_key.public()) + let endpoint_info = EndpointInfo::new(secret_key.public().into()) .with_relay_url(Some("https://relay.example".parse().unwrap())); let signed_packet = endpoint_info.to_pkarr_signed_packet(&secret_key, 30)?; state @@ -996,7 +997,7 @@ mod test_dns_pkarr { let resolver = DnsResolver::with_nameserver(nameserver); let resolved = resolver - .lookup_endpoint_by_id(&endpoint_info.endpoint_id, &origin) + .lookup_endpoint_by_id(&endpoint_info.endpoint_id.ed25519().unwrap(), &origin) .await?; assert_eq!(resolved, endpoint_info); @@ -1015,7 +1016,7 @@ mod test_dns_pkarr { .context("DnsPkarrServer")?; let secret_key = SecretKey::generate(&mut rng); - let endpoint_id = secret_key.public(); + let endpoint_id = secret_key.public().into(); let relay_url = Some(TransportAddr::Relay( "https://relay.example".parse().unwrap(), @@ -1039,7 +1040,7 @@ mod test_dns_pkarr { println!("resolved {resolved:?}"); let expected_addr = EndpointAddr { - id: endpoint_id, + id: endpoint_id.into(), addrs: relay_url.into_iter().collect(), }; @@ -1063,7 +1064,7 @@ mod test_dns_pkarr { // wait until our shared state received the update from pkarr publishing dns_pkarr_server - .on_endpoint(&ep1.id(), PUBLISH_TIMEOUT) + .on_endpoint(&ep1.id().ed25519().unwrap(), PUBLISH_TIMEOUT) .await .context("wait for on endpoint update")?; diff --git a/iroh/src/discovery/dns.rs b/iroh/src/discovery/dns.rs index bcfe90cef74..57877f5b610 100644 --- a/iroh/src/discovery/dns.rs +++ b/iroh/src/discovery/dns.rs @@ -107,6 +107,7 @@ impl Discovery for DnsDiscovery { &self, endpoint_id: EndpointId, ) -> Option>> { + let endpoint_id = *endpoint_id.ed25519()?; let resolver = self.dns_resolver.clone(); let origin_domain = self.origin_domain.clone(); let fut = async move { diff --git a/iroh/src/discovery/pkarr.rs b/iroh/src/discovery/pkarr.rs index e520049bc8f..cdb8f32ecc8 100644 --- a/iroh/src/discovery/pkarr.rs +++ b/iroh/src/discovery/pkarr.rs @@ -46,7 +46,7 @@ use std::sync::Arc; -use iroh_base::{EndpointId, RelayUrl, SecretKey}; +use iroh_base::{EndpointId, PublicKey, RelayUrl, SecretKey}; use iroh_relay::endpoint_info::{EncodingError, EndpointInfo}; use n0_future::{ boxed::BoxStream, @@ -67,7 +67,7 @@ use super::{DiscoveryError, IntoDiscovery, IntoDiscoveryError}; use crate::dns::DnsResolver; use crate::{ Endpoint, - discovery::{Discovery, DiscoveryItem, EndpointData}, + discovery::{Discovery, DiscoveryItem, EndpointData, NoResultsSnafu}, endpoint::force_staging_infra, util::reqwest_client_builder, }; @@ -231,7 +231,7 @@ impl IntoDiscovery for PkarrPublisherBuilder { /// [`ConcurrentDiscovery`]: super::ConcurrentDiscovery #[derive(derive_more::Debug, Clone)] pub struct PkarrPublisher { - endpoint_id: EndpointId, + endpoint_id: PublicKey, watchable: Watchable>, _drop_guard: Arc>, } @@ -316,10 +316,10 @@ impl PkarrPublisher { pub fn update_endpoint_data(&self, data: &EndpointData) { let mut data = data.clone(); if data.relay_urls().next().is_some() { - // If relay url is set: only publish relay url, and no addrs. + // If relay url is set: only publish relay url, and no addrs. data.clear_ip_addrs(); } - let info = EndpointInfo::from_parts(self.endpoint_id, data); + let info = EndpointInfo::from_parts(self.endpoint_id.into(), data); self.watchable.set(Some(info)).ok(); } } @@ -548,6 +548,9 @@ impl PkarrRelayClient { /// Resolves a [`SignedPacket`] for the given [`EndpointId`]. pub async fn resolve(&self, endpoint_id: EndpointId) -> Result { + let EndpointId::Ed25519(endpoint_id) = endpoint_id else { + return Err(NoResultsSnafu { endpoint_id }.build()); + }; // We map the error to string, as in browsers the error is !Send let public_key = pkarr::PublicKey::try_from(endpoint_id.as_bytes()).context(PublicKeySnafu)?; diff --git a/iroh/src/discovery/static_provider.rs b/iroh/src/discovery/static_provider.rs index a1764026039..1ed7143564d 100644 --- a/iroh/src/discovery/static_provider.rs +++ b/iroh/src/discovery/static_provider.rs @@ -51,7 +51,7 @@ use super::{Discovery, DiscoveryError, DiscoveryItem, EndpointData, EndpointInfo /// .await?; /// /// // Sometime later add a RelayUrl for our endpoint. -/// let id = SecretKey::generate(&mut rand::rng()).public(); +/// let id = SecretKey::generate(&mut rand::rng()).public().into(); /// // You can pass either `EndpointInfo` or `EndpointAddr` to `add_endpoint_info`. /// discovery.add_endpoint_info(EndpointAddr { /// id, @@ -249,7 +249,7 @@ mod tests { let key = SecretKey::from_bytes(&[0u8; 32]); let addr = EndpointAddr { - id: key.public(), + id: key.public().into(), addrs: [TransportAddr::Relay("https://example.com".parse()?)] .into_iter() .collect(), @@ -259,7 +259,7 @@ mod tests { discovery.add_endpoint_info(endpoint_info.clone()); let back = discovery - .get_endpoint_info(key.public()) + .get_endpoint_info(key.public().into()) .context("no addr")?; assert_eq!(back, endpoint_info); @@ -267,10 +267,10 @@ mod tests { assert_eq!(back.into_endpoint_addr(), addr); let removed = discovery - .remove_endpoint_info(key.public()) + .remove_endpoint_info(key.public().into()) .context("nothing removed")?; assert_eq!(removed, endpoint_info); - let res = discovery.get_endpoint_info(key.public()); + let res = discovery.get_endpoint_info(key.public().into()); assert!(res.is_none()); Ok(()) @@ -281,13 +281,13 @@ mod tests { let discovery = StaticProvider::with_provenance("foo"); let key = SecretKey::from_bytes(&[0u8; 32]); let addr = EndpointAddr { - id: key.public(), + id: key.public().into(), addrs: [TransportAddr::Relay("https://example.com".parse()?)] .into_iter() .collect(), }; discovery.add_endpoint_info(addr); - let mut stream = discovery.resolve(key.public()).unwrap(); + let mut stream = discovery.resolve(key.public().into()).unwrap(); let item = stream.next().await.unwrap()?; assert_eq!(item.provenance(), "foo"); assert_eq!( diff --git a/iroh/src/endpoint.rs b/iroh/src/endpoint.rs index c6110c6f4d7..12053b0dcc5 100644 --- a/iroh/src/endpoint.rs +++ b/iroh/src/endpoint.rs @@ -20,9 +20,10 @@ use std::{ task::Poll, }; +use iroh_base::PublicKey; use ed25519_dalek::{VerifyingKey, pkcs8::DecodePublicKey}; use iroh_base::{EndpointAddr, EndpointId, RelayUrl, SecretKey, TransportAddr}; -use iroh_relay::{RelayConfig, RelayMap}; +use iroh_relay::{RelayConfig, RelayEndpointId, RelayMap}; use n0_future::time::Duration; use n0_watcher::Watcher; use nested_enum_utils::common_fields; @@ -697,7 +698,9 @@ impl Endpoint { if !endpoint_addr.is_empty() { self.add_endpoint_addr(endpoint_addr.clone(), Source::App)?; } - let endpoint_id = endpoint_addr.id; + let Some(endpoint_id) = endpoint_addr.id.to_ed25519() else { + panic!(); + }; let ip_addresses: Vec<_> = endpoint_addr.ip_addrs().cloned().collect(); let relay_url = endpoint_addr.relay_urls().next().cloned(); @@ -749,7 +752,7 @@ impl Endpoint { Ok(Connecting { inner: connect, ep: self.clone(), - remote_endpoint_id: Some(endpoint_id), + remote_endpoint_id: Some(endpoint_id.into()), _discovery_drop_guard, }) } @@ -815,7 +818,7 @@ impl Endpoint { /// This ID is the unique addressing information of this endpoint and other peers must know /// it to be able to connect to this endpoint. pub fn id(&self) -> EndpointId { - self.static_config.tls_config.secret_key.public() + self.static_config.tls_config.secret_key.public().into() } /// Returns the current [`EndpointAddr`]. @@ -997,14 +1000,14 @@ impl Endpoint { /// /// Will return `None` if we do not have any address information for the given `endpoint_id`. pub fn conn_type(&self, endpoint_id: EndpointId) -> Option> { - self.msock.conn_type(endpoint_id) + self.msock.conn_type(endpoint_id.to_ed25519()?) } /// Returns the currently lowest latency for this endpoint. /// /// Will return `None` if we do not have any address information for the given `endpoint_id`. pub fn latency(&self, endpoint_id: EndpointId) -> Option { - self.msock.latency(endpoint_id) + self.msock.latency(endpoint_id.to_ed25519()?) } /// Returns the DNS resolver used in this [`Endpoint`]. @@ -1221,7 +1224,7 @@ impl Endpoint { // # Remaining private methods /// Checks if the given `EndpointId` needs discovery. - pub(crate) fn needs_discovery(&self, endpoint_id: EndpointId, max_age: Duration) -> bool { + pub(crate) fn needs_discovery(&self, endpoint_id: RelayEndpointId, max_age: Duration) -> bool { match self.msock.remote_info(endpoint_id) { // No info means no path to endpoint -> start discovery. None => true, @@ -1260,7 +1263,7 @@ impl Endpoint { &self, endpoint_addr: EndpointAddr, ) -> Result<(EndpointIdMappedAddr, Option), GetMappingAddressError> { - let endpoint_id = endpoint_addr.id; + let endpoint_id = *endpoint_addr.id.ed25519().unwrap(); // Only return a mapped addr if we have some way of dialing this endpoint, in other // words, we have either a relay URL or at least one direct address. @@ -1933,12 +1936,12 @@ impl Connection { return Err(RemoteEndpointIdSnafu.build()); } - let peer_id = EndpointId::from_verifying_key( + let peer_id = PublicKey::from_verifying_key( VerifyingKey::from_public_key_der(&certs[0]) .map_err(|_| RemoteEndpointIdSnafu.build())?, ); - Ok(peer_id) + Ok(peer_id.into()) } Err(err) => { warn!("invalid peer certificate: {:?}", err); @@ -2218,7 +2221,7 @@ mod tests { .bind() .await?; info!("client connecting"); - let endpoint_addr = EndpointAddr::new(server_peer_id).with_relay_url(relay_url); + let endpoint_addr = EndpointAddr::new(server_peer_id.into()).with_relay_url(relay_url); let conn = ep.connect(endpoint_addr, TEST_ALPN).await?; let mut stream = conn.open_uni().await.e()?; @@ -2329,7 +2332,7 @@ mod tests { info!(me = %ep.id().fmt_short(), eps=?eps, "client bound"); let endpoint_addr = - EndpointAddr::new(server_endpoint_id).with_relay_url(relay_url.clone()); + EndpointAddr::new(server_endpoint_id.into()).with_relay_url(relay_url.clone()); info!(to = ?endpoint_addr, "client connecting"); let conn = ep.connect(endpoint_addr, TEST_ALPN).await.e()?; info!("client connected"); diff --git a/iroh/src/magicsock.rs b/iroh/src/magicsock.rs index a05c2a1a96f..ff83a4c4619 100644 --- a/iroh/src/magicsock.rs +++ b/iroh/src/magicsock.rs @@ -30,8 +30,8 @@ use std::{ use bytes::Bytes; use data_encoding::HEXLOWER; -use iroh_base::{EndpointAddr, EndpointId, PublicKey, RelayUrl, SecretKey, TransportAddr}; -use iroh_relay::{RelayConfig, RelayMap}; +use iroh_base::{EndpointAddr, PublicKey, RelayUrl, SecretKey, TransportAddr}; +use iroh_relay::{RelayConfig, RelayEndpointId, RelayMap}; use n0_future::{ task::{self, AbortOnDropHandle}, time::{self, Duration, Instant}, @@ -288,7 +288,7 @@ impl MagicSock { } /// Return the [`RemoteInfo`] for a single endpoint in the endpoint map. - pub(crate) fn remote_info(&self, endpoint_id: EndpointId) -> Option { + pub(crate) fn remote_info(&self, endpoint_id: RelayEndpointId) -> Option { self.endpoint_map.remote_info(endpoint_id) } @@ -382,17 +382,17 @@ impl MagicSock { /// given `endpoint_id`. pub(crate) fn conn_type( &self, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, ) -> Option> { self.endpoint_map.conn_type(endpoint_id) } - pub(crate) fn latency(&self, endpoint_id: EndpointId) -> Option { + pub(crate) fn latency(&self, endpoint_id: RelayEndpointId) -> Option { self.endpoint_map.latency(endpoint_id) } /// Returns the socket address which can be used by the QUIC layer to dial this endpoint. - pub(crate) fn get_mapping_addr(&self, endpoint_id: EndpointId) -> Option { + pub(crate) fn get_mapping_addr(&self, endpoint_id: RelayEndpointId) -> Option { self.endpoint_map .get_quic_mapped_addr_for_endpoint_key(endpoint_id) } @@ -849,7 +849,7 @@ impl MagicSock { } /// Handle a ping message. - fn handle_ping(&self, dm: disco::Ping, sender: EndpointId, src: &transports::Addr) { + fn handle_ping(&self, dm: disco::Ping, sender: RelayEndpointId, src: &transports::Addr) { // Insert the ping into the endpoint map, and return whether a ping with this tx_id was already // received. let addr: SendAddr = src.clone().into(); @@ -1671,8 +1671,8 @@ impl DiscoState { fn encode_and_seal( &self, - this_endpoint_id: EndpointId, - other_endpoint_id: EndpointId, + this_endpoint_id: RelayEndpointId, + other_endpoint_id: RelayEndpointId, msg: &disco::Message, ) -> Bytes { let mut seal = msg.as_bytes(); @@ -1789,7 +1789,7 @@ impl AsyncUdpSocket for MagicUdpSocket { enum ActorMessage { EndpointPingExpired(usize, TransactionId), NetworkChange, - ScheduleDirectAddrUpdate(UpdateReason, Option<(EndpointId, RelayUrl)>), + ScheduleDirectAddrUpdate(UpdateReason, Option<(RelayEndpointId, RelayUrl)>), RelayMapChange, #[cfg(test)] ForceNetworkChange(bool), @@ -2543,6 +2543,7 @@ mod tests { use data_encoding::HEXLOWER; use iroh_base::{EndpointAddr, EndpointId, PublicKey, TransportAddr}; + use iroh_relay::RelayEndpointId; use n0_future::{StreamExt, time}; use n0_snafu::{Result, ResultExt}; use n0_watcher::Watcher; @@ -2635,12 +2636,12 @@ mod tests { } } - fn tracked_endpoints(&self) -> Vec { + fn tracked_endpoints(&self) -> Vec { self.endpoint .magic_sock() .list_remote_infos() .into_iter() - .map(|ep| ep.endpoint_id) + .map(|ep| ep.endpoint_id.into()) .collect() } @@ -2672,7 +2673,7 @@ mod tests { } let addr = EndpointAddr { - id: me.public(), + id: me.public().into(), addrs: new_addrs.iter().copied().map(TransportAddr::Ip).collect(), }; m.endpoint.magic_sock().add_test_addr(addr); @@ -2772,7 +2773,7 @@ mod tests { loss: ExpectedLoss, ) -> Result { info!("connecting to {}", dest_id.fmt_short()); - let dest = EndpointAddr::new(dest_id); + let dest = EndpointAddr::new(dest_id.into()); let conn = ep.endpoint.connect(dest, ALPN).await?; info!("opening bi"); @@ -2827,8 +2828,8 @@ mod tests { payload: &[u8], loss: ExpectedLoss, ) { - let send_endpoint_id = sender.endpoint.id(); - let recv_endpoint_id = receiver.endpoint.id(); + let send_endpoint_id = sender.endpoint.id().to_ed25519().unwrap(); + let recv_endpoint_id = receiver.endpoint.id().to_ed25519().unwrap(); info!("\nroundtrip: {send_endpoint_id:#} -> {recv_endpoint_id:#}"); let receiver_task = tokio::spawn(echo_receiver(receiver, loss)); @@ -3125,7 +3126,7 @@ mod tests { ep: &quinn::Endpoint, ep_secret_key: SecretKey, addr: EndpointIdMappedAddr, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, ) -> Result { // Endpoint::connect sets this, do the same to have similar behaviour. let mut transport_config = quinn::TransportConfig::default(); @@ -3151,7 +3152,7 @@ mod tests { ep: &quinn::Endpoint, ep_secret_key: SecretKey, mapped_addr: EndpointIdMappedAddr, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, transport_config: Arc, ) -> Result { let alpns = vec![ALPN.to_vec()]; @@ -3181,7 +3182,7 @@ mod tests { let secret_key_2 = SecretKey::from_bytes(&[2u8; 32]); let endpoint_id_2 = secret_key_2.public(); let secret_key_missing_endpoint = SecretKey::from_bytes(&[255u8; 32]); - let endpoint_id_missing_endpoint = secret_key_missing_endpoint.public(); + let endpoint_id_missing_endpoint = secret_key_missing_endpoint.public().into(); let msock_1 = magicsock_ep(secret_key_1.clone()).await.unwrap(); @@ -3239,7 +3240,7 @@ mod tests { .map(|x| TransportAddr::Ip(x.addr)) .collect(); let endpoint_addr_2 = EndpointAddr { - id: endpoint_id_2, + id: endpoint_id_2.into(), addrs, }; msock_1 @@ -3310,7 +3311,7 @@ mod tests { // Add an empty entry in the EndpointMap of ep_1 msock_1.endpoint_map.add_endpoint_addr( EndpointAddr { - id: endpoint_id_2, + id: endpoint_id_2.into(), addrs: Default::default(), }, Source::NamedApp { @@ -3353,7 +3354,7 @@ mod tests { .collect(); msock_1.endpoint_map.add_endpoint_addr( EndpointAddr { - id: endpoint_id_2, + id: endpoint_id_2.into(), addrs, }, Source::NamedApp { @@ -3396,7 +3397,7 @@ mod tests { assert_eq!(stack.endpoint.magic_sock().endpoint_map.endpoint_count(), 0); // Empty - let empty_addr = EndpointAddr::new(SecretKey::generate(&mut rng).public()); + let empty_addr = EndpointAddr::new(SecretKey::generate(&mut rng).public().into()); let err = stack .endpoint @@ -3411,7 +3412,7 @@ mod tests { // relay url only let addr = EndpointAddr { - id: SecretKey::generate(&mut rng).public(), + id: SecretKey::generate(&mut rng).public().into(), addrs: [TransportAddr::Relay("http://my-relay.com".parse().unwrap())] .into_iter() .collect(), @@ -3424,7 +3425,7 @@ mod tests { // addrs only let addr = EndpointAddr { - id: SecretKey::generate(&mut rng).public(), + id: SecretKey::generate(&mut rng).public().into(), addrs: [TransportAddr::Ip("127.0.0.1:1234".parse().unwrap())] .into_iter() .collect(), @@ -3437,7 +3438,7 @@ mod tests { // both let addr = EndpointAddr { - id: SecretKey::generate(&mut rng).public(), + id: SecretKey::generate(&mut rng).public().into(), addrs: [ TransportAddr::Relay("http://my-relay.com".parse().unwrap()), TransportAddr::Ip("127.0.0.1:1234".parse().unwrap()), diff --git a/iroh/src/magicsock/endpoint_map.rs b/iroh/src/magicsock/endpoint_map.rs index e23da332321..dd012df5f5a 100644 --- a/iroh/src/magicsock/endpoint_map.rs +++ b/iroh/src/magicsock/endpoint_map.rs @@ -6,7 +6,8 @@ use std::{ time::Duration, }; -use iroh_base::{EndpointAddr, EndpointId, PublicKey, RelayUrl}; +use iroh_base::{EndpointAddr, PublicKey, RelayUrl}; +use iroh_relay::RelayEndpointId; use n0_future::time::Instant; use serde::{Deserialize, Serialize}; use tracing::{debug, info, instrument, trace, warn}; @@ -53,7 +54,7 @@ pub(super) struct EndpointMap { #[derive(Default, Debug)] pub(super) struct EndpointMapInner { - by_endpoint_key: HashMap, + by_endpoint_key: HashMap, by_ip_port: HashMap, by_quic_mapped_addr: HashMap, by_id: HashMap, @@ -69,7 +70,7 @@ pub(super) struct EndpointMapInner { #[derive(Debug, Clone)] enum EndpointStateKey { Idx(usize), - EndpointId(EndpointId), + EndpointId(RelayEndpointId), EndpointIdMappedAddr(EndpointIdMappedAddr), IpPort(IpPort), } @@ -171,7 +172,7 @@ impl EndpointMap { pub(super) fn receive_relay( &self, relay_url: &RelayUrl, - src: EndpointId, + src: RelayEndpointId, ) -> EndpointIdMappedAddr { self.inner .lock() @@ -210,7 +211,7 @@ impl EndpointMap { pub(super) fn get_quic_mapped_addr_for_endpoint_key( &self, - endpoint_key: EndpointId, + endpoint_key: RelayEndpointId, ) -> Option { self.inner .lock() @@ -317,17 +318,17 @@ impl EndpointMap { /// the `endpoint_id` pub(super) fn conn_type( &self, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, ) -> Option> { self.inner.lock().expect("poisoned").conn_type(endpoint_id) } - pub(super) fn latency(&self, endpoint_id: EndpointId) -> Option { + pub(super) fn latency(&self, endpoint_id: RelayEndpointId) -> Option { self.inner.lock().expect("poisoned").latency(endpoint_id) } /// Get the [`RemoteInfo`]s for the endpoint identified by [`EndpointId`]. - pub(super) fn remote_info(&self, endpoint_id: EndpointId) -> Option { + pub(super) fn remote_info(&self, endpoint_id: RelayEndpointId) -> Option { self.inner .lock() .expect("poisoned") @@ -376,7 +377,9 @@ impl EndpointMapInner { metrics: &Metrics, ) { let source0 = source.clone(); - let endpoint_id = endpoint_addr.id; + let Some(endpoint_id) = endpoint_addr.id.to_ed25519() else { + panic!(); + }; let relay_url = endpoint_addr.relay_urls().next().cloned(); #[cfg(any(test, feature = "test-utils"))] let path_selection = self.path_selection; @@ -471,7 +474,7 @@ impl EndpointMapInner { /// Marks the endpoint we believe to be at `ipp` as recently used. #[cfg(not(wasm_browser))] - fn receive_udp(&mut self, udp_addr: SocketAddr) -> Option<(EndpointId, EndpointIdMappedAddr)> { + fn receive_udp(&mut self, udp_addr: SocketAddr) -> Option<(RelayEndpointId, EndpointIdMappedAddr)> { let ip_port: IpPort = udp_addr.into(); let Some(endpoint_state) = self.get_mut(EndpointStateKey::IpPort(ip_port)) else { trace!(src=%udp_addr, "receive_udp: no endpoint_state found for addr, ignore"); @@ -485,7 +488,7 @@ impl EndpointMapInner { } #[instrument(skip_all, fields(src = %src.fmt_short()))] - fn receive_relay(&mut self, relay_url: &RelayUrl, src: EndpointId) -> EndpointIdMappedAddr { + fn receive_relay(&mut self, relay_url: &RelayUrl, src: RelayEndpointId) -> EndpointIdMappedAddr { #[cfg(any(test, feature = "test-utils"))] let path_selection = self.path_selection; let endpoint_state = self.get_or_insert_with(EndpointStateKey::EndpointId(src), || { @@ -519,7 +522,7 @@ impl EndpointMapInner { } /// Get the [`RemoteInfo`]s for each endpoint. - fn remote_info(&self, endpoint_id: EndpointId) -> Option { + fn remote_info(&self, endpoint_id: RelayEndpointId) -> Option { self.get(EndpointStateKey::EndpointId(endpoint_id)) .map(|ep| ep.info(Instant::now())) } @@ -533,19 +536,19 @@ impl EndpointMapInner { /// /// Will return `None` if there is not an entry in the [`EndpointMap`] for /// the `public_key` - fn conn_type(&self, endpoint_id: EndpointId) -> Option> { + fn conn_type(&self, endpoint_id: RelayEndpointId) -> Option> { self.get(EndpointStateKey::EndpointId(endpoint_id)) .map(|ep| ep.conn_type()) } - fn latency(&self, endpoint_id: EndpointId) -> Option { + fn latency(&self, endpoint_id: RelayEndpointId) -> Option { self.get(EndpointStateKey::EndpointId(endpoint_id)) .and_then(|ep| ep.latency()) } fn handle_pong( &mut self, - sender: EndpointId, + sender: RelayEndpointId, src: &transports::Addr, pong: Pong, metrics: &Metrics, @@ -564,7 +567,7 @@ impl EndpointMapInner { #[must_use = "actions must be handled"] fn handle_call_me_maybe( &mut self, - sender: EndpointId, + sender: RelayEndpointId, cm: CallMeMaybe, metrics: &Metrics, ) -> Vec { @@ -591,7 +594,7 @@ impl EndpointMapInner { fn handle_ping( &mut self, - sender: EndpointId, + sender: RelayEndpointId, src: SendAddr, tx_id: TransactionId, ) -> PingHandled { @@ -639,7 +642,7 @@ impl EndpointMapInner { self.by_quic_mapped_addr .insert(*endpoint_state.quic_mapped_addr(), id); self.by_endpoint_key - .insert(*endpoint_state.public_key(), id); + .insert((*endpoint_state.public_key()).into(), id); self.by_id.insert(id, endpoint_state); self.by_id.get_mut(&id).expect("just inserted") @@ -796,10 +799,10 @@ mod tests { let ip_addresses_c = [TransportAddr::Ip(addr(5000))]; let addrs_a = std::iter::once(TransportAddr::Relay(relay_x)).chain(ip_addresses_a); - let endpoint_addr_a = EndpointAddr::new(endpoint_a).with_addrs(addrs_a); - let endpoint_addr_b = EndpointAddr::new(endpoint_b).with_relay_url(relay_y); - let endpoint_addr_c = EndpointAddr::new(endpoint_c).with_addrs(ip_addresses_c); - let endpoint_addr_d = EndpointAddr::new(endpoint_d); + let endpoint_addr_a = EndpointAddr::new(endpoint_a.into()).with_addrs(addrs_a); + let endpoint_addr_b = EndpointAddr::new(endpoint_b.into()).with_relay_url(relay_y); + let endpoint_addr_c = EndpointAddr::new(endpoint_c.into()).with_addrs(ip_addresses_c); + let endpoint_addr_d = EndpointAddr::new(endpoint_d.into()); endpoint_map.add_test_addr(endpoint_addr_a); endpoint_map.add_test_addr(endpoint_addr_b); @@ -876,7 +879,7 @@ mod tests { info!("Adding active addresses"); for i in 0..MAX_INACTIVE_DIRECT_ADDRESSES { let addr = SocketAddr::new(LOCALHOST, 5000 + i as u16); - let endpoint_addr = EndpointAddr::new(public_key).with_ip_addr(addr); + let endpoint_addr = EndpointAddr::new(public_key.into()).with_ip_addr(addr); // add address endpoint_map.add_test_addr(endpoint_addr); // make it active @@ -886,7 +889,7 @@ mod tests { info!("Adding offline/inactive addresses"); for i in 0..MAX_INACTIVE_DIRECT_ADDRESSES * 2 { let addr = SocketAddr::new(LOCALHOST, 6000 + i as u16); - let endpoint_addr = EndpointAddr::new(public_key).with_ip_addr(addr); + let endpoint_addr = EndpointAddr::new(public_key.into()).with_ip_addr(addr); endpoint_map.add_test_addr(endpoint_addr); } @@ -930,7 +933,7 @@ mod tests { // add one active endpoint and more than MAX_INACTIVE_ENDPOINTS inactive endpoints let active_endpoint = SecretKey::generate(&mut rng).public(); let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 167); - endpoint_map.add_test_addr(EndpointAddr::new(active_endpoint).with_ip_addr(addr)); + endpoint_map.add_test_addr(EndpointAddr::new(active_endpoint.into()).with_ip_addr(addr)); endpoint_map .inner .lock() @@ -939,7 +942,7 @@ mod tests { .expect("registered"); for _ in 0..MAX_INACTIVE_ENDPOINTS + 1 { - let endpoint = SecretKey::generate(&mut rng).public(); + let endpoint = SecretKey::generate(&mut rng).public().into(); endpoint_map.add_test_addr(EndpointAddr::new(endpoint)); } diff --git a/iroh/src/magicsock/endpoint_map/endpoint_state.rs b/iroh/src/magicsock/endpoint_map/endpoint_state.rs index e4b1c2a2209..70edb3e78d2 100644 --- a/iroh/src/magicsock/endpoint_map/endpoint_state.rs +++ b/iroh/src/magicsock/endpoint_map/endpoint_state.rs @@ -6,7 +6,8 @@ use std::{ }; use data_encoding::HEXLOWER; -use iroh_base::{EndpointAddr, EndpointId, PublicKey, RelayUrl, TransportAddr}; +use iroh_base::{EndpointAddr, PublicKey, RelayUrl, TransportAddr}; +use iroh_relay::RelayEndpointId; use n0_future::{ task::{self, AbortOnDropHandle}, time::{self, Duration, Instant}, @@ -59,7 +60,7 @@ const STAYIN_ALIVE_MIN_ELAPSED: Duration = Duration::from_secs(2); pub(in crate::magicsock) enum PingAction { SendCallMeMaybe { relay_url: RelayUrl, - dst_endpoint: EndpointId, + dst_endpoint: RelayEndpointId, }, SendPing(SendPing), } @@ -68,7 +69,7 @@ pub(in crate::magicsock) enum PingAction { pub(in crate::magicsock) struct SendPing { pub id: usize, pub dst: SendAddr, - pub dst_endpoint: EndpointId, + pub dst_endpoint: RelayEndpointId, pub tx_id: TransactionId, pub purpose: DiscoPingPurpose, } @@ -108,7 +109,7 @@ pub(super) struct EndpointState { /// The UDP address used on the QUIC-layer to address this endpoint. quic_mapped_addr: EndpointIdMappedAddr, /// The global identifier for this endpoint. - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, /// The last time we pinged all endpoints. last_full_ping: Option, /// The url of relay endpoint that we can relay over to communicate. @@ -148,7 +149,7 @@ pub(super) struct EndpointState { /// Options for creating a new [`EndpointState`]. #[derive(Debug)] pub(super) struct Options { - pub(super) endpoint_id: EndpointId, + pub(super) endpoint_id: RelayEndpointId, pub(super) relay_url: Option, /// Is this endpoint currently active (sending data)? pub(super) active: bool, @@ -1082,7 +1083,7 @@ impl EndpointState { self.last_used = Some(now); } - pub(super) fn receive_relay(&mut self, url: &RelayUrl, src: EndpointId, now: Instant) { + pub(super) fn receive_relay(&mut self, url: &RelayUrl, src: RelayEndpointId, now: Instant) { match self.relay_url.as_mut() { Some((current_home, state)) if current_home == url => { // We received on the expected url. update state. @@ -1233,7 +1234,7 @@ impl From for EndpointAddr { } EndpointAddr { - id: info.endpoint_id, + id: info.endpoint_id.into(), addrs, } } @@ -1384,7 +1385,7 @@ impl From for RelayUrl { #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub(crate) struct RemoteInfo { /// The globally unique identifier for this endpoint. - pub endpoint_id: EndpointId, + pub endpoint_id: RelayEndpointId, /// Relay server information, if available. pub relay_url: Option, /// The addresses at which this endpoint might be reachable. @@ -1448,7 +1449,7 @@ pub enum ConnectionType { mod tests { use std::{collections::BTreeMap, net::Ipv4Addr}; - use iroh_base::SecretKey; + use iroh_base::{EndpointId, SecretKey}; use rand::SeedableRng; use super::*; @@ -1463,7 +1464,7 @@ mod tests { let pong_src = SendAddr::Udp("0.0.0.0:1".parse().unwrap()); let latency = Duration::from_millis(50); - let relay_and_state = |endpoint_id: EndpointId, url: RelayUrl| { + let relay_and_state = |endpoint_id: RelayEndpointId, url: RelayUrl| { let relay_state = PathState::with_pong_reply( endpoint_id, PongReply { @@ -1615,7 +1616,7 @@ mod tests { let mut expect = Vec::from([ RemoteInfo { - endpoint_id: a_endpoint.endpoint_id, + endpoint_id: a_endpoint.endpoint_id.into(), relay_url: None, addrs: Vec::from([DirectAddrInfo { addr: a_socket_addr, @@ -1630,7 +1631,7 @@ mod tests { last_used: Some(elapsed), }, RemoteInfo { - endpoint_id: b_endpoint.endpoint_id, + endpoint_id: b_endpoint.endpoint_id.into(), relay_url: Some(RelayUrlInfo { relay_url: b_endpoint.relay_url.as_ref().unwrap().0.clone(), last_alive: None, @@ -1642,7 +1643,7 @@ mod tests { last_used: Some(elapsed), }, RemoteInfo { - endpoint_id: c_endpoint.endpoint_id, + endpoint_id: c_endpoint.endpoint_id.into(), relay_url: Some(RelayUrlInfo { relay_url: c_endpoint.relay_url.as_ref().unwrap().0.clone(), last_alive: None, @@ -1654,7 +1655,7 @@ mod tests { last_used: Some(elapsed), }, RemoteInfo { - endpoint_id: d_endpoint.endpoint_id, + endpoint_id: d_endpoint.endpoint_id.into(), relay_url: Some(RelayUrlInfo { relay_url: d_endpoint.relay_url.as_ref().unwrap().0.clone(), last_alive: None, diff --git a/iroh/src/magicsock/endpoint_map/path_state.rs b/iroh/src/magicsock/endpoint_map/path_state.rs index d78b67179f3..d737b78de69 100644 --- a/iroh/src/magicsock/endpoint_map/path_state.rs +++ b/iroh/src/magicsock/endpoint_map/path_state.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap}; -use iroh_base::EndpointId; +use iroh_relay::RelayEndpointId; use n0_future::time::{Duration, Instant}; use tracing::{Level, debug, event}; @@ -32,7 +32,7 @@ const DISCO_PING_INTERVAL: Duration = Duration::from_secs(5); #[derive(Debug, Clone)] pub(super) struct PathState { /// The endpoint for which this path exists. - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, /// The path this applies for. path: SendAddr, /// The last (outgoing) ping time. @@ -66,7 +66,7 @@ pub(super) struct PathState { impl PathState { pub(super) fn new( - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, path: SendAddr, source: Source, now: Instant, @@ -86,7 +86,7 @@ impl PathState { } pub(super) fn with_last_payload( - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, path: SendAddr, source: Source, now: Instant, @@ -106,7 +106,7 @@ impl PathState { } pub(super) fn with_ping( - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, path: SendAddr, tx_id: TransactionId, source: Source, @@ -142,7 +142,7 @@ impl PathState { } #[cfg(test)] - pub(super) fn with_pong_reply(endpoint_id: EndpointId, r: PongReply) -> Self { + pub(super) fn with_pong_reply(endpoint_id: RelayEndpointId, r: PongReply) -> Self { PathState { endpoint_id, path: r.from.clone(), diff --git a/iroh/src/magicsock/transports.rs b/iroh/src/magicsock/transports.rs index e6de8d002f9..bbefc6e978b 100644 --- a/iroh/src/magicsock/transports.rs +++ b/iroh/src/magicsock/transports.rs @@ -7,6 +7,7 @@ use std::{ }; use iroh_base::{EndpointId, RelayUrl}; +use iroh_relay::RelayEndpointId; use n0_watcher::Watcher; use relay::{RelayNetworkChangeSender, RelaySender}; use smallvec::SmallVec; @@ -40,8 +41,8 @@ pub(crate) type LocalAddrsWatch = n0_watcher::Map< ( n0_watcher::Join>, n0_watcher::Join< - Option<(RelayUrl, EndpointId)>, - n0_watcher::Map>, Option<(RelayUrl, EndpointId)>>, + Option<(RelayUrl, RelayEndpointId)>, + n0_watcher::Map>, Option<(RelayUrl, RelayEndpointId)>>, >, ), Vec, @@ -304,7 +305,7 @@ pub(crate) struct Transmit<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum Addr { Ip(SocketAddr), - Relay(RelayUrl, EndpointId), + Relay(RelayUrl, RelayEndpointId), } impl Default for Addr { @@ -326,7 +327,7 @@ impl From for Addr { impl From<(RelayUrl, EndpointId)> for Addr { fn from(value: (RelayUrl, EndpointId)) -> Self { - Self::Relay(value.0, value.1) + Self::Relay(value.0, value.1.to_ed25519().unwrap()) } } diff --git a/iroh/src/magicsock/transports/relay.rs b/iroh/src/magicsock/transports/relay.rs index 489a22835a0..9d32bb0a825 100644 --- a/iroh/src/magicsock/transports/relay.rs +++ b/iroh/src/magicsock/transports/relay.rs @@ -5,8 +5,8 @@ use std::{ }; use bytes::Bytes; -use iroh_base::{EndpointId, RelayUrl}; -use iroh_relay::protos::relay::Datagrams; +use iroh_base::RelayUrl; +use iroh_relay::{RelayEndpointId, protos::relay::Datagrams}; use n0_future::{ ready, task::{self, AbortOnDropHandle}, @@ -34,7 +34,7 @@ pub(crate) struct RelayTransport { actor_sender: mpsc::Sender, _actor_handle: AbortOnDropHandle<()>, my_relay: Watchable>, - my_endpoint_id: EndpointId, + my_endpoint_id: RelayEndpointId, } impl RelayTransport { @@ -149,7 +149,7 @@ impl RelayTransport { meta_out.ecn = None; meta_out.dst_ip = None; // TODO: insert the relay url for this relay - *addr = (dm.url, dm.src).into(); + *addr = (dm.url, dm.src.into()).into(); num_msgs += 1; } @@ -164,7 +164,7 @@ impl RelayTransport { pub(super) fn local_addr_watch( &self, - ) -> n0_watcher::Map>, Option<(RelayUrl, EndpointId)>> { + ) -> n0_watcher::Map>, Option<(RelayUrl, RelayEndpointId)>> { let my_endpoint_id = self.my_endpoint_id; self.my_relay .watch() @@ -240,14 +240,14 @@ pub(crate) struct RelaySender { } impl RelaySender { - pub(super) fn is_valid_send_addr(&self, _url: &RelayUrl, _endpoint_id: &EndpointId) -> bool { + pub(super) fn is_valid_send_addr(&self, _url: &RelayUrl, _endpoint_id: &RelayEndpointId) -> bool { true } pub(super) async fn send( &self, dest_url: RelayUrl, - dest_endpoint: EndpointId, + dest_endpoint: RelayEndpointId, transmit: &Transmit<'_>, ) -> io::Result<()> { let contents = datagrams_from_transmit(transmit); @@ -284,7 +284,7 @@ impl RelaySender { &mut self, cx: &mut Context, dest_url: RelayUrl, - dest_endpoint: EndpointId, + dest_endpoint: RelayEndpointId, transmit: &Transmit<'_>, ) -> Poll> { match ready!(self.sender.poll_reserve(cx)) { @@ -327,7 +327,7 @@ impl RelaySender { pub(super) fn try_send( &self, dest_url: RelayUrl, - dest_endpoint: EndpointId, + dest_endpoint: RelayEndpointId, transmit: &Transmit<'_>, ) -> io::Result<()> { let contents = datagrams_from_transmit(transmit); @@ -388,7 +388,7 @@ fn datagrams_from_transmit(transmit: &Transmit<'_>) -> Datagrams { mod tests { use std::{collections::BTreeSet, time::Duration}; - use iroh_base::EndpointId; + use iroh_base::{EndpointId, PublicKey}; use tokio::task::JoinSet; use tracing::debug; @@ -427,7 +427,7 @@ mod tests { sender .try_send(RelayRecvDatagram { url, - src: EndpointId::from_bytes(&[0u8; 32]).unwrap(), + src: PublicKey::from_bytes(&[0u8; 32]).unwrap().into(), datagrams: Datagrams::from(&i.to_le_bytes()), }) .unwrap(); diff --git a/iroh/src/magicsock/transports/relay/actor.rs b/iroh/src/magicsock/transports/relay/actor.rs index 8ad69779c9a..0815b986ef4 100644 --- a/iroh/src/magicsock/transports/relay/actor.rs +++ b/iroh/src/magicsock/transports/relay/actor.rs @@ -38,11 +38,9 @@ use std::{ }; use backon::{Backoff, BackoffBuilder, ExponentialBuilder}; -use iroh_base::{EndpointId, RelayUrl, SecretKey}; +use iroh_base::{RelayUrl, SecretKey}; use iroh_relay::{ - self as relay, PingTracker, - client::{Client, ConnectError, RecvError, SendError}, - protos::relay::{ClientToRelayMsg, Datagrams, RelayToClientMsg}, + self as relay, client::{Client, ConnectError, RecvError, SendError}, protos::relay::{ClientToRelayMsg, Datagrams, RelayToClientMsg}, PingTracker, RelayEndpointId }; use n0_future::{ FuturesUnorderedBounded, SinkExt, StreamExt, @@ -181,7 +179,7 @@ enum ActiveRelayMessage { #[derive(Debug)] enum ActiveRelayPrioMessage { /// Returns whether or not this relay can reach the EndpointId. - HasEndpointRoute(EndpointId, oneshot::Sender), + HasEndpointRoute(RelayEndpointId, oneshot::Sender), } /// Configuration needed to start an [`ActiveRelayActor`]. @@ -795,12 +793,12 @@ struct ConnectedRelayState { /// Tracks pings we have sent, awaits pong replies. ping_tracker: PingTracker, /// Endpoints which are reachable via this relay server. - endpoints_present: BTreeSet, + endpoints_present: BTreeSet, /// The [`EndpointId`] from whom we received the last packet. /// /// This is to avoid a slower lookup in the [`ConnectedRelayState::endpoints_present`] map /// when we are only communicating to a single remote endpoint. - last_packet_src: Option, + last_packet_src: Option, /// A pong we need to send ASAP. pong_pending: Option<[u8; 8]>, /// Whether the connection is to be considered established. @@ -829,7 +827,7 @@ pub(super) enum RelayActorMessage { #[derive(Debug, Clone)] pub(crate) struct RelaySendItem { /// The destination for the datagrams. - pub(crate) remote_endpoint: EndpointId, + pub(crate) remote_endpoint: RelayEndpointId, /// The home relay of the remote endpoint. pub(crate) url: RelayUrl, /// One or more datagrams to send. @@ -1033,7 +1031,7 @@ impl RelayActor { async fn active_relay_handle_for_endpoint( &mut self, url: &RelayUrl, - remote_endpoint: &EndpointId, + remote_endpoint: &RelayEndpointId, ) -> ActiveRelayHandle { if let Some(handle) = self.active_relays.get(url) { return handle.clone(); @@ -1225,7 +1223,7 @@ struct ActiveRelayHandle { #[derive(Debug)] pub(crate) struct RelayRecvDatagram { pub(crate) url: RelayUrl, - pub(crate) src: EndpointId, + pub(crate) src: RelayEndpointId, pub(crate) datagrams: Datagrams, } @@ -1237,7 +1235,7 @@ mod tests { }; use iroh_base::{EndpointId, RelayUrl, SecretKey}; - use iroh_relay::{PingTracker, protos::relay::Datagrams}; + use iroh_relay::{protos::relay::Datagrams, PingTracker, RelayEndpointId}; use n0_snafu::{Error, Result, ResultExt}; use tokio::sync::{mpsc, oneshot}; use tokio_util::{sync::CancellationToken, task::AbortOnDropHandle}; @@ -1288,7 +1286,7 @@ mod tests { /// This actor will connect to the relay server, pretending to be an iroh endpoint, and echo /// back any datagram it receives from the relay. This is used by the /// [`ActiveRelayActor`] under test to check connectivity works. - fn start_echo_endpoint(relay_url: RelayUrl) -> (EndpointId, AbortOnDropHandle<()>) { + fn start_echo_endpoint(relay_url: RelayUrl) -> (RelayEndpointId, AbortOnDropHandle<()>) { let secret_key = SecretKey::from_bytes(&[8u8; 32]); let (recv_datagram_tx, mut recv_datagram_rx) = mpsc::channel(16); let (send_datagram_tx, send_datagram_rx) = mpsc::channel(16); diff --git a/iroh/src/test_utils.rs b/iroh/src/test_utils.rs index 3900703d920..03789e8d242 100644 --- a/iroh/src/test_utils.rs +++ b/iroh/src/test_utils.rs @@ -84,6 +84,7 @@ pub(crate) mod dns_and_pkarr_servers { use std::{net::SocketAddr, time::Duration}; use iroh_base::{EndpointId, SecretKey}; + use iroh_relay::RelayEndpointId; use url::Url; use super::CleanupDropGuard; @@ -158,7 +159,7 @@ pub(crate) mod dns_and_pkarr_servers { /// If `timeout` elapses an error is returned. pub async fn on_endpoint( &self, - endpoint_id: &EndpointId, + endpoint_id: &RelayEndpointId, timeout: Duration, ) -> std::io::Result<()> { self.state.on_endpoint(endpoint_id, timeout).await @@ -346,8 +347,8 @@ pub(crate) mod pkarr_dns_state { time::Duration, }; - use iroh_base::EndpointId; - use iroh_relay::endpoint_info::{EndpointIdExt, EndpointInfo, IROH_TXT_NAME}; + use iroh_base::{EndpointId, PublicKey}; + use iroh_relay::{endpoint_info::{EndpointIdExt, EndpointInfo, IROH_TXT_NAME}, RelayEndpointId}; use pkarr::SignedPacket; use tracing::debug; @@ -355,7 +356,7 @@ pub(crate) mod pkarr_dns_state { #[derive(Debug, Clone)] pub struct State { - packets: Arc>>, + packets: Arc>>, origin: String, notify: Arc, } @@ -375,7 +376,7 @@ pub(crate) mod pkarr_dns_state { pub async fn on_endpoint( &self, - endpoint: &EndpointId, + endpoint: &RelayEndpointId, timeout: Duration, ) -> std::io::Result<()> { let timeout = tokio::time::sleep(timeout); @@ -396,8 +397,8 @@ pub(crate) mod pkarr_dns_state { } pub fn upsert(&self, signed_packet: SignedPacket) -> std::io::Result { - let endpoint_id = EndpointId::from_bytes(&signed_packet.public_key().to_bytes()) - .map_err(std::io::Error::other)?; + let endpoint_id = PublicKey::from_bytes(&signed_packet.public_key().to_bytes()) + .map_err(std::io::Error::other)?.into(); let mut map = self.packets.lock().expect("poisoned"); let updated = match map.entry(endpoint_id) { hash_map::Entry::Vacant(e) => { @@ -420,7 +421,7 @@ pub(crate) mod pkarr_dns_state { } /// Returns a mutex guard, do not hold over await points - pub fn get(&self, endpoint_id: &EndpointId, cb: F) -> T + pub fn get(&self, endpoint_id: &RelayEndpointId, cb: F) -> T where F: FnOnce(Option<&mut SignedPacket>) -> T, { @@ -441,7 +442,7 @@ pub(crate) mod pkarr_dns_state { continue; }; - self.get(&endpoint_id, |packet| { + self.get(&endpoint_id.into(), |packet| { if let Some(packet) = packet { let endpoint_info = EndpointInfo::from_pkarr_signed_packet(packet) .map_err(std::io::Error::other)?; @@ -477,14 +478,14 @@ pub(crate) mod pkarr_dns_state { /// subsequent labels. /// /// Returns a [`EndpointId`] if parsed successfully, otherwise `None`. - fn endpoint_id_from_domain_name(name: &str) -> Option { + fn endpoint_id_from_domain_name(name: &str) -> Option { let mut labels = name.split("."); let label = labels.next()?; if label != IROH_TXT_NAME { return None; } let label = labels.next()?; - let endpoint_id = EndpointId::from_z32(label).ok()?; + let endpoint_id = PublicKey::from_z32(label).ok()?; Some(endpoint_id) } @@ -495,14 +496,14 @@ pub(crate) mod pkarr_dns_state { ttl: u32, ) -> impl Iterator + 'static { let txt_strings = endpoint_info.to_txt_strings(); - let records = to_hickory_records(txt_strings, endpoint_info.endpoint_id, origin, ttl); + let records = to_hickory_records(txt_strings, endpoint_info.endpoint_id.to_ed25519().unwrap(), origin, ttl); records.collect::>().into_iter() } /// Converts to a list of [`hickory_resolver::proto::rr::Record`] resource records. fn to_hickory_records( txt_strings: Vec, - endpoint_id: EndpointId, + endpoint_id: RelayEndpointId, origin: &str, ttl: u32, ) -> impl Iterator + '_ { @@ -524,7 +525,7 @@ pub(crate) mod pkarr_dns_state { #[test] fn test_endpoint_id_from_domain_name() -> Result { let name = "_iroh.dgjpkxyn3zyrk3zfads5duwdgbqpkwbjxfj4yt7rezidr3fijccy.dns.iroh.link."; - let endpoint_id = super::endpoint_id_from_domain_name(name); + let endpoint_id = super::endpoint_id_from_domain_name(name).map(EndpointId::from); let expected: EndpointId = "1992d53c02cdc04566e5c0edb1ce83305cd550297953a047a445ea3264b54b18".parse()?; assert_eq!(endpoint_id, Some(expected)); diff --git a/iroh/src/tls/name.rs b/iroh/src/tls/name.rs index a9b64573639..3e03adf83cd 100644 --- a/iroh/src/tls/name.rs +++ b/iroh/src/tls/name.rs @@ -12,20 +12,20 @@ //! We *could* decide to remove that indicator in the future likely without breakage. use data_encoding::BASE32_DNSSEC; -use iroh_base::EndpointId; +use iroh_relay::RelayEndpointId; -pub(crate) fn encode(endpoint_id: EndpointId) -> String { +pub(crate) fn encode(endpoint_id: RelayEndpointId) -> String { format!( "{}.iroh.invalid", BASE32_DNSSEC.encode(endpoint_id.as_bytes()) ) } -pub(crate) fn decode(name: &str) -> Option { +pub(crate) fn decode(name: &str) -> Option { let [base32_endpoint_id, "iroh", "invalid"] = name.split(".").collect::>()[..] else { return None; }; - EndpointId::from_bytes( + RelayEndpointId::from_bytes( &BASE32_DNSSEC .decode(base32_endpoint_id.as_bytes()) .ok()?