1use std::net::Ipv4Addr;
57use crate::error::VCLError;
58use etherparse::{Ipv4HeaderSlice, Ipv6HeaderSlice};
59use tracing::{debug, info, warn};
60
61#[derive(Debug, Clone)]
63pub struct TunConfig {
64 pub name: String,
66 pub address: Ipv4Addr,
68 pub destination: Ipv4Addr,
70 pub netmask: Ipv4Addr,
72 pub mtu: u16,
74}
75
76impl Default for TunConfig {
77 fn default() -> Self {
78 TunConfig {
79 name: "vcl0".to_string(),
80 address: "10.0.0.1".parse().unwrap(),
81 destination: "10.0.0.2".parse().unwrap(),
82 netmask: "255.255.255.0".parse().unwrap(),
83 mtu: 1420,
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
90pub enum IpVersion {
91 V4,
92 V6,
93 Unknown(u8),
94}
95
96#[derive(Debug, Clone)]
98pub struct IpPacket {
99 pub raw: Vec<u8>,
101 pub version: IpVersion,
103 pub src: String,
105 pub dst: String,
107 pub protocol: u8,
109 pub len: usize,
111}
112
113pub struct VCLTun {
117 #[cfg(target_os = "linux")]
118 dev: tun::AsyncDevice,
119 #[cfg(target_os = "windows")]
120 dev: wintun::Adapter,
121 #[cfg(not(any(target_os = "linux", target_os = "windows")))]
122 _marker: std::marker::PhantomData<()>,
123 config: TunConfig,
124}
125
126impl VCLTun {
127 #[cfg(target_os = "linux")]
136 pub fn create(config: TunConfig) -> Result<Self, VCLError> {
137 let mut tun_config = tun::Configuration::default();
138 tun_config.tun_name(&config.name);
139 tun_config
140 .address(config.address)
141 .destination(config.destination)
142 .netmask(config.netmask)
143 .mtu(config.mtu)
144 .up();
145
146 let dev = tun::create_as_async(&tun_config)
147 .map_err(|e| VCLError::IoError(format!("Failed to create TUN device: {}", e)))?;
148
149 info!(
150 name = %config.name,
151 address = %config.address,
152 destination = %config.destination,
153 mtu = config.mtu,
154 platform = "linux",
155 "TUN interface created"
156 );
157
158 Ok(VCLTun { dev, config })
159 }
160
161 #[cfg(target_os = "windows")]
163 pub fn create(config: TunConfig) -> Result<Self, VCLError> {
164 let adapter = wintun::Adapter::open(&config.name)
165 .or_else(|_| wintun::Adapter::create(&config.name, "VCL", None))
166 .map_err(|e| VCLError::IoError(format!("Failed to create Wintun adapter: {}", e)))?;
167
168 adapter
169 .set_address(config.address)
170 .map_err(|e| VCLError::IoError(format!("Failed to set adapter address: {}", e)))?;
171 adapter
172 .set_gateway(config.destination)
173 .map_err(|e| VCLError::IoError(format!("Failed to set adapter gateway: {}", e)))?;
174 adapter
175 .set_netmask(config.netmask)
176 .map_err(|e| VCLError::IoError(format!("Failed to set adapter netmask: {}", e)))?;
177
178 info!(
179 name = %config.name,
180 address = %config.address,
181 destination = %config.destination,
182 mtu = config.mtu,
183 platform = "windows",
184 "Wintun interface created"
185 );
186
187 Ok(VCLTun { dev: adapter, config })
188 }
189
190 #[cfg(not(any(target_os = "linux", target_os = "windows")))]
192 pub fn create(_config: TunConfig) -> Result<Self, VCLError> {
193 Err(VCLError::IoError(
194 "TUN interface is only supported on Linux and Windows".to_string(),
195 ))
196 }
197
198 #[cfg(target_os = "linux")]
200 pub async fn read_packet(&mut self) -> Result<Vec<u8>, VCLError> {
201 use tokio::io::AsyncReadExt;
202 let mut buf = vec![0u8; self.config.mtu as usize + 4];
203 let n = self.dev.read(&mut buf).await
204 .map_err(|e| VCLError::IoError(format!("TUN read failed: {}", e)))?;
205 buf.truncate(n);
206 debug!(size = n, platform = "linux", "TUN packet read");
207 Ok(buf)
208 }
209
210 #[cfg(target_os = "windows")]
211 pub async fn read_packet(&mut self) -> Result<Vec<u8>, VCLError> {
212 let adapter = self.dev.clone();
213 let mtu = self.config.mtu as usize;
214 tokio::task::spawn_blocking(move || {
215 let mut buf = vec![0u8; mtu + 4];
216 let n = adapter.receive_packet(&mut buf)
217 .map_err(|e| VCLError::IoError(format!("Wintun read failed: {}", e)))?;
218 buf.truncate(n);
219 Ok(buf)
220 })
221 .await
222 .map_err(|e| VCLError::IoError(format!("Wintun read task failed: {}", e)))?
223 }
224
225 #[cfg(not(any(target_os = "linux", target_os = "windows")))]
226 pub async fn read_packet(&mut self) -> Result<Vec<u8>, VCLError> {
227 Err(VCLError::IoError("TUN not supported on this platform".to_string()))
228 }
229
230 #[cfg(target_os = "linux")]
232 pub async fn write_packet(&mut self, packet: &[u8]) -> Result<(), VCLError> {
233 use tokio::io::AsyncWriteExt;
234 self.dev.write_all(packet).await
235 .map_err(|e| VCLError::IoError(format!("TUN write failed: {}", e)))?;
236 debug!(size = packet.len(), platform = "linux", "TUN packet injected");
237 Ok(())
238 }
239
240 #[cfg(target_os = "windows")]
241 pub async fn write_packet(&mut self, packet: &[u8]) -> Result<(), VCLError> {
242 let adapter = self.dev.clone();
243 let packet = packet.to_vec();
244 tokio::task::spawn_blocking(move || {
245 adapter.send_packet(&packet)
246 .map_err(|e| VCLError::IoError(format!("Wintun write failed: {}", e)))?;
247 Ok(())
248 })
249 .await
250 .map_err(|e| VCLError::IoError(format!("Wintun write task failed: {}", e)))?
251 }
252
253 #[cfg(not(any(target_os = "linux", target_os = "windows")))]
254 pub async fn write_packet(&mut self, _packet: &[u8]) -> Result<(), VCLError> {
255 Err(VCLError::IoError("TUN not supported on this platform".to_string()))
256 }
257
258 pub fn name(&self) -> &str {
260 &self.config.name
261 }
262
263 pub fn mtu(&self) -> u16 {
265 self.config.mtu
266 }
267
268 pub fn address(&self) -> Ipv4Addr {
270 self.config.address
271 }
272
273 pub fn destination(&self) -> Ipv4Addr {
275 self.config.destination
276 }
277
278 pub fn config(&self) -> &TunConfig {
280 &self.config
281 }
282}
283
284pub fn parse_ip_packet(raw: Vec<u8>) -> Result<IpPacket, VCLError> {
294 if raw.is_empty() {
295 return Err(VCLError::InvalidPacket("Empty IP packet".to_string()));
296 }
297
298 let version_byte = raw[0] >> 4;
299 let len = raw.len();
300
301 match version_byte {
302 4 => parse_ipv4(raw, len),
303 6 => parse_ipv6(raw, len),
304 v => {
305 warn!(version = v, "Unknown IP version in TUN packet");
306 Ok(IpPacket {
307 raw,
308 version: IpVersion::Unknown(v),
309 src: String::new(),
310 dst: String::new(),
311 protocol: 0,
312 len,
313 })
314 }
315 }
316}
317
318fn parse_ipv4(raw: Vec<u8>, len: usize) -> Result<IpPacket, VCLError> {
319 let header = Ipv4HeaderSlice::from_slice(&raw)
320 .map_err(|e| VCLError::InvalidPacket(format!("IPv4 parse error: {}", e)))?;
321
322 let src = format!(
323 "{}.{}.{}.{}",
324 header.source()[0], header.source()[1],
325 header.source()[2], header.source()[3]
326 );
327 let dst = format!(
328 "{}.{}.{}.{}",
329 header.destination()[0], header.destination()[1],
330 header.destination()[2], header.destination()[3]
331 );
332 let protocol = header.protocol().0;
333
334 debug!(src = %src, dst = %dst, protocol, size = len, "IPv4 packet parsed");
335
336 Ok(IpPacket {
337 raw,
338 version: IpVersion::V4,
339 src,
340 dst,
341 protocol,
342 len,
343 })
344}
345
346fn parse_ipv6(raw: Vec<u8>, len: usize) -> Result<IpPacket, VCLError> {
347 let header = Ipv6HeaderSlice::from_slice(&raw)
348 .map_err(|e| VCLError::InvalidPacket(format!("IPv6 parse error: {}", e)))?;
349
350 let src = format!("{:?}", header.source_addr());
351 let dst = format!("{:?}", header.destination_addr());
352 let protocol = header.next_header().0;
353
354 debug!(src = %src, dst = %dst, protocol, size = len, "IPv6 packet parsed");
355
356 Ok(IpPacket {
357 raw,
358 version: IpVersion::V6,
359 src,
360 dst,
361 protocol,
362 len,
363 })
364}
365
366pub fn is_ipv4(raw: &[u8]) -> bool {
368 raw.first().map(|b| b >> 4 == 4).unwrap_or(false)
369}
370
371pub fn is_ipv6(raw: &[u8]) -> bool {
373 raw.first().map(|b| b >> 4 == 6).unwrap_or(false)
374}
375
376pub fn ip_version(raw: &[u8]) -> Option<IpVersion> {
378 raw.first().map(|b| match b >> 4 {
379 4 => IpVersion::V4,
380 6 => IpVersion::V6,
381 v => IpVersion::Unknown(v),
382 })
383}
384
385#[cfg(test)]
386mod tests {
387 use super::*;
388
389 fn make_ipv4_packet() -> Vec<u8> {
390 vec![
392 0x45, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 192, 168, 1, 1, 10, 0, 0, 1, 0x00, 0x00, 0x00, 0x00, ]
404 }
405
406 fn make_ipv6_packet() -> Vec<u8> {
407 let mut pkt = vec![
409 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x11, 0x40, ];
414 pkt.extend_from_slice(&[0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1]);
416 pkt.extend_from_slice(&[0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2]);
418 pkt.extend_from_slice(&[0u8; 8]);
420 pkt
421 }
422
423 #[test]
424 fn test_tun_config_default() {
425 let c = TunConfig::default();
426 assert_eq!(c.name, "vcl0");
427 assert_eq!(c.mtu, 1420);
428 assert_eq!(c.address, "10.0.0.1".parse::<Ipv4Addr>().unwrap());
429 }
430
431 #[test]
432 fn test_parse_ipv4_packet() {
433 let raw = make_ipv4_packet();
434 let pkt = parse_ip_packet(raw).unwrap();
435 assert_eq!(pkt.version, IpVersion::V4);
436 assert_eq!(pkt.src, "192.168.1.1");
437 assert_eq!(pkt.dst, "10.0.0.1");
438 assert_eq!(pkt.protocol, 6); }
440
441 #[test]
442 fn test_parse_ipv6_packet() {
443 let raw = make_ipv6_packet();
444 let pkt = parse_ip_packet(raw).unwrap();
445 assert_eq!(pkt.version, IpVersion::V6);
446 assert_eq!(pkt.protocol, 17); }
448
449 #[test]
450 fn test_parse_empty_packet() {
451 let result = parse_ip_packet(vec![]);
452 assert!(result.is_err());
453 }
454
455 #[test]
456 fn test_parse_unknown_version() {
457 let raw = vec![0x30, 0x00, 0x00, 0x00]; let pkt = parse_ip_packet(raw).unwrap();
459 assert_eq!(pkt.version, IpVersion::Unknown(3));
460 }
461
462 #[test]
463 fn test_is_ipv4() {
464 assert!(is_ipv4(&make_ipv4_packet()));
465 assert!(!is_ipv4(&make_ipv6_packet()));
466 assert!(!is_ipv4(&[]));
467 }
468
469 #[test]
470 fn test_is_ipv6() {
471 assert!(is_ipv6(&make_ipv6_packet()));
472 assert!(!is_ipv6(&make_ipv4_packet()));
473 assert!(!is_ipv6(&[]));
474 }
475
476 #[test]
477 fn test_ip_version() {
478 assert_eq!(ip_version(&make_ipv4_packet()), Some(IpVersion::V4));
479 assert_eq!(ip_version(&make_ipv6_packet()), Some(IpVersion::V6));
480 assert_eq!(ip_version(&[0x30]), Some(IpVersion::Unknown(3)));
481 assert_eq!(ip_version(&[]), None);
482 }
483
484 #[test]
485 fn test_tun_create_non_linux() {
486 #[cfg(not(target_os = "linux"))]
487 {
488 let result = VCLTun::create(TunConfig::default());
489 assert!(result.is_err());
490 }
491 #[cfg(target_os = "linux")]
492 {
493 let c = TunConfig::default();
494 assert_eq!(c.mtu, 1420);
495 }
496 }
497
498 #[test]
499 fn test_ip_packet_len() {
500 let raw = make_ipv4_packet();
501 let expected_len = raw.len();
502 let pkt = parse_ip_packet(raw).unwrap();
503 assert_eq!(pkt.len, expected_len);
504 }
505}