mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-29 09:41:34 +00:00
multiaddr: add support for onion protocol. (#542)
* multiaddr: add support for onion protocol. * Comment `read_onion`. * Split onion into address and port parts.
This commit is contained in:
committed by
Pierre Krieger
parent
d81f4e264f
commit
e05422c05f
@ -9,8 +9,10 @@ readme = "README.md"
|
||||
version = "0.3.0"
|
||||
|
||||
[dependencies]
|
||||
arrayref = "0.3"
|
||||
bs58 = "0.2.0"
|
||||
byteorder = "0.4"
|
||||
data-encoding = "2.1"
|
||||
multihash = { path = "../multihash" }
|
||||
serde = "1.0.70"
|
||||
unsigned-varint = "0.1"
|
||||
|
@ -3,8 +3,11 @@
|
||||
///! Implementation of [multiaddr](https://github.com/jbenet/multiaddr)
|
||||
///! in Rust.
|
||||
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
extern crate bs58;
|
||||
extern crate byteorder;
|
||||
extern crate data_encoding;
|
||||
extern crate serde;
|
||||
extern crate unsigned_varint;
|
||||
pub extern crate multihash;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use bs58;
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
|
||||
use data_encoding::BASE32;
|
||||
use multihash::Multihash;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@ -50,7 +51,7 @@ pub enum Protocol<'a> {
|
||||
P2pWebRtcStar,
|
||||
P2pWebSocketStar,
|
||||
Memory,
|
||||
Onion(Cow<'a, [u8]>),
|
||||
Onion(Cow<'a, [u8; 10]>, u16),
|
||||
P2p(Multihash),
|
||||
P2pCircuit,
|
||||
Quic,
|
||||
@ -121,7 +122,11 @@ impl<'a> Protocol<'a> {
|
||||
}
|
||||
"http" => Ok(Protocol::Http),
|
||||
"https" => Ok(Protocol::Https),
|
||||
"onion" => unimplemented!(), // FIXME
|
||||
"onion" =>
|
||||
iter.next()
|
||||
.ok_or(Error::InvalidProtocolString)
|
||||
.and_then(|s| read_onion(&s.to_uppercase()))
|
||||
.map(|(a, p)| Protocol::Onion(Cow::Owned(a), p)),
|
||||
"quic" => Ok(Protocol::Quic),
|
||||
"ws" => Ok(Protocol::Ws),
|
||||
"wss" => Ok(Protocol::Wss),
|
||||
@ -191,7 +196,11 @@ impl<'a> Protocol<'a> {
|
||||
P2P_WEBRTC_STAR => Ok((Protocol::P2pWebRtcStar, input)),
|
||||
P2P_WEBSOCKET_STAR => Ok((Protocol::P2pWebSocketStar, input)),
|
||||
MEMORY => Ok((Protocol::Memory, input)),
|
||||
ONION => unimplemented!(), // FIXME
|
||||
ONION => {
|
||||
let (data, rest) = split_at(12, input)?;
|
||||
let port = BigEndian::read_u16(&data[10 ..]);
|
||||
Ok((Protocol::Onion(Cow::Borrowed(array_ref!(data, 0, 10)), port), rest))
|
||||
}
|
||||
P2P => {
|
||||
let (n, input) = decode::usize(input)?;
|
||||
let (data, rest) = split_at(n, input)?;
|
||||
@ -285,7 +294,11 @@ impl<'a> Protocol<'a> {
|
||||
w.write_all(encode::usize(bytes.len(), &mut encode::usize_buffer()))?;
|
||||
w.write_all(&bytes)?
|
||||
}
|
||||
Protocol::Onion(_) => unimplemented!(), // FIXME
|
||||
Protocol::Onion(addr, port) => {
|
||||
w.write_all(encode::u32(ONION, &mut buf))?;
|
||||
w.write_all(addr.as_ref())?;
|
||||
w.write_u16::<BigEndian>(*port)?
|
||||
}
|
||||
Protocol::Quic => w.write_all(encode::u32(QUIC, &mut buf))?,
|
||||
Protocol::Utp => w.write_all(encode::u32(UTP, &mut buf))?,
|
||||
Protocol::Udt => w.write_all(encode::u32(UDT, &mut buf))?,
|
||||
@ -317,7 +330,7 @@ impl<'a> Protocol<'a> {
|
||||
P2pWebRtcStar => P2pWebRtcStar,
|
||||
P2pWebSocketStar => P2pWebSocketStar,
|
||||
Memory => Memory,
|
||||
Onion(cow) => Onion(Cow::Owned(cow.into_owned())),
|
||||
Onion(addr, port) => Onion(Cow::Owned(addr.into_owned()), port),
|
||||
P2p(a) => P2p(a),
|
||||
P2pCircuit => P2pCircuit,
|
||||
Quic => Quic,
|
||||
@ -348,7 +361,10 @@ impl<'a> fmt::Display for Protocol<'a> {
|
||||
P2pWebRtcStar => f.write_str("/p2p-webrtc-star"),
|
||||
P2pWebSocketStar => f.write_str("/p2p-websocket-star"),
|
||||
Memory => f.write_str("/memory"),
|
||||
Onion(_) => unimplemented!(), // FIXME!
|
||||
Onion(addr, port) => {
|
||||
let s = BASE32.encode(addr.as_ref());
|
||||
write!(f, "/onion/{}:{}", s.to_lowercase(), port)
|
||||
}
|
||||
P2p(c) => write!(f, "/p2p/{}", bs58::encode(c.as_bytes()).into_string()),
|
||||
P2pCircuit => f.write_str("/p2p-circuit"),
|
||||
Quic => f.write_str("/quic"),
|
||||
@ -378,3 +394,35 @@ impl<'a> From<Ipv6Addr> for Protocol<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a version 2 onion address and return its binary representation.
|
||||
//
|
||||
// Format: <base-32 address> ":" <port number>
|
||||
fn read_onion(s: &str) -> Result<([u8; 10], u16)> {
|
||||
let mut parts = s.split(':');
|
||||
|
||||
// address part (without ".onion")
|
||||
let b32 = parts.next().ok_or(Error::InvalidMultiaddr)?;
|
||||
if b32.len() != 16 {
|
||||
return Err(Error::InvalidMultiaddr)
|
||||
}
|
||||
|
||||
// port number
|
||||
let port = parts.next()
|
||||
.ok_or(Error::InvalidMultiaddr)
|
||||
.and_then(|p| str::parse(p).map_err(From::from))?;
|
||||
|
||||
// nothing else expected
|
||||
if parts.next().is_some() {
|
||||
return Err(Error::InvalidMultiaddr)
|
||||
}
|
||||
|
||||
if 10 != BASE32.decode_len(b32.len()).map_err(|_| Error::InvalidMultiaddr)? {
|
||||
return Err(Error::InvalidMultiaddr)
|
||||
}
|
||||
|
||||
let mut buf = [0u8; 10];
|
||||
BASE32.decode_mut(b32.as_bytes(), &mut buf).map_err(|_| Error::InvalidMultiaddr)?;
|
||||
|
||||
Ok((buf, port))
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ struct Proto(Protocol<'static>);
|
||||
impl Arbitrary for Proto {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
||||
use Protocol::*;
|
||||
match g.gen_range(0, 22) { // TODO: Add Protocol::Quic
|
||||
match g.gen_range(0, 23) { // TODO: Add Protocol::Quic
|
||||
0 => Proto(Dccp(g.gen())),
|
||||
1 => Proto(Dns4(Cow::Owned(SubString::arbitrary(g).0))),
|
||||
2 => Proto(Dns6(Cow::Owned(SubString::arbitrary(g).0))),
|
||||
@ -83,6 +83,11 @@ impl Arbitrary for Proto {
|
||||
19 => Proto(Utp),
|
||||
20 => Proto(Ws),
|
||||
21 => Proto(Wss),
|
||||
22 => {
|
||||
let mut a = [0; 10];
|
||||
g.fill(&mut a);
|
||||
Proto(Onion(Cow::Owned(a), g.gen()))
|
||||
}
|
||||
_ => panic!("outside range")
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user