rusnel 0.4.0

Rusnel is a fast TCP/UDP tunnel, transported over and encrypted using QUIC protocol. Single executable including both client and server
Documentation
//! Build script that bakes optional credential paths into the binary at
//! compile time. The intent is "Sliver-style" pre-configured deployments:
//! drop a CA/cert/key into env vars at `cargo build` time and the resulting
//! binary runs in mTLS mode by default with no flags required.
//!
//! All embedding is opt-in. None of the env vars set → empty constants → no
//! behaviour change vs. the unembedded build.
//!
//! Recognised env vars (all paths must exist at build time):
//!
//!   RUSNEL_EMBED_SERVER_ADDR     — default <host:port> the client will
//!                                  connect to when no positional arg given
//!   RUSNEL_EMBED_CA              — CA cert bundle (PEM)
//!   RUSNEL_EMBED_FINGERPRINT     — server fingerprint string for client
//!                                  fingerprint-pinning mode
//!   RUSNEL_EMBED_SERVER_NAME     — SNI name to send (matches a SAN in the
//!                                  server cert)
//!   RUSNEL_EMBED_SERVER_CERT     — server cert (PEM); enables server mode
//!                                  default
//!   RUSNEL_EMBED_SERVER_KEY      — server key (PEM); pairs with above
//!   RUSNEL_EMBED_CLIENT_CERT     — client cert (PEM); enables client mTLS
//!                                  default
//!   RUSNEL_EMBED_CLIENT_KEY      — client key (PEM); pairs with above
//!
//! For each path-style var, the file's bytes are baked in via include_bytes!
//! and the absolute path is recorded as a `cargo:rerun-if-changed` so cargo
//! re-runs this script when the file or env var changes.

// build.rs is a one-shot tool; panics here surface as clear cargo errors.
#![allow(clippy::unwrap_used)]

use std::env;
use std::fs;
use std::io::Write as _;
use std::path::{Path, PathBuf};

const PATH_VARS: &[&str] = &[
    "RUSNEL_EMBED_CA",
    "RUSNEL_EMBED_SERVER_CERT",
    "RUSNEL_EMBED_SERVER_KEY",
    "RUSNEL_EMBED_CLIENT_CERT",
    "RUSNEL_EMBED_CLIENT_KEY",
];

const STRING_VARS: &[&str] = &[
    "RUSNEL_EMBED_SERVER_ADDR",
    "RUSNEL_EMBED_FINGERPRINT",
    "RUSNEL_EMBED_SERVER_NAME",
];

fn main() {
    for v in PATH_VARS.iter().chain(STRING_VARS.iter()) {
        println!("cargo:rerun-if-env-changed={v}");
    }

    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set"));
    let dest = out_dir.join("embedded.rs");
    let mut f = fs::File::create(&dest).expect("failed to create embedded.rs");

    writeln!(
        f,
        "// This file is auto-generated by build.rs — do not edit.\n"
    )
    .unwrap();

    for var in PATH_VARS {
        let const_name = const_for_var(var);
        match env::var(var) {
            Ok(p) if !p.is_empty() => {
                let abs = absolutize(&p);
                if !abs.exists() {
                    panic!("{var}={} does not exist", abs.display());
                }
                println!("cargo:rerun-if-changed={}", abs.display());
                writeln!(
                    f,
                    "pub const {const_name}: Option<&[u8]> = Some(include_bytes!({:?}));",
                    abs
                )
                .unwrap();
            }
            _ => {
                writeln!(f, "pub const {const_name}: Option<&[u8]> = None;").unwrap();
            }
        }
    }

    for var in STRING_VARS {
        let const_name = const_for_var(var);
        match env::var(var) {
            Ok(s) if !s.is_empty() => {
                writeln!(f, "pub const {const_name}: Option<&str> = Some({:?});", s).unwrap();
            }
            _ => {
                writeln!(f, "pub const {const_name}: Option<&str> = None;").unwrap();
            }
        }
    }
}

/// Map e.g. `RUSNEL_EMBED_CA` → `EMBED_CA`.
fn const_for_var(var: &str) -> String {
    var.strip_prefix("RUSNEL_").unwrap_or(var).to_string()
}

fn absolutize(p: &str) -> PathBuf {
    let path = Path::new(p);
    if path.is_absolute() {
        path.to_path_buf()
    } else {
        let manifest = env::var("CARGO_MANIFEST_DIR")
            .map(PathBuf::from)
            .unwrap_or_else(|_| PathBuf::from("."));
        manifest.join(path)
    }
}