webrtc_sniffer/
net.rs

1use std::net::{IpAddr, SocketAddr};
2
3use etherparse::{err::packet, NetSlice, SlicedPacket, TransportSlice};
4use pcap::{Activated, Capture, Packet, PacketCodec, PacketIter, Savefile};
5use thiserror::Error;
6
7pub struct UdpIter<S: Activated + ?Sized> {
8    inner: PacketIter<S, UdpCodec>,
9}
10
11#[derive(Debug, Error)]
12pub enum DissectError {
13    #[error("{0}")]
14    Cap(#[from] pcap::Error),
15    #[error("{0}")]
16    ParsePacket(#[from] packet::SliceError),
17}
18
19impl<S: Activated + ?Sized> UdpIter<S> {
20    pub fn new(capture: Capture<S>, file: Option<Savefile>) -> Self {
21        UdpIter {
22            inner: capture.iter(UdpCodec { file }),
23        }
24    }
25}
26
27impl<S: Activated + ?Sized> Iterator for UdpIter<S> {
28    type Item = Result<(SocketAddr, SocketAddr, Box<[u8]>), DissectError>;
29
30    fn next(&mut self) -> Option<Self::Item> {
31        loop {
32            match self
33                .inner
34                .next()?
35                .map_err(DissectError::Cap)
36                .and_then(|x| x)
37                .transpose()
38            {
39                Some(v) => break Some(v),
40                None => continue,
41            }
42        }
43    }
44}
45
46struct UdpCodec {
47    file: Option<Savefile>,
48}
49
50impl PacketCodec for UdpCodec {
51    type Item = Result<Option<(SocketAddr, SocketAddr, Box<[u8]>)>, DissectError>;
52
53    fn decode(&mut self, packet: Packet<'_>) -> Self::Item {
54        let eth = SlicedPacket::from_ethernet(packet.data)?;
55        if let (Some(net), Some(transport)) = (eth.net, eth.transport) {
56            let (src_ip, dst_ip) = match net {
57                NetSlice::Ipv4(ip) => (
58                    IpAddr::V4(ip.header().source().into()),
59                    IpAddr::V4(ip.header().destination().into()),
60                ),
61                NetSlice::Ipv6(ip) => (
62                    IpAddr::V6(ip.header().source().into()),
63                    IpAddr::V6(ip.header().destination().into()),
64                ),
65                NetSlice::Arp(_) => return Ok(None),
66            };
67            let (src_port, dst_port, slice) = match transport {
68                TransportSlice::Udp(udp) => {
69                    (udp.source_port(), udp.destination_port(), udp.payload())
70                }
71                _ => return Ok(None),
72            };
73            if let Some(file) = &mut self.file {
74                file.write(&packet);
75                file.flush()?;
76            }
77
78            Ok(Some((
79                SocketAddr::new(src_ip, src_port),
80                SocketAddr::new(dst_ip, dst_port),
81                slice.to_vec().into_boxed_slice(),
82            )))
83        } else {
84            Ok(None)
85        }
86    }
87}