use crate::{
error::parser::TunnelBuildRecordParseError,
i2np::{HopRole, AES256_IV_LEN, AES256_KEY_LEN, ROUTER_HASH_LEN},
primitives::{Mapping, MessageId, RouterId, TunnelId},
};
use nom::{
bytes::complete::take,
number::complete::{be_u32, be_u8},
Err, IResult,
};
#[derive(Debug)]
pub struct TunnelBuildRecord<'a> {
tunnel_id: TunnelId,
next_tunnel_id: TunnelId,
next_router: RouterId,
tunnel_layer_key: &'a [u8],
tunnel_iv_key: &'a [u8],
role: HopRole,
next_message_id: MessageId,
}
impl<'a> TunnelBuildRecord<'a> {
pub fn parse_frame(
input: &'a [u8],
) -> IResult<&'a [u8], TunnelBuildRecord<'a>, TunnelBuildRecordParseError> {
let (rest, tunnel_id) = be_u32(input)?;
let (rest, next_tunnel_id) = be_u32(rest)?;
let (rest, next_router_hash) = take(ROUTER_HASH_LEN)(rest)?;
let (rest, tunnel_layer_key) = take(AES256_KEY_LEN)(rest)?;
let (rest, tunnel_iv_key) = take(AES256_KEY_LEN)(rest)?;
let (rest, _tunnel_reply_key) = take(AES256_KEY_LEN)(rest)?;
let (rest, _tunnel_reply_iv) = take(AES256_IV_LEN)(rest)?;
let (rest, flags) = be_u8(rest)?;
let (rest, _reserved) = take(3usize)(rest)?;
let (rest, _request_time) = be_u32(rest)?;
let (rest, _request_expiration) = be_u32(rest)?;
let (rest, next_message_id) = be_u32(rest)?;
let (rest, _options) = Mapping::parse_frame(rest).map_err(Err::convert)?;
let (rest, _padding) = take(input.len() - rest.len())(rest)?;
let role = HopRole::from_u8(flags)
.ok_or(Err::Error(TunnelBuildRecordParseError::InvalidHop(flags)))?;
Ok((
rest,
TunnelBuildRecord {
tunnel_id: TunnelId::from(tunnel_id),
next_tunnel_id: TunnelId::from(next_tunnel_id),
next_router: RouterId::from(next_router_hash),
tunnel_layer_key,
tunnel_iv_key,
role,
next_message_id: MessageId::from(next_message_id),
},
))
}
pub fn parse(input: &'a [u8]) -> Result<TunnelBuildRecord<'a>, TunnelBuildRecordParseError> {
Ok(Self::parse_frame(input)?.1)
}
pub fn tunnel_id(&self) -> TunnelId {
self.tunnel_id
}
pub fn next_tunnel_id(&self) -> TunnelId {
self.next_tunnel_id
}
pub fn next_router(&self) -> RouterId {
self.next_router.clone()
}
pub fn role(&self) -> HopRole {
self.role
}
pub fn next_message_id(&self) -> MessageId {
self.next_message_id
}
pub fn tunnel_layer_key(&self) -> &[u8] {
self.tunnel_layer_key
}
pub fn tunnel_iv_key(&self) -> &[u8] {
self.tunnel_iv_key
}
}