diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 25 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 112 |
3 files changed, 137 insertions, 2 deletions
diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..0b560f0 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,25 @@ +use std::io; +use std::sync::mpsc; + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("io: {0}")] + Io(#[from] io::Error), + #[error("mpsc recv: {0}")] + MpscRecv(#[from] mpsc::RecvError), + #[error("mpsc send Vec<u8>")] + MpscSendU8Vec, + + #[error("pcap: {0}")] + Pcap(#[from] pcap::Error), +} + +impl From<mpsc::SendError<Vec<u8>>> for Error { + fn from(_: mpsc::SendError<Vec<u8>>) -> Self { + Self::MpscSendU8Vec + } +} + +pub type Result<T> = std::result::Result<T, Error>; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7edf3bf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +mod error; +pub use error::*; diff --git a/src/main.rs b/src/main.rs index e7a11a9..299e0c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,111 @@ -fn main() { - println!("Hello, world!"); +use std::io::Read; +use std::net::{SocketAddr, UdpSocket}; +use std::os::fd::{AsRawFd, RawFd}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +use pcap::Capture; +use ringbuf::{HeapRb, Rb}; +use rsdsl_netlinkd::link; +use rsdsl_udpdumpd::Result; + +fn main() -> Result<()> { + let devices = [ + "wlan0", "eth0", "eth0.10", "eth0.20", "eth0.30", "eth0.40", "eth1", "ppp0", "dslite0", + "he6in4", + ]; + + let clt = Arc::new(Mutex::new(None)); + let rb = Arc::new(Mutex::new(HeapRb::new(2000))); + + let sock = UdpSocket::bind("[::]:5555")?; + + let (mut r, w) = os_pipe::pipe()?; + let fd = w.as_raw_fd(); + + for dev in devices { + thread::spawn(move || loop { + if let Err(e) = link::wait_up(dev.to_owned()) { + println!("can't wait for {}: {}", dev, e); + + thread::sleep(Duration::from_secs(8)); + continue; + } + + match capture(dev, fd) { + Ok(_) => unreachable!(), + Err(e) => println!("can't capture on {}: {}", dev, e), + } + + thread::sleep(Duration::from_secs(8)); + }); + } + + let sock2 = sock.try_clone()?; + let clt2 = clt.clone(); + let rb2 = rb.clone(); + thread::spawn(move || loop { + match recv_ctl(&sock2, clt2.clone(), rb2.clone()) { + Ok(_) => {} + Err(e) => println!("can't recv control packets: {}", e), + } + }); + + loop { + let mut buf = [0; 1600]; + let n = r.read(&mut buf)?; + let buf = &buf[..n]; + + rb.lock() + .expect("packet ring buffer mutex is poisoned") + .push_overwrite(buf.to_vec()); + + let mut clt = clt.lock().expect("client address mutex is poisoned"); + if let Some(addr) = *clt { + match sock.send_to(buf, addr) { + Ok(_) => {} + Err(e) => { + *clt = None; + println!("can't send pcap pkt: {}", e); + } + } + } + } +} + +fn recv_ctl( + sock: &UdpSocket, + clt: Arc<Mutex<Option<SocketAddr>>>, + rb: Arc<Mutex<HeapRb<Vec<u8>>>>, +) -> Result<()> { + let mut buf = [0; 0]; + let (_, raddr) = sock.recv_from(&mut buf)?; + + for pkt in rb + .lock() + .expect("packet ring buffer mutex is poisoned") + .iter() + { + sock.send_to(pkt, raddr)?; + } + + *clt.lock().expect("client address mutex is poisoned") = Some(raddr); + + println!("connect {}", raddr); + Ok(()) +} + +fn capture(dev: &str, fd: RawFd) -> Result<()> { + println!("capturing on {}", dev); + + let mut cap = Capture::from_device(dev)?.immediate_mode(true).open()?; + let mut savefile = unsafe { cap.savefile_raw_fd(fd)? }; + + loop { + let pkt = cap.next_packet()?; + + savefile.write(&pkt); + savefile.flush()?; + } } |