Skip to content

Commit

Permalink
feat: add implementation of the SCION packet
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcsmith committed Nov 1, 2023
1 parent 22fcd76 commit e136b17
Show file tree
Hide file tree
Showing 11 changed files with 1,331 additions and 5 deletions.
22 changes: 20 additions & 2 deletions crates/scion/src/address/host.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::net::{IpAddr, SocketAddr};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};

use super::ServiceAddress;

/// The AS-local host identifier of a SCION address.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Host {
/// An IPv4 or IPv6 host address
Ip(IpAddr),
Expand Down Expand Up @@ -92,3 +92,21 @@ where
.unwrap_or(HostType::None)
}
}

impl From<IpAddr> for Host {
fn from(value: IpAddr) -> Self {
Host::Ip(value)
}
}

impl From<Ipv4Addr> for Host {
fn from(value: Ipv4Addr) -> Self {
Host::Ip(value.into())
}
}

impl From<Ipv6Addr> for Host {
fn from(value: Ipv6Addr) -> Self {
Host::Ip(value.into())
}
}
3 changes: 2 additions & 1 deletion crates/scion/src/address/ia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use super::{AddressParseError, Asn, Isd};
/// The combined ISD and AS identifier of a SCION AS (sometimes abbreviated as IA).
#[derive(Copy, Clone, Eq, PartialEq, Deserialize, Hash)]
#[serde(try_from = "String")]
pub struct IsdAsn(u64);
#[repr(transparent)]
pub struct IsdAsn(pub u64);

impl IsdAsn {
/// A SCION IA of the special wildcard IA, 0-0.
Expand Down
10 changes: 8 additions & 2 deletions crates/scion/src/address/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{

use thiserror;

use super::{HostAddress, HostType};
use super::{Host, HostAddress, HostType};

/// A SCION service address.
///
Expand All @@ -18,7 +18,7 @@ use super::{HostAddress, HostType};
/// both represent the anycast service address ServiceAddress::CONTROL. The
/// corresponding multicast service address would be CS_M.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct ServiceAddress(u16);
pub struct ServiceAddress(pub u16);

impl ServiceAddress {
/// SCION daemon anycast service address (DS_A)
Expand Down Expand Up @@ -112,6 +112,12 @@ impl From<ServiceAddress> for u16 {
}
}

impl From<ServiceAddress> for Host {
fn from(value: ServiceAddress) -> Self {
Host::Svc(value)
}
}

impl Display for ServiceAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.anycast() {
Expand Down
4 changes: 4 additions & 0 deletions crates/scion/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
pub mod address;
pub mod daemon;
pub mod packet;
pub mod path;
pub mod reliable;

mod wire_encoding;

#[cfg(test)]
pub(crate) mod test_utils;
102 changes: 102 additions & 0 deletions crates/scion/src/packet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! Representation of SCION packet and constituent types.
//!
//! This module contains an implementation of the SCION packet representation, its wire
//! format, and errors encountered while decoding the packet.
//!
//! For paths useable in a SCION packet, see the [path module][`crate::path`].

use bytes::{Buf, Bytes};

use crate::{
path::PathErrorKind,
wire_encoding::{WireDecode, WireDecodeWithContext},
};

mod common_header;
pub use common_header::{AddressInfo, CommonHeader, FlowId, Version};

mod address_header;
pub use address_header::{AddressHeader, RawHostAddress};

mod path_header;
pub use path_header::PathHeader;

/// Instances of an object associated with both a source and destination endpoint.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ByEndpoint<T> {
destination: T,
source: T,
}

/// A SCION network packet.
#[allow(unused)]
pub struct ScionPacket {
/// Metadata about the remaining headers and payload.
common_header: CommonHeader,
/// Source and destination addresses.
address_header: AddressHeader,
/// The path to the destination, when necessary.
path_header: Option<PathHeader>,
/// The packet payload.
payload: Bytes,
}

impl<T> WireDecode<T> for ScionPacket
where
T: Buf,
{
type Error = DecodeError;

fn decode(data: &mut T) -> Result<Self, Self::Error> {
let common_header = CommonHeader::decode(data)?;

// Limit the data for headers to the length specified by the common header
let mut header_data = data.take(common_header.remaining_header_length());

let address_header =
AddressHeader::decode_with_context(&mut header_data, common_header.address_info)?;

let path_context = (common_header.path_type, header_data.remaining());
let path_header = match PathHeader::decode_with_context(&mut header_data, path_context) {
Err(DecodeError::EmptyPath) => None,
other => Some(other?),
};

// The path header consumes all the remaining header bytes
debug_assert_eq!(header_data.remaining(), 0);

if data.remaining() < common_header.payload_size() {
return Err(DecodeError::PacketEmptyOrTruncated);
}

let payload = data.copy_to_bytes(common_header.payload_size());

Ok(Self {
common_header,
address_header,
path_header,
payload,
})
}
}

/// Errors raised when failing to decode a [`ScionPacket`] or its constituents.
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum DecodeError {
#[error("cannot decode packet with unsupported header version {0:?}")]
UnsupportedVersion(Version),
#[error("header length factor is inconsistent with the SCION specification: {0}")]
InvalidHeaderLength(u8),
#[error("the provided bytes did not include the full packet")]
PacketEmptyOrTruncated,
#[error("attempted to decode the empty path type")]
EmptyPath,
#[error("invalid path header: {0}")]
InvalidPath(PathErrorKind),
}

impl From<PathErrorKind> for DecodeError {
fn from(value: PathErrorKind) -> Self {
Self::InvalidPath(value)
}
}
Loading

0 comments on commit e136b17

Please sign in to comment.