use std::fmt;
use std::net::IpAddr;
use std::sync::mpsc;
use std::time::Duration;
use rns_core::announce::ValidatedAnnounce;
use rns_core::transport::announce_verify_queue::AnnounceVerifyKey;
use rns_core::transport::types::{InterfaceId, InterfaceInfo};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HolePunchPolicy {
Reject,
AcceptAll,
AskApp,
}
impl Default for HolePunchPolicy {
fn default() -> Self {
HolePunchPolicy::AcceptAll
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum RuntimeConfigValue {
Int(i64),
Float(f64),
Bool(bool),
String(String),
Null,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeConfigSource {
Startup,
RuntimeOverride,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeConfigApplyMode {
Immediate,
NewConnectionsOnly,
NextReconnect,
RestartRequired,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RuntimeConfigEntry {
pub key: String,
pub value: RuntimeConfigValue,
pub default: RuntimeConfigValue,
pub source: RuntimeConfigSource,
pub apply_mode: RuntimeConfigApplyMode,
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuntimeConfigError {
pub code: RuntimeConfigErrorCode,
pub message: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeConfigErrorCode {
UnknownKey,
InvalidType,
InvalidValue,
Unsupported,
NotFound,
ApplyFailed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LifecycleState {
Active,
Draining,
Stopping,
Stopped,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DrainStatus {
pub state: LifecycleState,
pub drain_age_seconds: Option<f64>,
pub deadline_remaining_seconds: Option<f64>,
pub drain_complete: bool,
pub interface_writer_queued_frames: usize,
pub provider_backlog_events: usize,
pub provider_consumer_queued_events: usize,
pub detail: Option<String>,
}
pub enum Event<W: Send> {
Frame {
interface_id: InterfaceId,
data: Vec<u8>,
},
AnnounceVerified {
key: AnnounceVerifyKey,
validated: ValidatedAnnounce,
sig_cache_key: [u8; 32],
},
AnnounceVerifyFailed {
key: AnnounceVerifyKey,
sig_cache_key: [u8; 32],
},
InterfaceUp(InterfaceId, Option<W>, Option<InterfaceInfo>),
InterfaceDown(InterfaceId),
Tick,
BeginDrain { timeout: Duration },
Shutdown,
SendOutbound {
raw: Vec<u8>,
dest_type: u8,
attached_interface: Option<InterfaceId>,
},
RegisterDestination { dest_hash: [u8; 16], dest_type: u8 },
StoreSharedAnnounce {
dest_hash: [u8; 16],
name_hash: [u8; 10],
identity_prv_key: [u8; 64],
app_data: Option<Vec<u8>>,
},
DeregisterDestination { dest_hash: [u8; 16] },
DeregisterLinkDestination { dest_hash: [u8; 16] },
Query(QueryRequest, mpsc::Sender<QueryResponse>),
RegisterLinkDestination {
dest_hash: [u8; 16],
sig_prv_bytes: [u8; 32],
sig_pub_bytes: [u8; 32],
resource_strategy: u8,
},
RegisterRequestHandler {
path: String,
allowed_list: Option<Vec<[u8; 16]>>,
handler: Box<
dyn Fn([u8; 16], &str, &[u8], Option<&([u8; 16], [u8; 64])>) -> Option<Vec<u8>> + Send,
>,
},
CreateLink {
dest_hash: [u8; 16],
dest_sig_pub_bytes: [u8; 32],
response_tx: mpsc::Sender<[u8; 16]>,
},
SendRequest {
link_id: [u8; 16],
path: String,
data: Vec<u8>,
},
IdentifyOnLink {
link_id: [u8; 16],
identity_prv_key: [u8; 64],
},
TeardownLink { link_id: [u8; 16] },
SendResource {
link_id: [u8; 16],
data: Vec<u8>,
metadata: Option<Vec<u8>>,
},
SetResourceStrategy { link_id: [u8; 16], strategy: u8 },
AcceptResource {
link_id: [u8; 16],
resource_hash: Vec<u8>,
accept: bool,
},
SendChannelMessage {
link_id: [u8; 16],
msgtype: u16,
payload: Vec<u8>,
response_tx: mpsc::Sender<Result<(), String>>,
},
SendOnLink {
link_id: [u8; 16],
data: Vec<u8>,
context: u8,
},
RequestPath { dest_hash: [u8; 16] },
RegisterProofStrategy {
dest_hash: [u8; 16],
strategy: rns_core::types::ProofStrategy,
signing_key: Option<[u8; 64]>,
},
ProposeDirectConnect { link_id: [u8; 16] },
SetDirectConnectPolicy { policy: HolePunchPolicy },
HolePunchProbeResult {
link_id: [u8; 16],
session_id: [u8; 16],
observed_addr: std::net::SocketAddr,
socket: std::net::UdpSocket,
probe_server: std::net::SocketAddr,
},
HolePunchProbeFailed {
link_id: [u8; 16],
session_id: [u8; 16],
},
InterfaceConfigChanged(InterfaceId),
BackbonePeerConnected {
server_interface_id: InterfaceId,
peer_interface_id: InterfaceId,
peer_ip: IpAddr,
peer_port: u16,
},
BackbonePeerDisconnected {
server_interface_id: InterfaceId,
peer_interface_id: InterfaceId,
peer_ip: IpAddr,
peer_port: u16,
connected_for: Duration,
had_received_data: bool,
},
BackbonePeerIdleTimeout {
server_interface_id: InterfaceId,
peer_interface_id: InterfaceId,
peer_ip: IpAddr,
peer_port: u16,
connected_for: Duration,
},
BackbonePeerWriteStall {
server_interface_id: InterfaceId,
peer_interface_id: InterfaceId,
peer_ip: IpAddr,
peer_port: u16,
connected_for: Duration,
},
BackbonePeerPenalty {
server_interface_id: InterfaceId,
peer_ip: IpAddr,
penalty_level: u8,
blacklist_for: Duration,
},
LoadHook {
name: String,
wasm_bytes: Vec<u8>,
attach_point: String,
priority: i32,
response_tx: mpsc::Sender<Result<(), String>>,
},
UnloadHook {
name: String,
attach_point: String,
response_tx: mpsc::Sender<Result<(), String>>,
},
ReloadHook {
name: String,
attach_point: String,
wasm_bytes: Vec<u8>,
response_tx: mpsc::Sender<Result<(), String>>,
},
SetHookEnabled {
name: String,
attach_point: String,
enabled: bool,
response_tx: mpsc::Sender<Result<(), String>>,
},
SetHookPriority {
name: String,
attach_point: String,
priority: i32,
response_tx: mpsc::Sender<Result<(), String>>,
},
ListHooks {
response_tx: mpsc::Sender<Vec<HookInfo>>,
},
}
#[derive(Debug, Clone)]
pub struct HookInfo {
pub name: String,
pub attach_point: String,
pub priority: i32,
pub enabled: bool,
pub consecutive_traps: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct BackbonePeerStateEntry {
pub interface_name: String,
pub peer_ip: IpAddr,
pub connected_count: usize,
pub blacklisted_remaining_secs: Option<f64>,
pub blacklist_reason: Option<String>,
pub reject_count: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackbonePeerHookEvent {
pub server_interface_id: InterfaceId,
pub peer_interface_id: Option<InterfaceId>,
pub peer_ip: IpAddr,
pub peer_port: u16,
pub connected_for: Duration,
pub had_received_data: bool,
pub penalty_level: u8,
pub blacklist_for: Duration,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackboneInterfaceEntry {
pub interface_id: InterfaceId,
pub interface_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProviderBridgeConsumerStats {
pub id: u64,
pub connected: bool,
pub queue_len: usize,
pub queued_bytes: usize,
pub dropped_pending: u64,
pub dropped_total: u64,
pub queue_max_events: usize,
pub queue_max_bytes: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProviderBridgeStats {
pub connected: bool,
pub consumer_count: usize,
pub queue_max_events: usize,
pub queue_max_bytes: usize,
pub backlog_len: usize,
pub backlog_bytes: usize,
pub backlog_dropped_pending: u64,
pub backlog_dropped_total: u64,
pub total_disconnect_count: u64,
pub consumers: Vec<ProviderBridgeConsumerStats>,
}
#[derive(Debug)]
pub enum QueryRequest {
InterfaceStats,
PathTable { max_hops: Option<u8> },
RateTable,
NextHop { dest_hash: [u8; 16] },
NextHopIfName { dest_hash: [u8; 16] },
LinkCount,
DropPath { dest_hash: [u8; 16] },
DropAllVia { transport_hash: [u8; 16] },
DropAnnounceQueues,
TransportIdentity,
GetBlackholed,
BlackholeIdentity {
identity_hash: [u8; 16],
duration_hours: Option<f64>,
reason: Option<String>,
},
UnblackholeIdentity { identity_hash: [u8; 16] },
HasPath { dest_hash: [u8; 16] },
HopsTo { dest_hash: [u8; 16] },
RecallIdentity { dest_hash: [u8; 16] },
LocalDestinations,
Links,
Resources,
InjectPath {
dest_hash: [u8; 16],
next_hop: [u8; 16],
hops: u8,
expires: f64,
interface_name: String,
packet_hash: [u8; 32],
},
InjectIdentity {
dest_hash: [u8; 16],
identity_hash: [u8; 16],
public_key: [u8; 64],
app_data: Option<Vec<u8>>,
hops: u8,
received_at: f64,
},
DiscoveredInterfaces {
only_available: bool,
only_transport: bool,
},
SendProbe {
dest_hash: [u8; 16],
payload_size: usize,
},
CheckProof { packet_hash: [u8; 32] },
ListRuntimeConfig,
GetRuntimeConfig { key: String },
SetRuntimeConfig {
key: String,
value: RuntimeConfigValue,
},
ResetRuntimeConfig { key: String },
BackbonePeerState { interface_name: Option<String> },
BackboneInterfaces,
ProviderBridgeStats,
DrainStatus,
ClearBackbonePeerState {
interface_name: String,
peer_ip: IpAddr,
},
BlacklistBackbonePeer {
interface_name: String,
peer_ip: IpAddr,
duration: Duration,
reason: String,
penalty_level: u8,
},
}
#[derive(Debug)]
pub enum QueryResponse {
InterfaceStats(InterfaceStatsResponse),
PathTable(Vec<PathTableEntry>),
RateTable(Vec<RateTableEntry>),
NextHop(Option<NextHopResponse>),
NextHopIfName(Option<String>),
LinkCount(usize),
DropPath(bool),
DropAllVia(usize),
DropAnnounceQueues,
TransportIdentity(Option<[u8; 16]>),
Blackholed(Vec<BlackholeInfo>),
BlackholeResult(bool),
UnblackholeResult(bool),
HasPath(bool),
HopsTo(Option<u8>),
RecallIdentity(Option<crate::common::destination::AnnouncedIdentity>),
LocalDestinations(Vec<LocalDestinationEntry>),
Links(Vec<LinkInfoEntry>),
Resources(Vec<ResourceInfoEntry>),
InjectPath(bool),
InjectIdentity(bool),
DiscoveredInterfaces(Vec<crate::common::discovery::DiscoveredInterface>),
SendProbe(Option<([u8; 32], u8)>),
CheckProof(Option<f64>),
RuntimeConfigList(Vec<RuntimeConfigEntry>),
RuntimeConfigEntry(Option<RuntimeConfigEntry>),
RuntimeConfigSet(Result<RuntimeConfigEntry, RuntimeConfigError>),
RuntimeConfigReset(Result<RuntimeConfigEntry, RuntimeConfigError>),
BackbonePeerState(Vec<BackbonePeerStateEntry>),
BackboneInterfaces(Vec<BackboneInterfaceEntry>),
ProviderBridgeStats(Option<ProviderBridgeStats>),
DrainStatus(DrainStatus),
ClearBackbonePeerState(bool),
BlacklistBackbonePeer(bool),
}
#[derive(Debug, Clone)]
pub struct InterfaceStatsResponse {
pub interfaces: Vec<SingleInterfaceStat>,
pub transport_id: Option<[u8; 16]>,
pub transport_enabled: bool,
pub transport_uptime: f64,
pub total_rxb: u64,
pub total_txb: u64,
pub probe_responder: Option<[u8; 16]>,
}
#[derive(Debug, Clone)]
pub struct SingleInterfaceStat {
pub id: u64,
pub name: String,
pub status: bool,
pub mode: u8,
pub rxb: u64,
pub txb: u64,
pub rx_packets: u64,
pub tx_packets: u64,
pub bitrate: Option<u64>,
pub ifac_size: Option<usize>,
pub started: f64,
pub ia_freq: f64,
pub oa_freq: f64,
pub interface_type: String,
}
#[derive(Debug, Clone)]
pub struct LocalDestinationEntry {
pub hash: [u8; 16],
pub dest_type: u8,
}
#[derive(Debug, Clone)]
pub struct LinkInfoEntry {
pub link_id: [u8; 16],
pub state: String,
pub is_initiator: bool,
pub dest_hash: [u8; 16],
pub remote_identity: Option<[u8; 16]>,
pub rtt: Option<f64>,
pub channel_window: Option<u16>,
pub channel_outstanding: Option<usize>,
pub pending_channel_packets: usize,
pub channel_send_ok: u64,
pub channel_send_not_ready: u64,
pub channel_send_too_big: u64,
pub channel_send_other_error: u64,
pub channel_messages_received: u64,
pub channel_proofs_sent: u64,
pub channel_proofs_received: u64,
}
#[derive(Debug, Clone)]
pub struct ResourceInfoEntry {
pub link_id: [u8; 16],
pub direction: String,
pub total_parts: usize,
pub transferred_parts: usize,
pub complete: bool,
}
#[derive(Debug, Clone)]
pub struct PathTableEntry {
pub hash: [u8; 16],
pub timestamp: f64,
pub via: [u8; 16],
pub hops: u8,
pub expires: f64,
pub interface: InterfaceId,
pub interface_name: String,
}
#[derive(Debug, Clone)]
pub struct RateTableEntry {
pub hash: [u8; 16],
pub last: f64,
pub rate_violations: u32,
pub blocked_until: f64,
pub timestamps: Vec<f64>,
}
#[derive(Debug, Clone)]
pub struct BlackholeInfo {
pub identity_hash: [u8; 16],
pub created: f64,
pub expires: f64,
pub reason: Option<String>,
}
#[derive(Debug, Clone)]
pub struct NextHopResponse {
pub next_hop: [u8; 16],
pub hops: u8,
pub interface: InterfaceId,
}
impl<W: Send> fmt::Debug for Event<W> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Event::Frame { interface_id, data } => f
.debug_struct("Frame")
.field("interface_id", interface_id)
.field("data_len", &data.len())
.finish(),
Event::AnnounceVerified { key, .. } => f
.debug_struct("AnnounceVerified")
.field("destination_hash", &key.destination_hash)
.field("received_from", &key.received_from)
.finish(),
Event::AnnounceVerifyFailed { key, .. } => f
.debug_struct("AnnounceVerifyFailed")
.field("destination_hash", &key.destination_hash)
.field("received_from", &key.received_from)
.finish(),
Event::InterfaceUp(id, writer, info) => f
.debug_tuple("InterfaceUp")
.field(id)
.field(&writer.is_some())
.field(&info.is_some())
.finish(),
Event::InterfaceDown(id) => f.debug_tuple("InterfaceDown").field(id).finish(),
Event::Tick => write!(f, "Tick"),
Event::BeginDrain { timeout } => f
.debug_struct("BeginDrain")
.field("timeout", timeout)
.finish(),
Event::Shutdown => write!(f, "Shutdown"),
Event::SendOutbound { raw, dest_type, .. } => f
.debug_struct("SendOutbound")
.field("raw_len", &raw.len())
.field("dest_type", dest_type)
.finish(),
Event::RegisterDestination {
dest_hash,
dest_type,
} => f
.debug_struct("RegisterDestination")
.field("dest_hash", dest_hash)
.field("dest_type", dest_type)
.finish(),
Event::StoreSharedAnnounce {
dest_hash,
name_hash,
app_data,
..
} => f
.debug_struct("StoreSharedAnnounce")
.field("dest_hash", dest_hash)
.field("name_hash", name_hash)
.field("app_data_len", &app_data.as_ref().map(|d| d.len()))
.finish(),
Event::DeregisterDestination { dest_hash } => f
.debug_struct("DeregisterDestination")
.field("dest_hash", dest_hash)
.finish(),
Event::DeregisterLinkDestination { dest_hash } => f
.debug_struct("DeregisterLinkDestination")
.field("dest_hash", dest_hash)
.finish(),
Event::Query(req, _) => f.debug_tuple("Query").field(req).finish(),
Event::RegisterLinkDestination { dest_hash, .. } => f
.debug_struct("RegisterLinkDestination")
.field("dest_hash", dest_hash)
.finish(),
Event::RegisterRequestHandler { path, .. } => f
.debug_struct("RegisterRequestHandler")
.field("path", path)
.finish(),
Event::CreateLink { dest_hash, .. } => f
.debug_struct("CreateLink")
.field("dest_hash", dest_hash)
.finish(),
Event::SendRequest { link_id, path, .. } => f
.debug_struct("SendRequest")
.field("link_id", link_id)
.field("path", path)
.finish(),
Event::IdentifyOnLink { link_id, .. } => f
.debug_struct("IdentifyOnLink")
.field("link_id", link_id)
.finish(),
Event::TeardownLink { link_id } => f
.debug_struct("TeardownLink")
.field("link_id", link_id)
.finish(),
Event::SendResource { link_id, data, .. } => f
.debug_struct("SendResource")
.field("link_id", link_id)
.field("data_len", &data.len())
.finish(),
Event::SetResourceStrategy { link_id, strategy } => f
.debug_struct("SetResourceStrategy")
.field("link_id", link_id)
.field("strategy", strategy)
.finish(),
Event::AcceptResource {
link_id, accept, ..
} => f
.debug_struct("AcceptResource")
.field("link_id", link_id)
.field("accept", accept)
.finish(),
Event::SendChannelMessage {
link_id,
msgtype,
payload,
..
} => f
.debug_struct("SendChannelMessage")
.field("link_id", link_id)
.field("msgtype", msgtype)
.field("payload_len", &payload.len())
.finish(),
Event::SendOnLink {
link_id,
data,
context,
} => f
.debug_struct("SendOnLink")
.field("link_id", link_id)
.field("data_len", &data.len())
.field("context", context)
.finish(),
Event::RequestPath { dest_hash } => f
.debug_struct("RequestPath")
.field("dest_hash", dest_hash)
.finish(),
Event::RegisterProofStrategy {
dest_hash,
strategy,
..
} => f
.debug_struct("RegisterProofStrategy")
.field("dest_hash", dest_hash)
.field("strategy", strategy)
.finish(),
Event::ProposeDirectConnect { link_id } => f
.debug_struct("ProposeDirectConnect")
.field("link_id", link_id)
.finish(),
Event::SetDirectConnectPolicy { .. } => {
write!(f, "SetDirectConnectPolicy")
}
Event::HolePunchProbeResult {
link_id,
session_id,
observed_addr,
probe_server,
..
} => f
.debug_struct("HolePunchProbeResult")
.field("link_id", link_id)
.field("session_id", session_id)
.field("observed_addr", observed_addr)
.field("probe_server", probe_server)
.finish(),
Event::HolePunchProbeFailed {
link_id,
session_id,
} => f
.debug_struct("HolePunchProbeFailed")
.field("link_id", link_id)
.field("session_id", session_id)
.finish(),
Event::InterfaceConfigChanged(id) => {
f.debug_tuple("InterfaceConfigChanged").field(id).finish()
}
Event::BackbonePeerConnected {
server_interface_id,
peer_interface_id,
peer_ip,
peer_port,
} => f
.debug_struct("BackbonePeerConnected")
.field("server_interface_id", server_interface_id)
.field("peer_interface_id", peer_interface_id)
.field("peer_ip", peer_ip)
.field("peer_port", peer_port)
.finish(),
Event::BackbonePeerDisconnected {
server_interface_id,
peer_interface_id,
peer_ip,
peer_port,
connected_for,
had_received_data,
} => f
.debug_struct("BackbonePeerDisconnected")
.field("server_interface_id", server_interface_id)
.field("peer_interface_id", peer_interface_id)
.field("peer_ip", peer_ip)
.field("peer_port", peer_port)
.field("connected_for", connected_for)
.field("had_received_data", had_received_data)
.finish(),
Event::BackbonePeerIdleTimeout {
server_interface_id,
peer_interface_id,
peer_ip,
peer_port,
connected_for,
} => f
.debug_struct("BackbonePeerIdleTimeout")
.field("server_interface_id", server_interface_id)
.field("peer_interface_id", peer_interface_id)
.field("peer_ip", peer_ip)
.field("peer_port", peer_port)
.field("connected_for", connected_for)
.finish(),
Event::BackbonePeerWriteStall {
server_interface_id,
peer_interface_id,
peer_ip,
peer_port,
connected_for,
} => f
.debug_struct("BackbonePeerWriteStall")
.field("server_interface_id", server_interface_id)
.field("peer_interface_id", peer_interface_id)
.field("peer_ip", peer_ip)
.field("peer_port", peer_port)
.field("connected_for", connected_for)
.finish(),
Event::BackbonePeerPenalty {
server_interface_id,
peer_ip,
penalty_level,
blacklist_for,
} => f
.debug_struct("BackbonePeerPenalty")
.field("server_interface_id", server_interface_id)
.field("peer_ip", peer_ip)
.field("penalty_level", penalty_level)
.field("blacklist_for", blacklist_for)
.finish(),
Event::LoadHook {
name,
attach_point,
priority,
..
} => f
.debug_struct("LoadHook")
.field("name", name)
.field("attach_point", attach_point)
.field("priority", priority)
.finish(),
Event::UnloadHook {
name, attach_point, ..
} => f
.debug_struct("UnloadHook")
.field("name", name)
.field("attach_point", attach_point)
.finish(),
Event::ReloadHook {
name, attach_point, ..
} => f
.debug_struct("ReloadHook")
.field("name", name)
.field("attach_point", attach_point)
.finish(),
Event::SetHookEnabled {
name,
attach_point,
enabled,
..
} => f
.debug_struct("SetHookEnabled")
.field("name", name)
.field("attach_point", attach_point)
.field("enabled", enabled)
.finish(),
Event::SetHookPriority {
name,
attach_point,
priority,
..
} => f
.debug_struct("SetHookPriority")
.field("name", name)
.field("attach_point", attach_point)
.field("priority", priority)
.finish(),
Event::ListHooks { .. } => write!(f, "ListHooks"),
}
}
}