use crate::core::types::Transport;
use memchr::memmem;
#[cfg(feature = "proto-dns")]
pub mod dns;
#[cfg(feature = "proto-ftp")]
pub mod ftp;
#[cfg(feature = "proto-http")]
pub mod http;
#[cfg(feature = "proto-https")]
pub mod https;
#[cfg(feature = "proto-ssh")]
pub mod ssh;
#[cfg(feature = "hooks")]
pub mod hooks;
#[cfg(feature = "hooks")]
use std::sync::Arc;
#[cfg(not(feature = "hooks"))]
use std::sync::Arc;
#[cfg(feature = "hooks")]
use crate::protocols::hooks::ProtocolHook;
pub struct ProtocolMatch {
pub name: String,
pub metadata: Option<String>,
pub implementation: Arc<dyn RefractiumProtocol>,
}
pub trait RefractiumProtocol: Send + Sync + dyn_clone::DynClone {
fn name(&self) -> &str;
fn identify(self: Arc<Self>, data: &[u8]) -> Option<ProtocolMatch>;
fn transport(&self) -> Transport;
#[cfg(feature = "hooks")]
fn hooks(&self) -> Vec<Arc<dyn ProtocolHook>> {
Vec::new()
}
}
dyn_clone::clone_trait_object!(RefractiumProtocol);
#[derive(Clone)]
pub struct DynamicProtocol {
pub name: String,
pub patterns: Vec<String>,
}
impl RefractiumProtocol for DynamicProtocol {
fn identify(self: Arc<Self>, data: &[u8]) -> Option<ProtocolMatch> {
let matched = self
.patterns
.iter()
.any(|p| memmem::find(data, p.as_bytes()).is_some());
if matched {
return Some(ProtocolMatch {
name: self.name.to_lowercase(),
metadata: None,
implementation: self,
});
}
None
}
fn name(&self) -> &str {
&self.name
}
fn transport(&self) -> Transport {
Transport::Both
}
}
pub struct ProtocolRegistry {
protocols: Vec<Arc<dyn RefractiumProtocol>>,
}
impl Default for ProtocolRegistry {
fn default() -> Self {
Self::new()
}
}
impl ProtocolRegistry {
#[must_use]
pub fn new() -> Self {
Self {
protocols: Vec::new(),
}
}
pub fn register(&mut self, proto: Arc<dyn RefractiumProtocol>) {
self.protocols.push(proto);
}
#[must_use]
pub fn probe(&self, data: &[u8]) -> Option<ProtocolMatch> {
for proto in &self.protocols {
if let Some(m) = Arc::clone(proto).identify(data) {
return Some(m);
}
}
None
}
}