1use std::net::SocketAddr;
2use serde::{Deserialize, Serialize};
3use ulid::Ulid;
4use url::Url;
5use crate::sessions::Headers;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct ConnectContext {
11 pub session_id: Ulid,
12 pub target_addr: TargetAddress,
13 pub client_addr: SocketAddr,
14 pub process: Option<ProcessInfo>,
15 pub request: ConnectRequest,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20#[serde(rename_all = "camelCase")]
21pub struct TargetAddress {
22 pub host: String,
23 pub port: u16,
24}
25
26impl TargetAddress {
27 pub fn new(host: impl Into<String>, port: u16) -> Self {
28 Self { host: host.into(), port }
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct ProcessInfo {
36 pub pid: u32,
37 pub name: Option<String>,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct Socks4Request {
43 pub user_id: String,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47#[serde(rename_all = "camelCase")]
48pub struct HttpConnectRequest {
49 pub target: String,
50 pub http_version: String,
51 pub headers: Headers,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct HttpDirectRequest {
57 pub method: String,
58 pub path: String,
59 pub http_version: String,
60 pub headers: Headers,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct HttpProxyRequest {
66 pub method: String,
67 pub url: Url,
68 pub http_version: String,
69 pub headers: Headers,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74#[serde(tag = "type", rename_all = "snake_case")]
75pub enum ConnectRequest {
76 #[serde(rename = "socks4")]
77 Socks4(Socks4Request),
78 #[serde(rename = "socks5")]
79 Socks5,
80 HttpConnect(HttpConnectRequest),
81 TlsSni,
82 HttpDirect(HttpDirectRequest),
83 HttpProxy(HttpProxyRequest),
84}
85
86#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct AcceptOptions {
92 pub target_addr: Option<TargetAddress>,
93 pub proxy: Option<Proxy>,
94 pub record: Option<bool>,
95 pub intercept_tls: Option<bool>,
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106#[serde(tag = "type", rename_all = "snake_case")]
107pub enum ConnectResult {
108 Accept(AcceptOptions),
109 Reject,
110}
111
112impl ConnectResult {
113 pub fn accept() -> Self {
115 ConnectResult::Accept(AcceptOptions::default())
116 }
117
118 pub fn use_proxy(proxy: Option<Proxy>) -> Self {
120 ConnectResult::Accept(
121 AcceptOptions { proxy, ..Default::default() }
122 )
123 }
124
125 pub fn reject() -> Self {
127 ConnectResult::Reject
128 }
129}
130
131impl From<AcceptOptions> for ConnectResult {
132 fn from(accept: AcceptOptions) -> Self {
133 ConnectResult::Accept(accept)
134 }
135}
136
137#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
139#[serde(rename_all = "lowercase")]
140pub enum ProxyType {
141 #[default]
142 Http,
143 Https,
144 Socks4,
145 Socks4a,
146 Socks5,
147 Socks5h,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
155#[serde(rename_all = "camelCase")]
156pub struct Proxy {
157 proxy_type: ProxyType,
158 host: String,
159 port: u16,
160 username: Option<String>,
161 password: Option<String>,
162}
163
164impl Proxy {
165 pub fn http(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
166 Self {
167 proxy_type: ProxyType::Http,
168 host: host.into(),
169 port,
170 username,
171 password
172 }
173 }
174
175 pub fn https(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
176 Self {
177 proxy_type: ProxyType::Https,
178 host: host.into(),
179 port,
180 username,
181 password
182 }
183 }
184
185 pub fn socks4(host: String, port: u16, user_id: Option<String>) -> Self {
186 Self {
187 proxy_type: ProxyType::Socks4,
188 host: host.into(),
189 port,
190 username: user_id,
191 password: None
192 }
193 }
194
195 pub fn socks4a(host: String, port: u16, user_id: Option<String>) -> Self {
196 Self {
197 proxy_type: ProxyType::Socks4a,
198 host: host.into(),
199 port,
200 username: user_id,
201 password: None
202 }
203 }
204
205 pub fn socks5(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
206 Self {
207 proxy_type: ProxyType::Socks5,
208 host: host.into(),
209 port,
210 username,
211 password
212 }
213 }
214
215 pub fn socks5h(host: String, port: u16, username: Option<String>, password: Option<String>) -> Self {
216 Self {
217 proxy_type: ProxyType::Socks5h,
218 host: host.into(),
219 port,
220 username,
221 password
222 }
223 }
224}