1use rkyv::{Archive, Deserialize, Serialize};
5
6#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq)]
12#[rkyv(compare(PartialEq), derive(Debug))]
13pub struct ProxyFrame {
14 pub conn_id: u64,
16
17 pub rip: [u8; 16],
19
20 pub rport: u16,
22
23 pub payload: Vec<u8>,
25
26 pub uuid: [u8; 16],
28
29 pub timestamp: u64,
31
32 pub checksum: u32,
34
35 pub flags: FrameFlags,
37}
38
39#[derive(Archive, Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq)]
41#[rkyv(compare(PartialEq), derive(Debug))]
42pub struct FrameFlags {
43 pub is_control: bool,
45
46 pub is_compressed: bool,
48
49 pub is_final: bool,
51
52 pub needs_ack: bool,
54
55 pub is_ack: bool,
57}
58
59impl ProxyFrame {
60 pub fn new_data(conn_id: u64, rip: [u8; 16], rport: u16, payload: Vec<u8>) -> Self {
62 let checksum = crc32fast::hash(&payload);
63 let uuid = uuid::Uuid::new_v4().into_bytes();
64 let timestamp = std::time::SystemTime::now()
65 .duration_since(std::time::UNIX_EPOCH)
66 .unwrap()
67 .as_millis() as u64;
68
69 Self {
70 conn_id,
71 rip,
72 rport,
73 payload,
74 uuid,
75 timestamp,
76 checksum,
77 flags: FrameFlags::default(),
78 }
79 }
80
81 pub fn new_control(payload: Vec<u8>) -> Self {
83 let mut frame = Self::new_data(0, [0; 16], 0, payload);
84 frame.flags.is_control = true;
85 frame
86 }
87
88 pub fn new_close(conn_id: u64) -> Self {
90 let mut frame = Self::new_data(conn_id, [0; 16], 0, vec![]);
91 frame.flags.is_final = true;
92 frame
93 }
94
95 pub fn verify_checksum(&self) -> bool {
97 crc32fast::hash(&self.payload) == self.checksum
98 }
99
100 pub fn ipv4_to_mapped(ipv4: [u8; 4]) -> [u8; 16] {
102 let mut mapped = [0u8; 16];
103 mapped[10] = 0xff;
104 mapped[11] = 0xff;
105 mapped[12..16].copy_from_slice(&ipv4);
106 mapped
107 }
108
109 pub fn mapped_to_ipv4(mapped: &[u8; 16]) -> Option<[u8; 4]> {
111 if mapped[..10] == [0; 10] && mapped[10] == 0xff && mapped[11] == 0xff {
112 let mut ipv4 = [0u8; 4];
113 ipv4.copy_from_slice(&mapped[12..16]);
114 Some(ipv4)
115 } else {
116 None
117 }
118 }
119}
120
121#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq)]
123#[rkyv(compare(PartialEq), derive(Debug))]
124pub enum ControlMessage {
125 DohQuery { query: Vec<u8> },
127
128 DohResponse { response: Vec<u8> },
130
131 Ping { nonce: u64 },
133
134 Pong { nonce: u64 },
136
137 KeyRotation {
139 new_pk: [u8; 32],
140 valid_from: u64,
141 valid_until: u64,
142 },
143
144 Emergency {
146 level: EmergencyLevel,
147 trigger_after: u64,
148 },
149}
150
151#[derive(Archive, Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
153#[rkyv(compare(PartialEq), derive(Debug))]
154pub enum EmergencyLevel {
155 Warning,
157 Stop,
159 Shutdown,
161}
162
163#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq)]
167#[rkyv(compare(PartialEq), derive(Debug))]
168pub struct PlainPacket {
169 pub magic: u32,
171
172 pub conn_id: u64,
174
175 pub handler_id: u64,
177
178 pub rip: [u8; 16],
180
181 pub rport: u16,
183
184 pub payload: Vec<u8>,
186
187 pub checksum: u32,
189
190 pub is_response: bool,
192}
193
194impl PlainPacket {
195 pub const MAGIC: u32 = 0xDEADBEEF;
197
198 pub fn from_frame(frame: &ProxyFrame, handler_id: u64) -> Self {
200 Self {
201 magic: Self::MAGIC,
202 conn_id: frame.conn_id,
203 handler_id,
204 rip: frame.rip,
205 rport: frame.rport,
206 payload: frame.payload.clone(),
207 checksum: frame.checksum,
208 is_response: false,
209 }
210 }
211
212 pub fn response(conn_id: u64, handler_id: u64, payload: Vec<u8>) -> Self {
214 let checksum = crc32fast::hash(&payload);
215 Self {
216 magic: Self::MAGIC,
217 conn_id,
218 handler_id,
219 rip: [0; 16],
220 rport: 0,
221 payload,
222 checksum,
223 is_response: true,
224 }
225 }
226
227 pub fn is_valid(&self) -> bool {
229 self.magic == Self::MAGIC && crc32fast::hash(&self.payload) == self.checksum
230 }
231}
232
233#[derive(Archive, Serialize, Deserialize, Debug, Clone, PartialEq)]
235#[rkyv(compare(PartialEq), derive(Debug))]
236pub enum RaftCommand {
237 Upsert {
239 conn_id: u64,
240 txid: u64,
241 client_addr: [u8; 16],
242 nat_entry: (u16, u16),
243 assigned_pod: u32,
244 },
245
246 Delete { conn_id: u64 },
248
249 Cleanup { before_timestamp: u64 },
251
252 Noop,
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259
260 #[test]
261 fn test_frame_creation() {
262 let payload = vec![1, 2, 3, 4, 5];
263 let frame = ProxyFrame::new_data(
264 42,
265 ProxyFrame::ipv4_to_mapped([192, 168, 1, 1]),
266 8080,
267 payload.clone(),
268 );
269
270 assert_eq!(frame.conn_id, 42);
271 assert_eq!(frame.rport, 8080);
272 assert_eq!(frame.payload, payload);
273 assert!(frame.verify_checksum());
274 }
275
276 #[test]
277 fn test_ipv4_mapping() {
278 let ipv4 = [192, 168, 1, 1];
279 let mapped = ProxyFrame::ipv4_to_mapped(ipv4);
280 let extracted = ProxyFrame::mapped_to_ipv4(&mapped);
281
282 assert_eq!(extracted, Some(ipv4));
283 }
284
285 #[test]
286 fn test_serialization() {
287 let frame = ProxyFrame::new_data(1, [0; 16], 443, vec![0xDE, 0xAD, 0xBE, 0xEF]);
288
289 let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&frame).unwrap();
290 let archived = rkyv::access::<ArchivedProxyFrame, rkyv::rancor::Error>(&bytes).unwrap();
291
292 assert_eq!(archived.conn_id, 1);
293 assert_eq!(archived.rport, 443);
294 }
295}