1#![allow(dead_code)]
11
12use alloc::vec::Vec;
13
14use super::tunnel::TunnelType;
15use crate::net::Ipv4Address;
16
17pub const DEFAULT_PORT: u16 = 1194;
21
22const HMAC_KEY_SIZE: usize = 20;
24
25const TLS_AUTH_KEY_SIZE: usize = 64;
27
28const REPLAY_WINDOW_SIZE: usize = 64;
30
31const SESSION_ID_SIZE: usize = 8;
33
34const MAX_CONTROL_SIZE: usize = 1500;
36
37const MAX_DATA_SIZE: usize = 65536;
39
40const MAX_PENDING_ACKS: usize = 64;
42
43const RENEG_SECONDS: u64 = 3600;
45
46const MAX_CONFIG_LINE: usize = 256;
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[repr(u8)]
54pub enum OpenvpnOpcode {
55 ControlHardResetClientV2 = 7,
57 ControlHardResetServerV2 = 8,
59 ControlV1 = 4,
61 AckV1 = 5,
63 DataV1 = 6,
65 DataV2 = 9,
67}
68
69impl OpenvpnOpcode {
70 pub fn from_byte(b: u8) -> Option<Self> {
72 match b >> 3 {
73 7 => Some(Self::ControlHardResetClientV2),
74 8 => Some(Self::ControlHardResetServerV2),
75 4 => Some(Self::ControlV1),
76 5 => Some(Self::AckV1),
77 6 => Some(Self::DataV1),
78 9 => Some(Self::DataV2),
79 _ => None,
80 }
81 }
82
83 pub fn encode(&self, key_id: u8) -> u8 {
85 ((*self as u8) << 3) | (key_id & 0x07)
86 }
87
88 pub fn is_control(&self) -> bool {
90 matches!(
91 self,
92 Self::ControlHardResetClientV2
93 | Self::ControlHardResetServerV2
94 | Self::ControlV1
95 | Self::AckV1
96 )
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct OpenvpnHeader {
105 pub opcode: OpenvpnOpcode,
107 pub key_id: u8,
109 pub session_id: u64,
111 pub hmac_hash: [u8; HMAC_KEY_SIZE],
113 pub packet_id: u32,
115 pub timestamp: u32,
117}
118
119impl OpenvpnHeader {
120 pub const SIZE: usize = 1 + SESSION_ID_SIZE + HMAC_KEY_SIZE + 4 + 4;
123
124 pub fn parse(data: &[u8]) -> Option<Self> {
126 if data.len() < Self::SIZE {
127 return None;
128 }
129
130 let opcode = OpenvpnOpcode::from_byte(data[0])?;
131 let key_id = data[0] & 0x07;
132 let session_id = u64::from_be_bytes([
133 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
134 ]);
135
136 let mut hmac_hash = [0u8; HMAC_KEY_SIZE];
137 hmac_hash.copy_from_slice(&data[9..29]);
138
139 let packet_id = u32::from_be_bytes([data[29], data[30], data[31], data[32]]);
140 let timestamp = u32::from_be_bytes([data[33], data[34], data[35], data[36]]);
141
142 Some(Self {
143 opcode,
144 key_id,
145 session_id,
146 hmac_hash,
147 packet_id,
148 timestamp,
149 })
150 }
151
152 pub fn to_bytes(&self) -> Vec<u8> {
154 let mut buf = Vec::with_capacity(Self::SIZE);
155 buf.push(self.opcode.encode(self.key_id));
156 buf.extend_from_slice(&self.session_id.to_be_bytes());
157 buf.extend_from_slice(&self.hmac_hash);
158 buf.extend_from_slice(&self.packet_id.to_be_bytes());
159 buf.extend_from_slice(&self.timestamp.to_be_bytes());
160 buf
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
168pub enum OpenvpnState {
169 #[default]
171 Initial,
172 TlsHandshake,
174 Authentication,
176 Connected,
178 Reconnecting,
180 Disconnected,
182}
183
184#[derive(Clone)]
188pub struct TlsAuth {
189 key: [u8; TLS_AUTH_KEY_SIZE],
191 direction: u8,
193}
194
195impl TlsAuth {
196 pub fn new(key: [u8; TLS_AUTH_KEY_SIZE], direction: u8) -> Self {
198 Self {
199 key,
200 direction: direction & 1,
201 }
202 }
203
204 fn hmac_key(&self) -> &[u8] {
206 if self.direction == 0 {
207 &self.key[0..32]
208 } else {
209 &self.key[32..64]
210 }
211 }
212
213 pub fn compute_hmac(&self, data: &[u8]) -> [u8; HMAC_KEY_SIZE] {
219 let key = self.hmac_key();
220 let mut result = [0u8; HMAC_KEY_SIZE];
221
222 let mut inner = [0u8; HMAC_KEY_SIZE];
224 for (i, byte) in inner.iter_mut().enumerate() {
225 let k = if i < key.len() { key[i] } else { 0 };
226 *byte = k ^ 0x36;
227 }
228 for (i, &b) in data.iter().enumerate() {
230 inner[i % HMAC_KEY_SIZE] ^= b;
231 }
232
233 for (i, byte) in result.iter_mut().enumerate() {
235 let k = if i < key.len() { key[i] } else { 0 };
236 *byte = (k ^ 0x5C) ^ inner[i];
237 }
238
239 result
240 }
241
242 pub fn verify_hmac(&self, data: &[u8], expected: &[u8; HMAC_KEY_SIZE]) -> bool {
244 let computed = self.compute_hmac(data);
245 let mut diff = 0u8;
247 for (a, b) in computed.iter().zip(expected.iter()) {
248 diff |= a ^ b;
249 }
250 diff == 0
251 }
252}
253
254#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
258pub enum CipherAlgorithm {
259 #[default]
261 Aes256Gcm,
262 Aes128Cbc,
264 ChaCha20Poly1305,
266}
267
268#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
270pub enum AuthAlgorithm {
271 #[default]
273 Sha256,
274 Sha512,
276}
277
278#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
280pub enum Compression {
281 #[default]
283 None,
284 Lzo,
286 Lz4,
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
292pub enum TransportProto {
293 #[default]
295 Udp,
296 Tcp,
298}
299
300#[derive(Debug, Clone)]
304pub struct OpenvpnConfig {
305 pub remote_host: Ipv4Address,
307 pub remote_port: u16,
309 pub protocol: TransportProto,
311 pub cipher: CipherAlgorithm,
313 pub auth: AuthAlgorithm,
315 pub compress: Compression,
317 pub tls_auth_key: Option<[u8; TLS_AUTH_KEY_SIZE]>,
319 pub dev_type: TunnelType,
321}
322
323impl Default for OpenvpnConfig {
324 fn default() -> Self {
325 Self {
326 remote_host: Ipv4Address::new(0, 0, 0, 0),
327 remote_port: DEFAULT_PORT,
328 protocol: TransportProto::Udp,
329 cipher: CipherAlgorithm::Aes256Gcm,
330 auth: AuthAlgorithm::Sha256,
331 compress: Compression::None,
332 tls_auth_key: None,
333 dev_type: TunnelType::Tun,
334 }
335 }
336}
337
338pub struct PacketIdWindow {
342 window: [u8; REPLAY_WINDOW_SIZE / 8],
344 base: u32,
346 highest: u32,
348}
349
350impl Default for PacketIdWindow {
351 fn default() -> Self {
352 Self::new()
353 }
354}
355
356impl PacketIdWindow {
357 pub fn new() -> Self {
359 Self {
360 window: [0u8; REPLAY_WINDOW_SIZE / 8],
361 base: 0,
362 highest: 0,
363 }
364 }
365
366 pub fn check_replay(&self, packet_id: u32) -> bool {
368 if packet_id == 0 {
369 return false; }
371
372 if packet_id > self.highest {
374 return true;
375 }
376
377 if packet_id < self.base {
379 return false;
380 }
381
382 let offset = (packet_id - self.base) as usize;
384 if offset >= REPLAY_WINDOW_SIZE {
385 return false;
386 }
387
388 let byte_idx = offset / 8;
389 let bit_idx = offset % 8;
390 (self.window[byte_idx] & (1 << bit_idx)) == 0
391 }
392
393 pub fn update(&mut self, packet_id: u32) {
395 if packet_id == 0 {
396 return;
397 }
398
399 if packet_id > self.highest {
400 let shift = (packet_id - self.highest) as usize;
402 if shift >= REPLAY_WINDOW_SIZE {
403 self.window = [0u8; REPLAY_WINDOW_SIZE / 8];
405 } else {
406 self.shift_window(shift);
408 }
409 self.highest = packet_id;
410 self.base = packet_id.saturating_sub(REPLAY_WINDOW_SIZE as u32 - 1);
411 }
412
413 if packet_id >= self.base {
415 let offset = (packet_id - self.base) as usize;
416 if offset < REPLAY_WINDOW_SIZE {
417 let byte_idx = offset / 8;
418 let bit_idx = offset % 8;
419 self.window[byte_idx] |= 1 << bit_idx;
420 }
421 }
422 }
423
424 fn shift_window(&mut self, count: usize) {
426 if count >= REPLAY_WINDOW_SIZE {
427 self.window = [0u8; REPLAY_WINDOW_SIZE / 8];
428 return;
429 }
430
431 let byte_shift = count / 8;
432 let bit_shift = count % 8;
433
434 if byte_shift > 0 {
435 for i in (byte_shift..self.window.len()).rev() {
436 self.window[i] = self.window[i - byte_shift];
437 }
438 for byte in self.window.iter_mut().take(byte_shift) {
439 *byte = 0;
440 }
441 }
442
443 if bit_shift > 0 {
444 for i in (1..self.window.len()).rev() {
445 self.window[i] =
446 (self.window[i] << bit_shift) | (self.window[i - 1] >> (8 - bit_shift));
447 }
448 self.window[0] <<= bit_shift;
449 }
450 }
451}
452
453#[derive(Debug, Clone, Copy, PartialEq, Eq)]
457pub enum OpenvpnError {
458 NotConnected,
460 AlreadyConnected,
462 InvalidPacket,
464 HmacFailed,
466 ReplayDetected,
468 PacketTooLarge,
470 NoSession,
472 InvalidOpcode,
474 InvalidState,
476 RenegotiationRequired,
478}
479
480pub struct OpenvpnClient {
482 config: OpenvpnConfig,
484 state: OpenvpnState,
486 session_id: u64,
488 remote_session_id: u64,
490 packet_id_counter: u32,
492 replay_window: PacketIdWindow,
494 key_id: u8,
496 tls_auth: Option<TlsAuth>,
498 pending_acks: Vec<u32>,
500 session_start: u64,
502 bytes_sent: u64,
504 bytes_received: u64,
506}
507
508impl OpenvpnClient {
509 pub fn new(config: OpenvpnConfig, session_id: u64) -> Self {
511 let tls_auth = config.tls_auth_key.map(|key| TlsAuth::new(key, 0));
512
513 Self {
514 config,
515 state: OpenvpnState::Initial,
516 session_id,
517 remote_session_id: 0,
518 packet_id_counter: 1, replay_window: PacketIdWindow::new(),
520 key_id: 0,
521 tls_auth,
522 pending_acks: Vec::new(),
523 session_start: 0,
524 bytes_sent: 0,
525 bytes_received: 0,
526 }
527 }
528
529 pub fn state(&self) -> OpenvpnState {
531 self.state
532 }
533
534 pub fn session_id(&self) -> u64 {
536 self.session_id
537 }
538
539 pub fn connect(&mut self, now: u64) -> Result<Vec<u8>, OpenvpnError> {
541 if self.state != OpenvpnState::Initial && self.state != OpenvpnState::Disconnected {
542 return Err(OpenvpnError::InvalidState);
543 }
544
545 self.state = OpenvpnState::TlsHandshake;
546 self.session_start = now;
547
548 let packet =
550 self.build_control_packet(OpenvpnOpcode::ControlHardResetClientV2, &[], now as u32);
551 Ok(packet)
552 }
553
554 pub fn disconnect(&mut self) {
556 self.state = OpenvpnState::Disconnected;
557 self.pending_acks.clear();
558 }
559
560 pub fn send_control(&mut self, payload: &[u8], now: u64) -> Result<Vec<u8>, OpenvpnError> {
562 if self.state == OpenvpnState::Initial || self.state == OpenvpnState::Disconnected {
563 return Err(OpenvpnError::NotConnected);
564 }
565 if payload.len() > MAX_CONTROL_SIZE {
566 return Err(OpenvpnError::PacketTooLarge);
567 }
568
569 let packet = self.build_control_packet(OpenvpnOpcode::ControlV1, payload, now as u32);
570 Ok(packet)
571 }
572
573 pub fn send_data(&mut self, payload: &[u8]) -> Result<Vec<u8>, OpenvpnError> {
575 if self.state != OpenvpnState::Connected {
576 return Err(OpenvpnError::NotConnected);
577 }
578 if payload.len() > MAX_DATA_SIZE {
579 return Err(OpenvpnError::PacketTooLarge);
580 }
581
582 let pid = self.next_packet_id();
583 let mut packet = Vec::with_capacity(1 + 4 + payload.len());
584
585 packet.push(OpenvpnOpcode::DataV2.encode(self.key_id));
587 packet.extend_from_slice(&pid.to_be_bytes());
589 packet.extend_from_slice(payload);
591
592 self.bytes_sent += payload.len() as u64;
593 Ok(packet)
594 }
595
596 pub fn receive_packet(&mut self, data: &[u8]) -> Result<Vec<u8>, OpenvpnError> {
598 if data.is_empty() {
599 return Err(OpenvpnError::InvalidPacket);
600 }
601
602 let opcode = OpenvpnOpcode::from_byte(data[0]).ok_or(OpenvpnError::InvalidOpcode)?;
603
604 if opcode.is_control() {
605 self.process_control(data)
606 } else {
607 self.process_data(data)
608 }
609 }
610
611 pub fn process_control(&mut self, data: &[u8]) -> Result<Vec<u8>, OpenvpnError> {
613 let header = OpenvpnHeader::parse(data).ok_or(OpenvpnError::InvalidPacket)?;
614
615 if let Some(ref tls_auth) = self.tls_auth {
617 let hmac_data = if data.len() > 29 { &data[29..] } else { &[] };
619 if !tls_auth.verify_hmac(hmac_data, &header.hmac_hash) {
620 return Err(OpenvpnError::HmacFailed);
621 }
622 }
623
624 if !self.replay_window.check_replay(header.packet_id) {
626 return Err(OpenvpnError::ReplayDetected);
627 }
628 self.replay_window.update(header.packet_id);
629
630 match header.opcode {
632 OpenvpnOpcode::ControlHardResetServerV2 => {
633 if self.state == OpenvpnState::TlsHandshake {
634 self.remote_session_id = header.session_id;
635 self.queue_ack(header.packet_id);
637 self.state = OpenvpnState::Authentication;
638 }
639 }
640 OpenvpnOpcode::ControlV1 => {
641 self.queue_ack(header.packet_id);
642 if self.state == OpenvpnState::Authentication {
645 self.state = OpenvpnState::Connected;
646 }
647 }
648 OpenvpnOpcode::AckV1 => {
649 self.pending_acks.retain(|&pid| pid != header.packet_id);
651 }
652 _ => {}
653 }
654
655 if data.len() > OpenvpnHeader::SIZE {
657 self.bytes_received += (data.len() - OpenvpnHeader::SIZE) as u64;
658 Ok(data[OpenvpnHeader::SIZE..].to_vec())
659 } else {
660 Ok(Vec::new())
661 }
662 }
663
664 fn process_data(&mut self, data: &[u8]) -> Result<Vec<u8>, OpenvpnError> {
666 if self.state != OpenvpnState::Connected {
667 return Err(OpenvpnError::NotConnected);
668 }
669
670 if data.len() < 5 {
672 return Err(OpenvpnError::InvalidPacket);
673 }
674
675 let packet_id = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
676
677 if !self.replay_window.check_replay(packet_id) {
679 return Err(OpenvpnError::ReplayDetected);
680 }
681 self.replay_window.update(packet_id);
682
683 let payload = data[5..].to_vec();
684 self.bytes_received += payload.len() as u64;
685 Ok(payload)
686 }
687
688 pub fn renegotiate(&mut self, now: u64) -> Result<Vec<u8>, OpenvpnError> {
690 if self.state != OpenvpnState::Connected {
691 return Err(OpenvpnError::InvalidState);
692 }
693
694 self.key_id = (self.key_id + 1) & 0x07;
695 self.state = OpenvpnState::TlsHandshake;
696 self.replay_window = PacketIdWindow::new();
697
698 let packet =
699 self.build_control_packet(OpenvpnOpcode::ControlHardResetClientV2, &[], now as u32);
700 Ok(packet)
701 }
702
703 pub fn needs_renegotiation(&self, now: u64) -> bool {
705 if self.state != OpenvpnState::Connected {
706 return false;
707 }
708 now.saturating_sub(self.session_start) >= RENEG_SECONDS
709 }
710
711 fn next_packet_id(&mut self) -> u32 {
713 let id = self.packet_id_counter;
714 self.packet_id_counter = self.packet_id_counter.wrapping_add(1);
715 if self.packet_id_counter == 0 {
716 self.packet_id_counter = 1; }
718 id
719 }
720
721 fn queue_ack(&mut self, packet_id: u32) {
723 if self.pending_acks.len() < MAX_PENDING_ACKS {
724 self.pending_acks.push(packet_id);
725 }
726 }
727
728 fn build_control_packet(
730 &mut self,
731 opcode: OpenvpnOpcode,
732 payload: &[u8],
733 timestamp: u32,
734 ) -> Vec<u8> {
735 let pid = self.next_packet_id();
736
737 let hmac_hash = if let Some(ref tls_auth) = self.tls_auth {
738 let mut hmac_data = Vec::new();
740 hmac_data.extend_from_slice(&pid.to_be_bytes());
741 hmac_data.extend_from_slice(×tamp.to_be_bytes());
742 hmac_data.extend_from_slice(payload);
743 tls_auth.compute_hmac(&hmac_data)
744 } else {
745 [0u8; HMAC_KEY_SIZE]
746 };
747
748 let header = OpenvpnHeader {
749 opcode,
750 key_id: self.key_id,
751 session_id: self.session_id,
752 hmac_hash,
753 packet_id: pid,
754 timestamp,
755 };
756
757 let mut packet = header.to_bytes();
758 packet.extend_from_slice(payload);
759 packet
760 }
761
762 pub fn traffic_stats(&self) -> (u64, u64) {
764 (self.bytes_sent, self.bytes_received)
765 }
766}
767
768pub fn parse_config(input: &str) -> OpenvpnConfig {
775 let mut config = OpenvpnConfig::default();
776
777 for line in input.lines() {
778 let line = line.trim();
779 if line.is_empty() || line.starts_with('#') || line.starts_with(';') {
780 continue;
781 }
782
783 let (key, value) = match line.find(|c: char| c.is_ascii_whitespace()) {
785 Some(pos) => (line[..pos].trim(), line[pos + 1..].trim()),
786 None => (line, ""),
787 };
788
789 match key {
790 "proto" => {
791 config.protocol = match value {
792 "tcp" | "tcp-client" => TransportProto::Tcp,
793 _ => TransportProto::Udp,
794 };
795 }
796 "remote" => {
797 let parts: Vec<&str> = value.split_whitespace().collect();
799 if let Some(host) = parts.first() {
800 config.remote_host = parse_ipv4(host);
801 }
802 if let Some(port_str) = parts.get(1) {
803 if let Some(port) = parse_u16(port_str) {
804 config.remote_port = port;
805 }
806 }
807 }
808 "port" => {
809 if let Some(port) = parse_u16(value) {
810 config.remote_port = port;
811 }
812 }
813 "dev" => {
814 config.dev_type = if value.starts_with("tap") {
815 TunnelType::Tap
816 } else {
817 TunnelType::Tun
818 };
819 }
820 "cipher" => {
821 config.cipher = match value {
822 "AES-128-CBC" => CipherAlgorithm::Aes128Cbc,
823 "CHACHA20-POLY1305" => CipherAlgorithm::ChaCha20Poly1305,
824 _ => CipherAlgorithm::Aes256Gcm,
825 };
826 }
827 "auth" => {
828 config.auth = match value {
829 "SHA512" => AuthAlgorithm::Sha512,
830 _ => AuthAlgorithm::Sha256,
831 };
832 }
833 "compress" => {
834 config.compress = match value {
835 "lzo" => Compression::Lzo,
836 "lz4" | "lz4-v2" => Compression::Lz4,
837 _ => Compression::None,
838 };
839 }
840 _ => {} }
842 }
843
844 config
845}
846
847fn parse_ipv4(s: &str) -> Ipv4Address {
849 let mut octets = [0u8; 4];
850 for (i, part) in s.split('.').take(4).enumerate() {
851 if let Some(val) = parse_u8(part) {
852 octets[i] = val;
853 }
854 }
855 Ipv4Address(octets)
856}
857
858fn parse_u16(s: &str) -> Option<u16> {
860 let mut result: u16 = 0;
861 for &b in s.as_bytes() {
862 if !b.is_ascii_digit() {
863 return None;
864 }
865 result = result.checked_mul(10)?.checked_add((b - b'0') as u16)?;
866 }
867 Some(result)
868}
869
870fn parse_u8(s: &str) -> Option<u8> {
872 let mut result: u16 = 0;
873 for &b in s.as_bytes() {
874 if !b.is_ascii_digit() {
875 return None;
876 }
877 result = result.checked_mul(10)?.checked_add((b - b'0') as u16)?;
878 }
879 if result > 255 {
880 None
881 } else {
882 Some(result as u8)
883 }
884}
885
886#[cfg(test)]
889mod tests {
890 use super::*;
891
892 #[test]
893 fn test_opcode_encode_decode() {
894 for opcode in [
895 OpenvpnOpcode::ControlHardResetClientV2,
896 OpenvpnOpcode::ControlHardResetServerV2,
897 OpenvpnOpcode::ControlV1,
898 OpenvpnOpcode::AckV1,
899 OpenvpnOpcode::DataV1,
900 OpenvpnOpcode::DataV2,
901 ] {
902 let key_id = 3u8;
903 let byte = opcode.encode(key_id);
904 let decoded = OpenvpnOpcode::from_byte(byte).unwrap();
905 assert_eq!(decoded, opcode);
906 assert_eq!(byte & 0x07, key_id);
907 }
908 }
909
910 #[test]
911 fn test_opcode_is_control() {
912 assert!(OpenvpnOpcode::ControlV1.is_control());
913 assert!(OpenvpnOpcode::AckV1.is_control());
914 assert!(OpenvpnOpcode::ControlHardResetClientV2.is_control());
915 assert!(!OpenvpnOpcode::DataV1.is_control());
916 assert!(!OpenvpnOpcode::DataV2.is_control());
917 }
918
919 #[test]
920 fn test_header_serialize_parse() {
921 let header = OpenvpnHeader {
922 opcode: OpenvpnOpcode::ControlV1,
923 key_id: 2,
924 session_id: 0xDEADBEEF_CAFEBABE,
925 hmac_hash: [0xAA; HMAC_KEY_SIZE],
926 packet_id: 42,
927 timestamp: 1000,
928 };
929
930 let bytes = header.to_bytes();
931 assert_eq!(bytes.len(), OpenvpnHeader::SIZE);
932
933 let parsed = OpenvpnHeader::parse(&bytes).unwrap();
934 assert_eq!(parsed.opcode, OpenvpnOpcode::ControlV1);
935 assert_eq!(parsed.key_id, 2);
936 assert_eq!(parsed.session_id, 0xDEADBEEF_CAFEBABE);
937 assert_eq!(parsed.hmac_hash, [0xAA; HMAC_KEY_SIZE]);
938 assert_eq!(parsed.packet_id, 42);
939 assert_eq!(parsed.timestamp, 1000);
940 }
941
942 #[test]
943 fn test_header_parse_too_short() {
944 assert!(OpenvpnHeader::parse(&[0u8; 10]).is_none());
945 }
946
947 #[test]
948 fn test_tls_auth_hmac() {
949 let key = [0x42u8; TLS_AUTH_KEY_SIZE];
950 let tls_auth = TlsAuth::new(key, 0);
951
952 let mac1 = tls_auth.compute_hmac(b"hello");
953 let mac2 = tls_auth.compute_hmac(b"hello");
954 assert_eq!(mac1, mac2);
955
956 let mac3 = tls_auth.compute_hmac(b"world");
957 assert_ne!(mac1, mac3);
958 }
959
960 #[test]
961 fn test_tls_auth_verify() {
962 let key = [0x42u8; TLS_AUTH_KEY_SIZE];
963 let tls_auth = TlsAuth::new(key, 0);
964
965 let mac = tls_auth.compute_hmac(b"test data");
966 assert!(tls_auth.verify_hmac(b"test data", &mac));
967 assert!(!tls_auth.verify_hmac(b"wrong data", &mac));
968 }
969
970 #[test]
971 fn test_tls_auth_direction() {
972 let mut key = [0u8; TLS_AUTH_KEY_SIZE];
974 for (i, b) in key.iter_mut().enumerate() {
975 *b = if i < 32 { 0x42 } else { 0xAB };
976 }
977 let auth0 = TlsAuth::new(key, 0);
978 let auth1 = TlsAuth::new(key, 1);
979
980 assert_eq!(auth0.hmac_key()[0], 0x42);
982 assert_eq!(auth1.hmac_key()[0], 0xAB);
983 }
984
985 #[test]
986 fn test_replay_window_basic() {
987 let mut window = PacketIdWindow::new();
988
989 assert!(!window.check_replay(0));
991
992 assert!(window.check_replay(1));
994 window.update(1);
995
996 assert!(!window.check_replay(1));
998
999 assert!(window.check_replay(2));
1001 window.update(2);
1002 assert!(window.check_replay(100));
1003 }
1004
1005 #[test]
1006 fn test_replay_window_large_jump() {
1007 let mut window = PacketIdWindow::new();
1008
1009 window.update(1);
1010 window.update(1000);
1011
1012 assert!(!window.check_replay(1));
1014
1015 assert!(window.check_replay(999));
1017 }
1018
1019 #[test]
1020 fn test_client_connect_disconnect() {
1021 let config = OpenvpnConfig::default();
1022 let mut client = OpenvpnClient::new(config, 0x1234);
1023
1024 assert_eq!(client.state(), OpenvpnState::Initial);
1025
1026 let pkt = client.connect(100).unwrap();
1027 assert!(!pkt.is_empty());
1028 assert_eq!(client.state(), OpenvpnState::TlsHandshake);
1029
1030 assert_eq!(client.connect(101), Err(OpenvpnError::InvalidState));
1032
1033 client.disconnect();
1034 assert_eq!(client.state(), OpenvpnState::Disconnected);
1035 }
1036
1037 #[test]
1038 fn test_client_send_data_requires_connected() {
1039 let config = OpenvpnConfig::default();
1040 let mut client = OpenvpnClient::new(config, 0x1234);
1041
1042 assert_eq!(client.send_data(b"hello"), Err(OpenvpnError::NotConnected));
1043 }
1044
1045 #[test]
1046 fn test_config_parse_basic() {
1047 let input = "\
1048proto udp
1049remote 10.0.0.1 1194
1050dev tun
1051cipher AES-256-GCM
1052auth SHA256
1053compress lz4
1054";
1055 let config = parse_config(input);
1056 assert_eq!(config.protocol, TransportProto::Udp);
1057 assert_eq!(config.remote_host, Ipv4Address::new(10, 0, 0, 1));
1058 assert_eq!(config.remote_port, 1194);
1059 assert_eq!(config.dev_type, TunnelType::Tun);
1060 assert_eq!(config.cipher, CipherAlgorithm::Aes256Gcm);
1061 assert_eq!(config.auth, AuthAlgorithm::Sha256);
1062 assert_eq!(config.compress, Compression::Lz4);
1063 }
1064
1065 #[test]
1066 fn test_config_parse_comments_and_blanks() {
1067 let input = "\
1068# This is a comment
1069; Another comment
1070
1071proto tcp
1072port 443
1073dev tap0
1074cipher AES-128-CBC
1075auth SHA512
1076";
1077 let config = parse_config(input);
1078 assert_eq!(config.protocol, TransportProto::Tcp);
1079 assert_eq!(config.remote_port, 443);
1080 assert_eq!(config.dev_type, TunnelType::Tap);
1081 assert_eq!(config.cipher, CipherAlgorithm::Aes128Cbc);
1082 assert_eq!(config.auth, AuthAlgorithm::Sha512);
1083 }
1084
1085 #[test]
1086 fn test_parse_ipv4() {
1087 assert_eq!(parse_ipv4("192.168.1.1"), Ipv4Address::new(192, 168, 1, 1));
1088 assert_eq!(parse_ipv4("10.0.0.1"), Ipv4Address::new(10, 0, 0, 1));
1089 assert_eq!(parse_ipv4("0.0.0.0"), Ipv4Address::new(0, 0, 0, 0));
1090 }
1091}