mirror of
https://github.com/aramperes/onetun.git
synced 2025-09-09 23:38:30 -04:00
Add optional IP packet capture for WireGuard tunnel
This commit is contained in:
parent
953bc18279
commit
ff0f5b967e
5 changed files with 141 additions and 1 deletions
113
src/pcap.rs
Normal file
113
src/pcap.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use crate::events::Event;
|
||||
use crate::Bus;
|
||||
use anyhow::Context;
|
||||
use smoltcp::time::Instant;
|
||||
use tokio::fs::File;
|
||||
use tokio::io::{AsyncWriteExt, BufWriter};
|
||||
|
||||
struct Pcap {
|
||||
writer: BufWriter<File>,
|
||||
}
|
||||
|
||||
/// libpcap file writer
|
||||
/// This is mostly taken from `smoltcp`, but rewritten to be async.
|
||||
impl Pcap {
|
||||
async fn flush(&mut self) -> anyhow::Result<()> {
|
||||
self.writer
|
||||
.flush()
|
||||
.await
|
||||
.with_context(|| "Failed to flush pcap writer")
|
||||
}
|
||||
|
||||
async fn write(&mut self, data: &[u8]) -> anyhow::Result<usize> {
|
||||
self.writer
|
||||
.write(data)
|
||||
.await
|
||||
.with_context(|| format!("Failed to write {} bytes to pcap writer", data.len()))
|
||||
}
|
||||
|
||||
async fn write_u16(&mut self, value: u16) -> anyhow::Result<()> {
|
||||
self.writer
|
||||
.write_u16(value)
|
||||
.await
|
||||
.with_context(|| "Failed to write u16 to pcap writer")
|
||||
}
|
||||
|
||||
async fn write_u32(&mut self, value: u32) -> anyhow::Result<()> {
|
||||
self.writer
|
||||
.write_u32(value)
|
||||
.await
|
||||
.with_context(|| "Failed to write u32 to pcap writer")
|
||||
}
|
||||
|
||||
async fn global_header(&mut self) -> anyhow::Result<()> {
|
||||
self.write_u32(0xa1b2c3d4).await?; // magic number
|
||||
self.write_u16(2).await?; // major version
|
||||
self.write_u16(4).await?; // minor version
|
||||
self.write_u32(0).await?; // timezone (= UTC)
|
||||
self.write_u32(0).await?; // accuracy (not used)
|
||||
self.write_u32(65535).await?; // maximum packet length
|
||||
self.write_u32(101).await?; // link-layer header type (101 = IP)
|
||||
self.flush().await
|
||||
}
|
||||
|
||||
async fn packet_header(&mut self, timestamp: Instant, length: usize) -> anyhow::Result<()> {
|
||||
assert!(length <= 65535);
|
||||
|
||||
self.write_u32(timestamp.secs() as u32).await?; // timestamp seconds
|
||||
self.write_u32(timestamp.micros() as u32).await?; // timestamp microseconds
|
||||
self.write_u32(length as u32).await?; // captured length
|
||||
self.write_u32(length as u32).await?; // original length
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn packet(&mut self, timestamp: Instant, packet: &[u8]) -> anyhow::Result<()> {
|
||||
self.packet_header(timestamp, packet.len())
|
||||
.await
|
||||
.with_context(|| "Failed to write packet header to pcap writer")?;
|
||||
self.write(packet)
|
||||
.await
|
||||
.with_context(|| "Failed to write packet to pcap writer")?;
|
||||
self.writer
|
||||
.flush()
|
||||
.await
|
||||
.with_context(|| "Failed to flush pcap writer")?;
|
||||
self.flush().await
|
||||
}
|
||||
}
|
||||
|
||||
/// Listens on the event bus for IP packets sent from and to the WireGuard tunnel.
|
||||
pub async fn capture(pcap_file: String, bus: Bus) -> anyhow::Result<()> {
|
||||
let mut endpoint = bus.new_endpoint();
|
||||
let file = File::create(&pcap_file)
|
||||
.await
|
||||
.with_context(|| "Failed to create pcap file")?;
|
||||
let writer = BufWriter::new(file);
|
||||
|
||||
let mut writer = Pcap { writer };
|
||||
writer
|
||||
.global_header()
|
||||
.await
|
||||
.with_context(|| "Failed to write global header to pcap writer")?;
|
||||
|
||||
info!("Capturing WireGuard IP packets to {}", &pcap_file);
|
||||
loop {
|
||||
match endpoint.recv().await {
|
||||
Event::InboundInternetPacket(_proto, ip) => {
|
||||
let instant = Instant::now();
|
||||
writer
|
||||
.packet(instant, &ip)
|
||||
.await
|
||||
.with_context(|| "Failed to write inbound IP packet to pcap writer")?;
|
||||
}
|
||||
Event::OutboundInternetPacket(ip) => {
|
||||
let instant = Instant::now();
|
||||
writer
|
||||
.packet(instant, &ip)
|
||||
.await
|
||||
.with_context(|| "Failed to write output IP packet to pcap writer")?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue