Skip to main content

relay_core_lib/capture/
source.rs

1use std::net::SocketAddr;
2use std::future::Future;
3use std::pin::Pin;
4use tokio::io::{AsyncRead, AsyncWrite};
5
6/// Represents an incoming connection from any source (TCP Listener, eBPF, TUN, etc.)
7pub struct IncomingConnection<IO> {
8    pub stream: IO,
9    pub client_addr: SocketAddr,
10    /// Original destination address (if known via TPROXY/eBPF/NAT lookup)
11    pub target_addr: Option<SocketAddr>, 
12}
13
14/// Trait for capturing traffic.
15/// This abstracts away the difference between a simple TCP Listener, 
16/// a Transparent Proxy (TPROXY), or a TUN interface with a user-space stack.
17pub trait CaptureSource {
18    type IO: AsyncRead + AsyncWrite + Unpin + Send + 'static;
19
20    /// Accept the next connection from the source
21    #[allow(clippy::type_complexity)]
22    fn accept(&mut self) -> Pin<Box<dyn Future<Output = crate::error::Result<IncomingConnection<Self::IO>>> + Send + '_>>;
23
24    /// Returns the addresses this source is listening on (for loop detection)
25    fn listen_addrs(&self) -> Vec<SocketAddr> {
26        vec![]
27    }
28}
29
30// Implement CaptureSource for Tokio TcpListener (Standard Explicit Proxy)
31use tokio::net::TcpListener;
32
33pub struct TcpCaptureSource {
34    listener: TcpListener,
35}
36
37impl TcpCaptureSource {
38    pub fn new(listener: TcpListener) -> Self {
39        Self { listener }
40    }
41}
42
43impl CaptureSource for TcpCaptureSource {
44    type IO = tokio::net::TcpStream;
45
46    fn accept(&mut self) -> Pin<Box<dyn Future<Output = crate::error::Result<IncomingConnection<Self::IO>>> + Send + '_>> {
47        Box::pin(async move {
48            let (stream, client_addr) = self.listener.accept().await?;
49            Ok(IncomingConnection {
50                stream,
51                client_addr,
52                target_addr: None, // Standard Proxy doesn't know target until parsing HTTP
53            })
54        })
55    }
56
57    fn listen_addrs(&self) -> Vec<SocketAddr> {
58        if let Ok(addr) = self.listener.local_addr() {
59            vec![addr]
60        } else {
61            vec![]
62        }
63    }
64}