runnel-rs 0.2.2

A Rust proxy and tunnel toolbox with WireGuard-style, TUN, SOCKS, and TLS-based transports.
Documentation
use anyhow::Error;

const NOISY_PATTERNS: &[&str] = &[
    "peer closed connection without sending TLS close_notify",
    "Broken pipe (os error 32)",
    "Connection reset by peer (os error 54)",
    "Connection reset by peer (os error 104)",
    "early eof",
    "UDP ASSOCIATE is not supported yet",
];

pub fn is_noisy_disconnect(err: &Error) -> bool {
    err.chain().any(|cause| {
        let text = cause.to_string();
        NOISY_PATTERNS.iter().any(|pattern| text.contains(pattern))
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn noisy_disconnect_matches_wrapped_broken_pipe() {
        let err = Error::new(std::io::Error::from_raw_os_error(32)).context("direct relay failed");
        assert!(is_noisy_disconnect(&err));
    }

    #[test]
    fn noisy_disconnect_matches_close_notify_message() {
        let err = anyhow::anyhow!(
            "failed to read server response: peer closed connection without sending TLS close_notify"
        );
        assert!(is_noisy_disconnect(&err));
    }

    #[test]
    fn timeouts_stay_actionable() {
        let err = anyhow::anyhow!("direct connect timed out");
        assert!(!is_noisy_disconnect(&err));
    }

    #[test]
    fn early_eof_is_treated_as_noise() {
        let err = anyhow::anyhow!("early eof");
        assert!(is_noisy_disconnect(&err));
    }

    #[test]
    fn udp_associate_noise_is_downgraded() {
        let err = anyhow::anyhow!("UDP ASSOCIATE is not supported yet");
        assert!(is_noisy_disconnect(&err));
    }
}