node: Add support for `.onion` addresses in wire

Adds support for encoding and decoding onion addresses in the gossip
protocol.
This commit is contained in:
cloudhead 2024-04-22 12:16:17 +02:00
parent ae709b00ed
commit 7a1ba7d4b1
No known key found for this signature in database
3 changed files with 37 additions and 5 deletions

View File

@ -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<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
self.into_raw_bytes().encode(writer)
}
}
impl Encode for Alias {
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
self.as_ref().encode(writer)
@ -509,6 +518,15 @@ impl Decode for node::Features {
}
}
impl Decode for tor::OnionAddrV3 {
fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
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::*;

View File

@ -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)),
};

View File

@ -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 {