use crate::packet::ReferenceIdentifier;
use std::convert::From;
use std::error::Error;
use std::fmt::{Display, Formatter};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum KissCode {
Unknown,
AssociationBelongsToAnycastServer,
AssociationBelongsToBroadcastServer,
AssociationBelongsToManycastServer,
ServerAuthenticationFailed,
AutokeySequenceFailed,
CryptographicAuthenticationFailed,
AccessDenied,
LostPeer,
AssociationNotYetSynchronized,
NoKeyFound,
RateExceeded,
TinkeringWithAssociation,
StepChange,
}
impl KissCode {
pub(crate) fn new(reference_identifier: &ReferenceIdentifier) -> KissCode {
if let ReferenceIdentifier::ASCII(s) = reference_identifier {
match s.as_str() {
"ACST" => KissCode::AssociationBelongsToAnycastServer,
"AUTH" => KissCode::ServerAuthenticationFailed,
"AUTO" => KissCode::AutokeySequenceFailed,
"BCST" => KissCode::AssociationBelongsToBroadcastServer,
"CRYP" => KissCode::CryptographicAuthenticationFailed,
"DENY" => KissCode::AccessDenied,
"DROP" => KissCode::LostPeer,
"RSTR" => KissCode::AccessDenied,
"INIT" => KissCode::AssociationNotYetSynchronized,
"MCST" => KissCode::AssociationBelongsToManycastServer,
"NKEY" => KissCode::NoKeyFound,
"RATE" => KissCode::RateExceeded,
"RMOT" => KissCode::TinkeringWithAssociation,
"STEP" => KissCode::StepChange,
_ => KissCode::Unknown,
}
} else {
KissCode::Unknown
}
}
}
impl Display for KissCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
KissCode::Unknown => write!(f, "Unknown"),
KissCode::AssociationBelongsToAnycastServer => {
write!(f, "The association belongs to a anycast server")
}
KissCode::AssociationBelongsToBroadcastServer => {
write!(f, "The association belongs to a broadcast server")
}
KissCode::AssociationBelongsToManycastServer => {
write!(f, "The association belongs to a manycast server")
}
KissCode::ServerAuthenticationFailed => write!(f, "Server authentication failed"),
KissCode::AutokeySequenceFailed => write!(f, "Autokey sequence failed"),
KissCode::CryptographicAuthenticationFailed => {
write!(f, "Cryptographic authentication or identification failed")
}
KissCode::AccessDenied => write!(f, "Access denied by remote server"),
KissCode::LostPeer => write!(f, "Lost peer in symmetric mode"),
KissCode::AssociationNotYetSynchronized => write!(
f,
"The association has not yet synchronized for the first time"
),
KissCode::NoKeyFound => write!(
f,
"No key found. Either the key was never installed or is not trusted"
),
KissCode::RateExceeded => write!(f, "Rate exceeded. The server has temporarily denied access because the client exceeded the rate threshold"),
KissCode::TinkeringWithAssociation => write!(f, "Somebody is tinkering with the association from a remote host"),
KissCode::StepChange => write!(f, " step change in system time has occurred, but the association has not yet resynchronized"),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ProtocolError {
PacketIsTooShort,
InvalidPacketVersion,
InvalidLeapIndicator,
InvalidMode,
InvalidOriginateTimestamp,
InvalidTransmitTimestamp,
InvalidReferenceIdentifier,
KissODeath(KissCode),
}
impl Error for ProtocolError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
impl Display for ProtocolError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProtocolError::PacketIsTooShort => write!(f, "Server reply packet is too short"),
ProtocolError::InvalidPacketVersion => {
write!(f, "Server reply packet has unsupported version")
}
ProtocolError::InvalidLeapIndicator => {
write!(f, "Server reply packet contains invalid leap indicator")
}
ProtocolError::InvalidMode => write!(f, "Server reply packet contains invalid mode"),
ProtocolError::InvalidOriginateTimestamp => {
write!(f, "Server reply contains invalid originate timestamp")
}
ProtocolError::InvalidTransmitTimestamp => {
write!(f, "Server reply contains invalid transmit timestamp")
}
ProtocolError::InvalidReferenceIdentifier => {
write!(f, "Server reply contains invalid reference identifier")
}
ProtocolError::KissODeath(code) => {
write!(f, "Kiss-o'-Death packet received: {code}")
}
}
}
}
#[derive(Debug)]
pub enum SynchronizationError {
IOError(std::io::Error),
ProtocolError(ProtocolError),
}
impl Error for SynchronizationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
SynchronizationError::IOError(io_error) => Some(io_error),
SynchronizationError::ProtocolError(protocol_error) => Some(protocol_error),
}
}
}
impl Display for SynchronizationError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SynchronizationError::IOError(io_error) => {
write!(f, "Input/output error: {io_error}")
}
SynchronizationError::ProtocolError(protocol_error) => {
write!(f, "Protocol error: {protocol_error}")
}
}
}
}
impl From<std::io::Error> for SynchronizationError {
fn from(io_error: std::io::Error) -> SynchronizationError {
SynchronizationError::IOError(io_error)
}
}
impl From<ProtocolError> for SynchronizationError {
fn from(protocol_error: ProtocolError) -> SynchronizationError {
SynchronizationError::ProtocolError(protocol_error)
}
}
impl SynchronizationError {
pub fn is_kiss_of_death(&self) -> bool {
matches!(
self,
SynchronizationError::ProtocolError(ProtocolError::KissODeath(_))
)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ConversionError {
Overflow,
}
impl Error for ConversionError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
impl Display for ConversionError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Overflow during timestamp conversion")
}
}