diff --git a/src/codec.rs b/src/codec.rs index 3f39206..f10beb9 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -1,9 +1,10 @@ use crate::{ + babel::{self, Tlv}, crypto::PublicKey, metric::Metric, packet::{ - BabelPacketBody, BabelPacketHeader, BabelTLV, BabelTLVType, ControlPacket, DataPacket, - Packet, PacketType, + BabelPacketBody, BabelPacketHeader, BabelTLVType, ControlPacket, DataPacket, Packet, + PacketType, }, }; use bytes::{Buf, BufMut, BytesMut}; @@ -221,12 +222,15 @@ impl Encoder for DataPacketCodec { /* ****************************CONTROL PACKET******************************** */ pub struct ControlPacketCodec { - header: Option, + // TODO: wrapper to make it easier to deserialize + codec: babel::Codec, } impl ControlPacketCodec { pub fn new() -> Self { - ControlPacketCodec { header: None } + ControlPacketCodec { + codec: babel::Codec::new(), + } } } @@ -235,134 +239,22 @@ impl Decoder for ControlPacketCodec { type Error = std::io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - let header = if let Some(header) = self.header.take() { - header - } else { - if buf.remaining() < 4 { - return Ok(None); - } - - let magic = buf.get_u8(); - let version = buf.get_u8(); - let body_length = buf.get_u16(); - - BabelPacketHeader { - magic, - version, - body_length, - } + let tlv = match self.codec.decode(buf)? { + None => return Ok(None), + Some(res) => res, }; - if buf.remaining() < header.body_length as usize { - // here the self.header is actually always None (due to take function) - // so assign it again to Some(header) - self.header = Some(header); - return Ok(None); - } - - let tlv_type = match BabelTLVType::from_u8(buf.get_u8()) { - Some(t) => t, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid TLV type", - )) - } + let body = BabelPacketBody { + tlv_type: match tlv { + babel::Tlv::Hello(_) => BabelTLVType::Hello, + babel::Tlv::Ihu(_) => BabelTLVType::IHU, + babel::Tlv::Update(_) => BabelTLVType::Update, + }, + length: tlv.wire_size(), + tlv, }; - let length = buf.get_u8(); - - let body = match tlv_type { - BabelTLVType::Hello => { - let seqno = buf.get_u16().into(); - let interval = buf.get_u16(); - - BabelPacketBody { - tlv_type, - length, - tlv: BabelTLV::Hello { seqno, interval }, - } - } - BabelTLVType::IHU => { - let interval = buf.get_u16(); - let address = IpAddr::V6(Ipv6Addr::new( - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - )); - - BabelPacketBody { - tlv_type, - length, - tlv: BabelTLV::IHU { interval, address }, - } - } - BabelTLVType::Update => { - let ae = buf.get_u8(); - let plen = buf.get_u8(); - let interval = buf.get_u16(); - let seqno = buf.get_u16().into(); - let metric = buf.get_u16(); - // based on the remaining bytes (ip + router_id) we can check if it's IPv4 or v6 - let prefix = match ae { - 0 => { - warn!("IPv4 ae, this should be removed!!"); - // 4 bytes IP + 4 bytes router_id - IpAddr::V4(Ipv4Addr::new( - buf.get_u8(), - buf.get_u8(), - buf.get_u8(), - buf.get_u8(), - )) - } - 1 => { - // 16 bytes IP + 4 bytes router_id - IpAddr::V6(Ipv6Addr::new( - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - buf.get_u16(), - )) - } - _ => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid address length", - )) - } - }; - - let mut router_id_bytes = [0u8; 32]; - router_id_bytes.copy_from_slice(&buf[..32]); - buf.advance(32); - - let router_id = PublicKey::from(router_id_bytes); - - BabelPacketBody { - tlv_type, - length, - tlv: BabelTLV::Update { - plen, - interval, - seqno, - metric: Metric::from(metric), - prefix, - router_id, - }, - } - } - }; - - Ok(Some(ControlPacket { header, body })) + Ok(Some(ControlPacket { body })) } } @@ -370,77 +262,6 @@ impl Encoder for ControlPacketCodec { type Error = io::Error; fn encode(&mut self, message: ControlPacket, buf: &mut BytesMut) -> Result<(), Self::Error> { - // Write BabelPacketHeader - buf.put_u8(message.header.magic); - buf.put_u8(message.header.version); - buf.put_u16(message.header.body_length); - - // Write BabelPacketBody - buf.put_u8(message.body.tlv_type as u8); - buf.put_u8(message.body.length); - - match message.body.tlv { - BabelTLV::Hello { seqno, interval } => { - buf.put_u16(seqno.into()); - buf.put_u16(interval); - } - BabelTLV::IHU { interval, address } => { - buf.put_u16(interval); - match address { - IpAddr::V4(ipv4) => { - buf.put_u8(ipv4.octets()[0]); - buf.put_u8(ipv4.octets()[1]); - buf.put_u8(ipv4.octets()[2]); - buf.put_u8(ipv4.octets()[3]); - } - IpAddr::V6(ipv6) => { - buf.put_u16(ipv6.segments()[0]); - buf.put_u16(ipv6.segments()[1]); - buf.put_u16(ipv6.segments()[2]); - buf.put_u16(ipv6.segments()[3]); - buf.put_u16(ipv6.segments()[4]); - buf.put_u16(ipv6.segments()[5]); - buf.put_u16(ipv6.segments()[6]); - buf.put_u16(ipv6.segments()[7]); - } - } - } - BabelTLV::Update { - plen, - interval, - seqno, - metric, - prefix, - router_id, - } => { - buf.put_u8(if prefix.is_ipv4() { 0 } else { 1 }); - buf.put_u8(plen); - buf.put_u16(interval); - buf.put_u16(seqno.into()); - buf.put_u16(metric.into()); - match prefix { - IpAddr::V4(ipv4) => { - buf.put_u8(ipv4.octets()[0]); - buf.put_u8(ipv4.octets()[1]); - buf.put_u8(ipv4.octets()[2]); - buf.put_u8(ipv4.octets()[3]); - } - IpAddr::V6(_ipv6) => { - buf.put_u16(_ipv6.segments()[0]); - buf.put_u16(_ipv6.segments()[1]); - buf.put_u16(_ipv6.segments()[2]); - buf.put_u16(_ipv6.segments()[3]); - buf.put_u16(_ipv6.segments()[4]); - buf.put_u16(_ipv6.segments()[5]); - buf.put_u16(_ipv6.segments()[6]); - buf.put_u16(_ipv6.segments()[7]); - } - } - - buf.put_slice(&router_id.to_bytes()); - } - } - - Ok(()) + self.codec.encode(message.body.tlv, buf) } } diff --git a/src/packet.rs b/src/packet.rs index 18d71b0..8e2ccef 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,6 +1,6 @@ use std::net::{IpAddr, Ipv6Addr}; -use crate::{crypto::PublicKey, metric::Metric, peer::Peer, sequence_number::SeqNo}; +use crate::{babel, crypto::PublicKey, metric::Metric, peer::Peer, sequence_number::SeqNo}; pub const BABEL_MAGIC: u8 = 42; pub const BABEL_VERSION: u8 = 2; @@ -39,7 +39,6 @@ pub struct ControlStruct { #[derive(Debug, PartialEq, Clone)] pub struct ControlPacket { - pub header: BabelPacketHeader, pub body: BabelPacketBody, } @@ -55,7 +54,7 @@ pub struct BabelPacketHeader { pub struct BabelPacketBody { pub tlv_type: BabelTLVType, pub length: u8, // length of the tlv (only the tlv, not tlv_type and length itself) - pub tlv: BabelTLV, + pub tlv: babel::Tlv, } impl BabelPacketHeader { @@ -70,33 +69,25 @@ impl BabelPacketHeader { impl ControlPacket { pub fn new_hello(dest_peer: &mut Peer, interval: u16) -> Self { - let header_length = (BabelTLVType::Hello.get_tlv_length(false) + 2) as u16; + let tlv: babel::Tlv = babel::Hello::new_unicast(dest_peer.hello_seqno(), interval).into(); dest_peer.increment_hello_seqno(); Self { - header: BabelPacketHeader::new(header_length), body: BabelPacketBody { tlv_type: BabelTLVType::Hello, - length: BabelTLVType::Hello.get_tlv_length(false), - tlv: BabelTLV::Hello { - seqno: dest_peer.hello_seqno(), - interval, - }, + length: tlv.wire_size(), + tlv, }, } } pub fn new_ihu(interval: u16, dest_address: IpAddr) -> Self { - let uses_ipv6 = dest_address.is_ipv6(); - let header_length = (BabelTLVType::IHU.get_tlv_length(uses_ipv6) + 2) as u16; + // TODO: Set rx metric + let tlv: babel::Tlv = babel::Ihu::new(Metric::from(0), interval, Some(dest_address)).into(); Self { - header: BabelPacketHeader::new(header_length), body: BabelPacketBody { tlv_type: BabelTLVType::IHU, - length: BabelTLVType::IHU.get_tlv_length(uses_ipv6), - tlv: BabelTLV::IHU { - interval, - address: dest_address, - }, + length: tlv.wire_size(), + tlv, }, } } @@ -109,21 +100,13 @@ impl ControlPacket { prefix: IpAddr, router_id: PublicKey, ) -> Self { - let uses_ipv6 = prefix.is_ipv6(); - let header_length = (BabelTLVType::Update.get_tlv_length(uses_ipv6) + 2) as u16; + let tlv: babel::Tlv = + babel::Update::new(plen, 0, interval, seqno, metric, prefix, router_id).into(); Self { - header: BabelPacketHeader::new(header_length), body: BabelPacketBody { tlv_type: BabelTLVType::Update, - length: BabelTLVType::Update.get_tlv_length(uses_ipv6), - tlv: BabelTLV::Update { - plen, - interval, - seqno, - metric, - prefix, - router_id, - }, + length: tlv.wire_size(), + tlv, }, } } @@ -145,37 +128,4 @@ impl BabelTLVType { _ => None, } } - - pub fn get_tlv_length(self, uses_ipv6: bool) -> u8 { - let (ipv6, ipv4) = match self { - Self::Hello => (4, 4), - Self::IHU => (18, 6), - Self::Update => (31 + 1, 19 + 1), // +1 for ae - }; - if uses_ipv6 { - ipv6 - } else { - ipv4 - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum BabelTLV { - Hello { - seqno: SeqNo, - interval: u16, - }, - IHU { - interval: u16, - address: IpAddr, - }, - Update { - plen: u8, - interval: u16, - seqno: SeqNo, - metric: Metric, - prefix: IpAddr, - router_id: PublicKey, - }, } diff --git a/src/router.rs b/src/router.rs index 85c5938..27d0179 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,7 +1,8 @@ use crate::{ + babel, crypto::{PublicKey, SecretKey}, metric::Metric, - packet::{BabelTLV, BabelTLVType, ControlPacket, ControlStruct, DataPacket}, + packet::{BabelTLVType, ControlPacket, ControlStruct, DataPacket}, peer::Peer, routing_table::{RouteEntry, RouteKey, RoutingTable}, sequence_number::SeqNo, @@ -297,16 +298,15 @@ impl Router { } } - fn handle_incoming_update(&self, update: ControlStruct) { - match update.control_packet.body.tlv { - BabelTLV::Update { - plen, - interval: _, - seqno, - metric, - prefix, - router_id, - } => { + fn handle_incoming_update(&self, update_packet: ControlStruct) { + match update_packet.control_packet.body.tlv { + babel::Tlv::Update(update) => { + let metric = update.metric(); + let plen = update.plen(); + let router_id = update.router_id(); + let prefix = update.prefix(); + let seqno = update.seqno(); + // convert prefix to ipv6 address if let IpAddr::V6(prefix_as_ipv6addr) = prefix { // add it the mapping @@ -315,7 +315,7 @@ impl Router { // create route key from incoming update control struct // we need the address of the neighbour; this corresponds to the source ip of the control struct as the update is received from the neighbouring peer - let neighbor_ip = update.src_overlay_ip; + let neighbor_ip = update_packet.src_overlay_ip; let route_key_from_update = RouteKey::new(prefix, plen, neighbor_ip); // used later to filter out static route if self.route_key_is_from_static_route(&route_key_from_update) { @@ -813,17 +813,16 @@ impl RouterInner { matching_peer.map(Clone::clone) } - fn send_update(&mut self, peer: &Peer, update: ControlPacket) { + fn send_update(&mut self, peer: &Peer, update_packet: ControlPacket) { // before sending an update, the source table might need to be updated - match update.body.tlv { - BabelTLV::Update { - plen, - interval: _, - seqno, - metric, - prefix, - router_id, - } => { + match update_packet.body.tlv { + babel::Tlv::Update(ref update) => { + let plen = update.plen(); + let seqno = update.seqno(); + let metric = update.metric(); + let prefix = update.prefix(); + let router_id = update.router_id(); + let source_key = SourceKey::new(prefix, plen, router_id); if let Some(source_entry) = self.source_table.get(&source_key) { @@ -847,7 +846,7 @@ impl RouterInner { } // send the update to the peer - if let Err(e) = peer.send_control_packet(update) { + if let Err(e) = peer.send_control_packet(update_packet) { error!("Error sending update to peer: {:?}", e); } } diff --git a/src/source_table.rs b/src/source_table.rs index edcf959..f019662 100644 --- a/src/source_table.rs +++ b/src/source_table.rs @@ -1,13 +1,6 @@ use std::{collections::HashMap, net::IpAddr}; -use log::error; - -use crate::{ - crypto::PublicKey, - metric::Metric, - packet::{BabelTLV, ControlStruct}, - sequence_number::SeqNo, -}; +use crate::{babel, crypto::PublicKey, metric::Metric, sequence_number::SeqNo}; #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] pub struct SourceKey { @@ -95,33 +88,18 @@ impl SourceTable { } /// Indicates if an update is feasible in the context of the current `SoureTable`. - pub fn is_update_feasible(&self, update: &ControlStruct) -> bool { + pub fn is_update_feasible(&self, update: &babel::Update) -> bool { // Before an update is accepted it should be checked against the feasbility condition // If an entry in the source table with the same source key exists, we perform the feasbility check // If no entry exists yet, the update is accepted as there is no better alternative available (yet) - match update.control_packet.body.tlv { - BabelTLV::Update { - plen, - interval: _, - seqno, - metric, - prefix, - router_id, - } => { - let source_key = SourceKey::new(prefix, plen, router_id); - match self.get(&source_key) { - Some(&entry) => { - (!seqno.lt(&entry.seqno())) - || (seqno == entry.seqno() && metric < entry.metric()) - || metric.is_infinite() - } - None => true, - } - } - _ => { - error!("Error accepting update, control struct did not match update packet"); - false + let source_key = SourceKey::new(update.prefix(), update.plen(), update.router_id()); + match self.get(&source_key) { + Some(entry) => { + (!update.seqno().lt(&entry.seqno())) + || (update.seqno() == entry.seqno() && update.metric() < entry.metric()) + || update.metric().is_infinite() } + None => true, } } }