use std::net::SocketAddr;
use serde::{Deserialize, Serialize};
use ulid::Ulid;
use url::Url;
use crate::sessions::Headers;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectContext {
pub session_id: Ulid,
pub target_addr: TargetAddress,
pub client_addr: SocketAddr,
pub process: Option<ProcessInfo>,
pub request: ConnectRequest,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TargetAddress {
pub host: String,
pub port: u16,
}
impl TargetAddress {
pub fn new(host: impl Into<String>, port: u16) -> Self {
Self { host: host.into(), port }
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProcessInfo {
pub pid: u32,
pub name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Socks4Request {
pub user_id: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HttpConnectRequest {
pub target: String,
pub http_version: String,
pub headers: Headers,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HttpDirectRequest {
pub method: String,
pub path: String,
pub http_version: String,
pub headers: Headers,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HttpProxyRequest {
pub method: String,
pub url: Url,
pub http_version: String,
pub headers: Headers,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ConnectRequest {
#[serde(rename = "socks4")]
Socks4(Socks4Request),
#[serde(rename = "socks5")]
Socks5,
HttpConnect(HttpConnectRequest),
TlsSni,
HttpDirect(HttpDirectRequest),
HttpProxy(HttpProxyRequest),
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AcceptOptions {
pub target_addr: Option<TargetAddress>,
pub proxy: Option<Proxy>,
pub record: Option<bool>,
pub intercept_tls: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ConnectResult {
Accept(AcceptOptions),
Reject,
}
impl ConnectResult {
pub fn accept() -> Self {
ConnectResult::Accept(AcceptOptions::default())
}
pub fn use_proxy(proxy: Option<Proxy>) -> Self {
ConnectResult::Accept(
AcceptOptions { proxy, ..Default::default() }
)
}
pub fn reject() -> Self {
ConnectResult::Reject
}
}
impl From<AcceptOptions> for ConnectResult {
fn from(accept: AcceptOptions) -> Self {
ConnectResult::Accept(accept)
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ProxyType {
#[default]
Http,
Https,
Socks4,
Socks4a,
Socks5,
Socks5h,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Proxy {
proxy_type: ProxyType,
host: String,
port: u16,
username: Option<String>,
password: Option<String>,
}
impl Proxy {
pub fn http(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
Self {
proxy_type: ProxyType::Http,
host: host.into(),
port,
username,
password
}
}
pub fn https(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
Self {
proxy_type: ProxyType::Https,
host: host.into(),
port,
username,
password
}
}
pub fn socks4(host: String, port: u16, user_id: Option<String>) -> Self {
Self {
proxy_type: ProxyType::Socks4,
host: host.into(),
port,
username: user_id,
password: None
}
}
pub fn socks4a(host: String, port: u16, user_id: Option<String>) -> Self {
Self {
proxy_type: ProxyType::Socks4a,
host: host.into(),
port,
username: user_id,
password: None
}
}
pub fn socks5(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
Self {
proxy_type: ProxyType::Socks5,
host: host.into(),
port,
username,
password
}
}
pub fn socks5h(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
Self {
proxy_type: ProxyType::Socks5h,
host: host.into(),
port,
username,
password
}
}
}