mod onion_announce_request;
mod onion_announce_response;
mod inner_onion_request;
mod inner_onion_response;
mod onion_data_request;
mod onion_data_response;
mod onion_request_0;
mod onion_request_1;
mod onion_request_2;
mod onion_response_1;
mod onion_response_2;
mod onion_response_3;
pub use self::onion_announce_request::*;
pub use self::onion_announce_response::*;
pub use self::inner_onion_request::*;
pub use self::inner_onion_response::*;
pub use self::onion_data_request::*;
pub use self::onion_data_response::*;
pub use self::onion_request_0::*;
pub use self::onion_request_1::*;
pub use self::onion_request_2::*;
pub use self::onion_response_1::*;
pub use self::onion_response_2::*;
pub use self::onion_response_3::*;
use toxcore::binary_io::*;
use toxcore::crypto_core::*;
use toxcore::dht::packed_node::PackedNode;
use nom::{be_u16, le_u8, rest};
use std::net::{
IpAddr,
Ipv4Addr,
Ipv6Addr,
SocketAddr,
};
use std::io::{Error, ErrorKind};
pub const IPV4_PADDING_SIZE: usize = 12;
pub const SIZE_IPPORT: usize = 19;
pub const ONION_RETURN_1_SIZE: usize = secretbox::NONCEBYTES + SIZE_IPPORT + MACBYTES; pub const ONION_RETURN_2_SIZE: usize = secretbox::NONCEBYTES + SIZE_IPPORT + MACBYTES + ONION_RETURN_1_SIZE; pub const ONION_RETURN_3_SIZE: usize = secretbox::NONCEBYTES + SIZE_IPPORT + MACBYTES + ONION_RETURN_2_SIZE;
pub const ONION_MAX_PACKET_SIZE: usize = 1400;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ProtocolType {
UDP,
TCP
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IpPort {
pub protocol: ProtocolType,
pub ip_addr: IpAddr,
pub port: u16
}
impl FromBytes for IpPort {
named!(from_bytes<IpPort>, alt!(call!(IpPort::from_udp_bytes) | call!(IpPort::from_tcp_bytes)));
}
impl ToBytes for IpPort {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_be_u8!(self.ip_type()) >>
gen_call!(|buf, ip_addr| IpAddr::to_bytes(ip_addr, buf), &self.ip_addr) >>
gen_cond!(self.ip_addr.is_ipv4(), gen_slice!(&[0; IPV4_PADDING_SIZE])) >>
gen_be_u16!(self.port)
)
}
}
impl IpPort {
fn ip_type(&self) -> u8 {
if self.ip_addr.is_ipv4() {
match self.protocol {
ProtocolType::UDP => 2,
ProtocolType::TCP => 130,
}
} else {
match self.protocol {
ProtocolType::UDP => 10,
ProtocolType::TCP => 138,
}
}
}
named!(
#[allow(unused_variables)]
#[doc = "Parse `IpPort` with UDP protocol type."],
from_udp_bytes<IpPort>,
do_parse!(
ip_addr: switch!(le_u8,
2 => terminated!(
map!(Ipv4Addr::from_bytes, IpAddr::V4),
take!(IPV4_PADDING_SIZE)
) |
10 => map!(Ipv6Addr::from_bytes, IpAddr::V6)
) >>
port: be_u16 >>
(IpPort { protocol: ProtocolType::UDP, ip_addr, port })
)
);
named!(
#[allow(unused_variables)]
#[doc = "Parse `IpPort` with TCP protocol type."],
from_tcp_bytes<IpPort>,
do_parse!(
ip_addr: switch!(le_u8,
130 => terminated!(
map!(Ipv4Addr::from_bytes, IpAddr::V4),
take!(IPV4_PADDING_SIZE)
) |
138 => map!(Ipv6Addr::from_bytes, IpAddr::V6)
) >>
port: be_u16 >>
(IpPort { protocol: ProtocolType::TCP, ip_addr, port })
)
);
pub fn to_udp_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_cond!(self.protocol == ProtocolType::TCP, |buf| gen_error(buf, 0)) >>
gen_call!(|buf, ip_port| IpPort::to_bytes(ip_port, buf), self)
)
}
pub fn to_tcp_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_cond!(self.protocol == ProtocolType::UDP, |buf| gen_error(buf, 0)) >>
gen_call!(|buf, ip_port| IpPort::to_bytes(ip_port, buf), self)
)
}
pub fn from_udp_saddr(saddr: SocketAddr) -> IpPort {
IpPort {
protocol: ProtocolType::UDP,
ip_addr: saddr.ip(),
port: saddr.port()
}
}
pub fn from_tcp_saddr(saddr: SocketAddr) -> IpPort {
IpPort {
protocol: ProtocolType::TCP,
ip_addr: saddr.ip(),
port: saddr.port()
}
}
pub fn to_saddr(&self) -> SocketAddr {
SocketAddr::new(self.ip_addr, self.port)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OnionReturn {
pub nonce: secretbox::Nonce,
pub payload: Vec<u8>
}
impl FromBytes for OnionReturn {
named!(from_bytes<OnionReturn>, do_parse!(
nonce: call!(secretbox::Nonce::from_bytes) >>
payload: rest >>
(OnionReturn { nonce, payload: payload.to_vec() })
));
}
impl ToBytes for OnionReturn {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_slice!(self.nonce.as_ref()) >>
gen_slice!(self.payload)
)
}
}
impl OnionReturn {
fn inner_to_bytes<'a>(ip_port: &IpPort, inner: Option<&OnionReturn>, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_call!(|buf, ip_port| IpPort::to_bytes(ip_port, buf), ip_port) >>
gen_call!(|buf, inner| match inner {
Some(inner) => OnionReturn::to_bytes(inner, buf),
None => Ok(buf)
}, inner)
)
}
named!(inner_from_bytes<(IpPort, Option<OnionReturn>)>, do_parse!(
ip_port: call!(IpPort::from_bytes) >>
rest_len: rest_len >>
inner: cond!(rest_len > 0, OnionReturn::from_bytes) >>
(ip_port, inner)
));
pub fn new(symmetric_key: &secretbox::Key, ip_port: &IpPort, inner: Option<&OnionReturn>) -> OnionReturn {
let nonce = secretbox::gen_nonce();
let mut buf = [0; ONION_RETURN_2_SIZE + SIZE_IPPORT];
let (_, size) = OnionReturn::inner_to_bytes(ip_port, inner, (&mut buf, 0)).unwrap();
let payload = secretbox::seal(&buf[..size], &nonce, symmetric_key);
OnionReturn { nonce, payload }
}
pub fn get_payload(&self, symmetric_key: &secretbox::Key) -> Result<(IpPort, Option<OnionReturn>), Error> {
let decrypted = secretbox::open(&self.payload, &self.nonce, symmetric_key)
.map_err(|()| {
debug!("Decrypting OnionReturn failed!");
Error::new(ErrorKind::Other, "OnionReturn decrypt error.")
})?;
match OnionReturn::inner_from_bytes(&decrypted) {
IResult::Incomplete(e) => {
debug!(target: "Onion", "Inner onion return deserialize error: {:?}", e);
Err(Error::new(ErrorKind::Other,
format!("Inner onion return deserialize error: {:?}", e)))
},
IResult::Error(e) => {
debug!(target: "Onion", "Inner onion return deserialize error: {:?}", e);
Err(Error::new(ErrorKind::Other,
format!("Inner onion return deserialize error: {:?}", e)))
},
IResult::Done(_, inner) => {
Ok(inner)
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AnnounceStatus {
Failed = 0,
Found = 1,
Announced = 2
}
impl FromBytes for AnnounceStatus {
named!(from_bytes<AnnounceStatus>, switch!(le_u8,
0 => value!(AnnounceStatus::Failed) |
1 => value!(AnnounceStatus::Found) |
2 => value!(AnnounceStatus::Announced)
));
}
impl ToBytes for AnnounceStatus {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
gen_be_u8!(buf, *self as u8)
}
}
#[cfg(test)]
mod tests {
use super::*;
const ONION_RETURN_1_PAYLOAD_SIZE: usize = ONION_RETURN_1_SIZE - secretbox::NONCEBYTES;
encode_decode_test!(
ip_port_udp_encode_decode,
IpPort {
protocol: ProtocolType::UDP,
ip_addr: "5.6.7.8".parse().unwrap(),
port: 12345
}
);
encode_decode_test!(
ip_port_tcp_encode_decode,
IpPort {
protocol: ProtocolType::TCP,
ip_addr: "5.6.7.8".parse().unwrap(),
port: 12345
}
);
encode_decode_test!(
onion_return_encode_decode,
OnionReturn {
nonce: secretbox::gen_nonce(),
payload: vec![42; ONION_RETURN_1_PAYLOAD_SIZE]
}
);
encode_decode_test!(announce_status_failed, AnnounceStatus::Failed);
encode_decode_test!(announce_status_found, AnnounceStatus::Found);
encode_decode_test!(announce_status_accounced, AnnounceStatus::Announced);
#[test]
fn ip_port_from_to_udp_saddr() {
let ip_port_1 = IpPort {
protocol: ProtocolType::UDP,
ip_addr: "5.6.7.8".parse().unwrap(),
port: 12345
};
let ip_port_2 = IpPort::from_udp_saddr(ip_port_1.to_saddr());
assert_eq!(ip_port_2, ip_port_1);
}
#[test]
fn ip_port_from_to_tcp_saddr() {
let ip_port_1 = IpPort {
protocol: ProtocolType::TCP,
ip_addr: "5.6.7.8".parse().unwrap(),
port: 12345
};
let ip_port_2 = IpPort::from_tcp_saddr(ip_port_1.to_saddr());
assert_eq!(ip_port_2, ip_port_1);
}
#[test]
fn onion_return_encrypt_decrypt() {
let alice_symmetric_key = secretbox::gen_key();
let bob_symmetric_key = secretbox::gen_key();
let ip_port_1 = IpPort {
protocol: ProtocolType::UDP,
ip_addr: "5.6.7.8".parse().unwrap(),
port: 12345
};
let onion_return_1 = OnionReturn::new(&alice_symmetric_key, &ip_port_1, None);
let ip_port_2 = IpPort {
protocol: ProtocolType::UDP,
ip_addr: "7.8.5.6".parse().unwrap(),
port: 54321
};
let onion_return_2 = OnionReturn::new(&bob_symmetric_key, &ip_port_2, Some(&onion_return_1));
let (decrypted_ip_port_2, decrypted_onion_return_1) = onion_return_2.get_payload(&bob_symmetric_key).unwrap();
assert_eq!(decrypted_ip_port_2, ip_port_2);
assert_eq!(decrypted_onion_return_1.unwrap(), onion_return_1);
let (decrypted_ip_port_1, none) = onion_return_1.get_payload(&alice_symmetric_key).unwrap();
assert_eq!(decrypted_ip_port_1, ip_port_1);
assert!(none.is_none());
}
#[test]
fn onion_return_encrypt_decrypt_invalid_key() {
let alice_symmetric_key = secretbox::gen_key();
let bob_symmetric_key = secretbox::gen_key();
let eve_symmetric_key = secretbox::gen_key();
let ip_port_1 = IpPort {
protocol: ProtocolType::UDP,
ip_addr: "5.6.7.8".parse().unwrap(),
port: 12345
};
let onion_return_1 = OnionReturn::new(&alice_symmetric_key, &ip_port_1, None);
let ip_port_2 = IpPort {
protocol: ProtocolType::UDP,
ip_addr: "7.8.5.6".parse().unwrap(),
port: 54321
};
let onion_return_2 = OnionReturn::new(&bob_symmetric_key, &ip_port_2, Some(&onion_return_1));
assert!(onion_return_1.get_payload(&eve_symmetric_key).is_err());
assert!(onion_return_2.get_payload(&eve_symmetric_key).is_err());
}
#[test]
fn onion_return_decrypt_invalid() {
let symmetric_key = secretbox::gen_key();
let nonce = secretbox::gen_nonce();
let invalid_payload = [42; 123];
let invalid_payload_encoded = secretbox::seal(&invalid_payload, &nonce, &symmetric_key);
let invalid_onion_return = OnionReturn {
nonce,
payload: invalid_payload_encoded
};
assert!(invalid_onion_return.get_payload(&symmetric_key).is_err());
let invalid_payload = [];
let invalid_payload_encoded = secretbox::seal(&invalid_payload, &nonce, &symmetric_key);
let invalid_onion_return = OnionReturn {
nonce,
payload: invalid_payload_encoded
};
assert!(invalid_onion_return.get_payload(&symmetric_key).is_err());
}
}