use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum ProtocolType {
HTTP1_0,
HTTP1_1,
HTTP2,
HTTP3,
GRPC,
WebSocket,
QUIC,
MQTT,
TCP,
UDP,
TLS,
SSH,
FTP,
SMTP,
DNS,
Redis,
MySQL,
Custom,
Unknown,
}
impl fmt::Display for ProtocolType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::HTTP1_0 => write!(f, "HTTP/1.0"),
Self::HTTP1_1 => write!(f, "HTTP/1.1"),
Self::HTTP2 => write!(f, "HTTP/2"),
Self::HTTP3 => write!(f, "HTTP/3"),
Self::GRPC => write!(f, "gRPC"),
Self::WebSocket => write!(f, "WebSocket"),
Self::QUIC => write!(f, "QUIC"),
Self::MQTT => write!(f, "MQTT"),
Self::TCP => write!(f, "TCP"),
Self::UDP => write!(f, "UDP"),
Self::TLS => write!(f, "TLS"),
Self::SSH => write!(f, "SSH"),
Self::FTP => write!(f, "FTP"),
Self::SMTP => write!(f, "SMTP"),
Self::DNS => write!(f, "DNS"),
Self::Redis => write!(f, "Redis"),
Self::MySQL => write!(f, "MySQL"),
Self::Custom => write!(f, "Custom"),
Self::Unknown => write!(f, "Unknown"),
}
}
}
impl ProtocolType {
pub fn default_port(&self) -> Option<u16> {
match self {
Self::HTTP1_0 | Self::HTTP1_1 => Some(80),
Self::HTTP2 | Self::HTTP3 => Some(443),
Self::GRPC => Some(443),
Self::WebSocket => Some(80),
Self::QUIC => Some(443),
Self::MQTT => Some(1883),
Self::TLS => Some(443),
Self::SSH => Some(22),
Self::FTP => Some(21),
Self::SMTP => Some(25),
Self::DNS => Some(53),
Self::Redis => Some(6379),
Self::MySQL => Some(3306),
Self::TCP | Self::UDP | Self::Custom | Self::Unknown => None,
}
}
pub fn is_http_based(&self) -> bool {
matches!(
self,
Self::HTTP1_0
| Self::HTTP1_1
| Self::HTTP2
| Self::HTTP3
| Self::GRPC
| Self::WebSocket
)
}
pub fn supports_upgrade(&self) -> bool {
matches!(
self,
Self::HTTP1_0 | Self::HTTP1_1 | Self::HTTP2 | Self::TCP | Self::UDP
)
}
pub fn is_encrypted(&self) -> bool {
matches!(
self,
Self::HTTP2 | Self::HTTP3 | Self::GRPC | Self::QUIC | Self::TLS | Self::SSH
)
}
pub fn protocol_family(&self) -> ProtocolFamily {
match self {
Self::HTTP1_0 | Self::HTTP1_1 | Self::HTTP2 | Self::HTTP3 => ProtocolFamily::HTTP,
Self::GRPC => ProtocolFamily::RPC,
Self::WebSocket => ProtocolFamily::WebSocket,
Self::QUIC => ProtocolFamily::QUIC,
Self::MQTT => ProtocolFamily::IoT,
Self::TCP | Self::UDP => ProtocolFamily::Transport,
Self::TLS => ProtocolFamily::Security,
Self::SSH => ProtocolFamily::Remote,
Self::FTP | Self::SMTP | Self::DNS | Self::Redis | Self::MySQL => ProtocolFamily::Transport,
Self::Custom => ProtocolFamily::Unknown,
Self::Unknown => ProtocolFamily::Unknown,
}
}
pub fn all() -> Vec<ProtocolType> {
vec![
Self::HTTP1_0,
Self::HTTP1_1,
Self::HTTP2,
Self::HTTP3,
Self::GRPC,
Self::WebSocket,
Self::QUIC,
Self::MQTT,
Self::TCP,
Self::UDP,
Self::TLS,
Self::SSH,
Self::FTP,
Self::SMTP,
Self::DNS,
Self::Redis,
Self::MySQL,
Self::Custom,
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ProtocolFamily {
HTTP,
RPC,
WebSocket,
QUIC,
IoT,
Transport,
Security,
Remote,
Unknown,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProtocolInfo {
pub protocol_type: ProtocolType,
pub version: Option<String>,
pub confidence: f32,
pub features: Vec<String>,
pub metadata: std::collections::HashMap<String, String>,
}
impl ProtocolInfo {
pub fn new(protocol_type: ProtocolType, confidence: f32) -> Self {
Self {
protocol_type,
version: None,
confidence: confidence.clamp(0.0, 1.0),
features: Vec::new(),
metadata: std::collections::HashMap::new(),
}
}
pub fn with_version<S: Into<String>>(mut self, version: S) -> Self {
self.version = Some(version.into());
self
}
pub fn add_feature<S: Into<String>>(&mut self, feature: S) {
self.features.push(feature.into());
}
pub fn add_metadata<K, V>(&mut self, key: K, value: V)
where
K: Into<String>,
V: Into<String>,
{
self.metadata.insert(key.into(), value.into());
}
pub fn is_confident(&self, threshold: f32) -> bool {
self.confidence >= threshold
}
pub fn has_feature(&self, feature: &str) -> bool {
self.features.iter().any(|f| f == feature)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UpgradePath {
pub from: ProtocolType,
pub to: ProtocolType,
pub method: UpgradeMethod,
pub required_headers: Vec<String>,
pub optional_headers: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum UpgradeMethod {
HttpUpgrade,
ALPN,
Direct,
Tunnel,
Negotiation,
Custom(String),
}
impl UpgradePath {
pub fn new(from: ProtocolType, to: ProtocolType, method: UpgradeMethod) -> Self {
Self {
from,
to,
method,
required_headers: Vec::new(),
optional_headers: Vec::new(),
}
}
pub fn common_paths() -> Vec<UpgradePath> {
vec![
UpgradePath::new(
ProtocolType::HTTP1_1,
ProtocolType::HTTP2,
UpgradeMethod::HttpUpgrade,
),
UpgradePath::new(
ProtocolType::HTTP2,
ProtocolType::GRPC,
UpgradeMethod::Direct,
),
UpgradePath::new(
ProtocolType::HTTP1_1,
ProtocolType::WebSocket,
UpgradeMethod::HttpUpgrade,
),
UpgradePath::new(
ProtocolType::TCP,
ProtocolType::TLS,
UpgradeMethod::Direct,
),
]
}
}