1use anyhow::{bail, Result};
53use bytes::{BufMut, BytesMut};
54
55pub const MAX_PACKET_SIZE: usize = 65535;
57
58#[repr(u8)]
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum Opcode {
62 ControlHardResetClientV1 = 1,
63 ControlHardResetServerV1 = 2,
64 ControlSoftResetV1 = 3,
65 ControlV1 = 4,
66 AckV1 = 5,
67 DataV1 = 6,
68 ControlHardResetClientV2 = 7,
69 ControlHardResetServerV2 = 8,
70 DataV2 = 9,
71 ControlHardResetClientV3 = 10,
74 ControlWkcV1 = 11,
76}
77
78impl Opcode {
79 pub fn from_u8(v: u8) -> Option<Self> {
80 match v {
81 1 => Some(Opcode::ControlHardResetClientV1),
82 2 => Some(Opcode::ControlHardResetServerV1),
83 3 => Some(Opcode::ControlSoftResetV1),
84 4 => Some(Opcode::ControlV1),
85 5 => Some(Opcode::AckV1),
86 6 => Some(Opcode::DataV1),
87 7 => Some(Opcode::ControlHardResetClientV2),
88 8 => Some(Opcode::ControlHardResetServerV2),
89 9 => Some(Opcode::DataV2),
90 10 => Some(Opcode::ControlHardResetClientV3),
91 11 => Some(Opcode::ControlWkcV1),
92 _ => None,
93 }
94 }
95
96 pub fn is_control(&self) -> bool {
103 matches!(
104 self,
105 Opcode::ControlHardResetClientV1
106 | Opcode::ControlHardResetServerV1
107 | Opcode::ControlHardResetClientV2
108 | Opcode::ControlHardResetServerV2
109 | Opcode::ControlSoftResetV1
110 | Opcode::ControlV1
111 )
112 }
113
114 pub fn is_data(&self) -> bool {
115 matches!(self, Opcode::DataV1 | Opcode::DataV2)
116 }
117
118 pub fn is_ack(&self) -> bool {
119 matches!(self, Opcode::AckV1)
120 }
121
122 pub fn is_tls_crypt_v2(&self) -> bool {
124 matches!(
125 self,
126 Opcode::ControlHardResetClientV3 | Opcode::ControlWkcV1
127 )
128 }
129
130 pub fn is_client_reset(&self) -> bool {
132 matches!(
133 self,
134 Opcode::ControlHardResetClientV1 | Opcode::ControlHardResetClientV2
135 )
136 }
137}
138
139pub fn parse_opcode_byte(data: &[u8]) -> Result<(Opcode, u8)> {
141 let first = *data
142 .first()
143 .ok_or_else(|| anyhow::anyhow!("Empty packet"))?;
144 let raw = (first >> 3) & 0x1F;
145 let opcode =
146 Opcode::from_u8(raw).ok_or_else(|| anyhow::anyhow!("Unknown OpenVPN opcode: {}", raw))?;
147 Ok((opcode, first & 0x07))
148}
149
150struct Reader<'a> {
152 buf: &'a [u8],
153 pos: usize,
154}
155
156impl<'a> Reader<'a> {
157 fn new(buf: &'a [u8]) -> Self {
158 Reader { buf, pos: 0 }
159 }
160
161 fn take(&mut self, n: usize, what: &str) -> Result<&'a [u8]> {
162 let end = self
163 .pos
164 .checked_add(n)
165 .ok_or_else(|| anyhow::anyhow!("Length overflow reading {}", what))?;
166 if end > self.buf.len() {
167 bail!(
168 "Packet too short for {}: need {} more bytes at offset {}, have {}",
169 what,
170 n,
171 self.pos,
172 self.buf.len().saturating_sub(self.pos)
173 );
174 }
175 let out = &self.buf[self.pos..end];
176 self.pos = end;
177 Ok(out)
178 }
179
180 fn u8(&mut self, what: &str) -> Result<u8> {
181 Ok(self.take(1, what)?[0])
182 }
183
184 fn u32(&mut self, what: &str) -> Result<u32> {
185 let b = self.take(4, what)?;
186 Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
187 }
188
189 fn u64(&mut self, what: &str) -> Result<u64> {
190 let b = self.take(8, what)?;
191 Ok(u64::from_be_bytes([
192 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
193 ]))
194 }
195
196 fn rest(&mut self) -> &'a [u8] {
197 let out = &self.buf[self.pos..];
198 self.pos = self.buf.len();
199 out
200 }
201}
202
203#[derive(Debug, Clone, PartialEq, Eq)]
205pub struct ControlFrame {
206 pub opcode: Opcode,
207 pub key_id: u8,
208 pub session_id: u64,
210 pub ack_packet_ids: Vec<u32>,
212 pub remote_session_id: Option<u64>,
215 pub packet_id: Option<u32>,
217 pub payload: Vec<u8>,
219}
220
221impl ControlFrame {
222 pub fn hard_reset_server_v2(
224 key_id: u8,
225 server_session_id: u64,
226 client_session_id: u64,
227 client_packet_id: u32,
228 our_packet_id: u32,
229 ) -> Self {
230 ControlFrame {
231 opcode: Opcode::ControlHardResetServerV2,
232 key_id,
233 session_id: server_session_id,
234 ack_packet_ids: vec![client_packet_id],
235 remote_session_id: Some(client_session_id),
236 packet_id: Some(our_packet_id),
237 payload: Vec::new(),
238 }
239 }
240
241 pub fn ack(
243 key_id: u8,
244 server_session_id: u64,
245 client_session_id: u64,
246 ack_packet_ids: Vec<u32>,
247 ) -> Self {
248 ControlFrame {
249 opcode: Opcode::AckV1,
250 key_id,
251 session_id: server_session_id,
252 ack_packet_ids,
253 remote_session_id: Some(client_session_id),
254 packet_id: None,
255 payload: Vec::new(),
256 }
257 }
258
259 pub fn parse(data: &[u8]) -> Result<Self> {
264 let (opcode, key_id) = parse_opcode_byte(data)?;
265
266 if opcode.is_tls_crypt_v2() {
267 bail!(
268 "{:?} is a tls-crypt-v2 frame: its reliability fields are encrypted and \
269 this server has no tls-crypt-v2 key, so it cannot be parsed",
270 opcode
271 );
272 }
273 if !opcode.is_control() && !opcode.is_ack() {
274 bail!("Not a control or ACK packet: {:?}", opcode);
275 }
276
277 let mut r = Reader::new(data);
278 r.take(1, "opcode byte")?;
279
280 let session_id = r.u64("session id")?;
281
282 let ack_count = r.u8("ACK array length")? as usize;
283 let mut ack_packet_ids = Vec::with_capacity(ack_count.min(64));
284 for i in 0..ack_count {
285 ack_packet_ids.push(r.u32(&format!("ACK id #{}", i))?);
286 }
287
288 let remote_session_id = if ack_count > 0 {
290 Some(r.u64("remote session id")?)
291 } else {
292 None
293 };
294
295 let packet_id = if opcode.is_ack() {
297 None
298 } else {
299 Some(r.u32("message packet id")?)
300 };
301
302 Ok(ControlFrame {
303 opcode,
304 key_id,
305 session_id,
306 ack_packet_ids,
307 remote_session_id,
308 packet_id,
309 payload: r.rest().to_vec(),
310 })
311 }
312
313 pub fn serialize(&self) -> BytesMut {
320 let mut buf = BytesMut::with_capacity(32 + self.payload.len());
321
322 buf.put_u8(((self.opcode as u8) << 3) | (self.key_id & 0x07));
323 buf.put_u64(self.session_id);
324
325 let acks = &self.ack_packet_ids[..self.ack_packet_ids.len().min(u8::MAX as usize)];
328 buf.put_u8(acks.len() as u8);
329 for id in acks {
330 buf.put_u32(*id);
331 }
332
333 if !acks.is_empty() {
334 buf.put_u64(self.remote_session_id.unwrap_or(0));
335 }
336
337 if !self.opcode.is_ack() {
338 buf.put_u32(self.packet_id.unwrap_or(0));
339 }
340
341 buf.put_slice(&self.payload);
342 buf
343 }
344
345 pub fn is_plain_reset(&self) -> bool {
354 self.opcode.is_client_reset() && self.payload.is_empty() && self.ack_packet_ids.is_empty()
355 }
356}
357
358#[derive(Debug, Clone, PartialEq, Eq)]
360pub struct DataFrame {
361 pub opcode: Opcode,
362 pub key_id: u8,
363 pub peer_id: Option<u32>,
365 pub payload: Vec<u8>,
366}
367
368impl DataFrame {
369 pub fn parse(data: &[u8]) -> Result<Self> {
370 let (opcode, key_id) = parse_opcode_byte(data)?;
371 if !opcode.is_data() {
372 bail!("Not a data packet: {:?}", opcode);
373 }
374
375 let mut r = Reader::new(data);
376 r.take(1, "opcode byte")?;
377
378 let peer_id = if opcode == Opcode::DataV2 {
379 let b = r.take(3, "peer id")?;
380 Some(u32::from_be_bytes([0, b[0], b[1], b[2]]))
381 } else {
382 None
383 };
384
385 Ok(DataFrame {
386 opcode,
387 key_id,
388 peer_id,
389 payload: r.rest().to_vec(),
390 })
391 }
392
393 pub fn serialize(&self) -> BytesMut {
394 let mut buf = BytesMut::with_capacity(4 + self.payload.len());
395 buf.put_u8(((self.opcode as u8) << 3) | (self.key_id & 0x07));
396 if self.opcode == Opcode::DataV2 {
397 let id = self.peer_id.unwrap_or(0);
398 buf.put_slice(&[(id >> 16) as u8, (id >> 8) as u8, id as u8]);
399 }
400 buf.put_slice(&self.payload);
401 buf
402 }
403}