From 7a1ba7d4b109c4bd45cac9c93755c6fa55823e3f Mon Sep 17 00:00:00 2001 From: cloudhead Date: Mon, 22 Apr 2024 12:16:17 +0200 Subject: [PATCH] node: Add support for `.onion` addresses in wire Adds support for encoding and decoding onion addresses in the gossip protocol. --- radicle-node/src/wire.rs | 18 ++++++++++++++++++ radicle-node/src/wire/message.rs | 12 +++++++++--- radicle/src/test/arbitrary.rs | 12 ++++++++++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/radicle-node/src/wire.rs b/radicle-node/src/wire.rs index de0d7512..fab8c2c3 100644 --- a/radicle-node/src/wire.rs +++ b/radicle-node/src/wire.rs @@ -15,6 +15,7 @@ use std::string::FromUtf8Error; use std::{io, mem}; use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt}; +use cyphernet::addr::tor; use crate::crypto::{PublicKey, Signature, Unverified}; use crate::git; @@ -56,6 +57,8 @@ pub enum Error { InvalidControlMessage(u8), #[error("invalid protocol version header `{0:x?}`")] InvalidProtocolVersion([u8; 4]), + #[error("invalid onion address: {0}")] + InvalidOnionAddr(#[from] tor::OnionAddrDecodeError), #[error("unknown address type `{0}`")] UnknownAddressType(u8), #[error("unknown message type `{0}`")] @@ -237,6 +240,12 @@ impl Encode for Refs { } } +impl Encode for cyphernet::addr::tor::OnionAddrV3 { + fn encode(&self, writer: &mut W) -> Result { + self.into_raw_bytes().encode(writer) + } +} + impl Encode for Alias { fn encode(&self, writer: &mut W) -> Result { self.as_ref().encode(writer) @@ -509,6 +518,15 @@ impl Decode for node::Features { } } +impl Decode for tor::OnionAddrV3 { + fn decode(reader: &mut R) -> Result { + let bytes: [u8; tor::ONION_V3_RAW_LEN] = Decode::decode(reader)?; + let addr = tor::OnionAddrV3::from_raw_bytes(bytes)?; + + Ok(addr) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/radicle-node/src/wire/message.rs b/radicle-node/src/wire/message.rs index 3ed6fcf5..2fdf84d1 100644 --- a/radicle-node/src/wire/message.rs +++ b/radicle-node/src/wire/message.rs @@ -1,7 +1,7 @@ use std::{io, mem, net}; use byteorder::{NetworkEndian, ReadBytesExt}; -use cyphernet::addr::{Addr, HostName, NetAddr}; +use cyphernet::addr::{tor, Addr, HostName, NetAddr}; use radicle::git::Oid; use radicle::node::Address; @@ -386,8 +386,12 @@ impl wire::Encode for Address { n += u8::from(AddressType::Dns).encode(writer)?; n += dns.encode(writer)?; } + HostName::Tor(addr) => { + n += u8::from(AddressType::Onion).encode(writer)?; + n += addr.encode(writer)?; + } _ => { - todo!(); + return Err(io::ErrorKind::Unsupported.into()); } } n += self.port().encode(writer)?; @@ -418,7 +422,9 @@ impl wire::Decode for Address { HostName::Dns(dns) } Ok(AddressType::Onion) => { - todo!(); + let onion: tor::OnionAddrV3 = wire::Decode::decode(reader)?; + + HostName::Tor(onion) } Err(other) => return Err(wire::Error::UnknownAddressType(other)), }; diff --git a/radicle/src/test/arbitrary.rs b/radicle/src/test/arbitrary.rs index 6bad684f..03a6c0f4 100644 --- a/radicle/src/test/arbitrary.rs +++ b/radicle/src/test/arbitrary.rs @@ -6,6 +6,8 @@ use std::{iter, net}; use crypto::test::signer::MockSigner; use crypto::{PublicKey, Unverified, Verified}; +use cyphernet::addr::tor::OnionAddrV3; +use cyphernet::EcPk; use nonempty::NonEmpty; use qcheck::Arbitrary; @@ -260,7 +262,7 @@ impl Arbitrary for RepoId { impl Arbitrary for AddressType { fn arbitrary(g: &mut qcheck::Gen) -> Self { - let t = *g.choose(&[1, 2, 3]).unwrap() as u8; + let t = *g.choose(&[1, 2, 3, 4]).unwrap() as u8; AddressType::try_from(t).unwrap() } @@ -285,7 +287,13 @@ impl Arbitrary for Address { .unwrap() .to_string(), ), - AddressType::Onion => todo!(), + AddressType::Onion => { + let pk = PublicKey::arbitrary(g); + let addr = OnionAddrV3::from( + cyphernet::ed25519::PublicKey::from_pk_compressed(**pk).unwrap(), + ); + cyphernet::addr::HostName::Tor(addr) + } }; Address::from(cyphernet::addr::NetAddr {