geph4-client 4.99.0-actuallyfive.7

Geph client
Documentation
use anyhow::Context;
use smol::future::FutureExt;

use super::ConnectContext;
use crate::config::VpnMode;

#[cfg(target_os = "linux")]
mod linux_routing;

#[cfg(target_os = "windows")]
mod windows_routing;

#[cfg(unix)]
use std::os::unix::prelude::{AsRawFd, FromRawFd};

pub(super) async fn vpn_loop(ctx: ConnectContext) -> anyhow::Result<()> {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    if ctx.opt.vpn_mode == Some(VpnMode::InheritedFd) {
        let fd_num: i32 = std::env::var("GEPH_VPN_FD")
            .ok()
            .and_then(|e| e.parse().ok())
            .expect("must set GEPH_VPN_FD to a file descriptor in order to use inherited-fd mode");
        return unsafe { fd_vpn_loop(ctx, fd_num).await };
    }

    #[cfg(target_os = "linux")]
    if ctx.opt.vpn_mode == Some(VpnMode::TunNoRoute) {
        let device = configure_tun_device();
        return unsafe { fd_vpn_loop(ctx, device.as_raw_fd()).await };
    }

    #[cfg(target_os = "linux")]
    if ctx.opt.vpn_mode == Some(VpnMode::TunRoute) {
        let device = configure_tun_device();
        return unsafe {
            fd_vpn_loop(ctx.clone(), device.as_raw_fd())
                .race(linux_routing::routing_loop(ctx.clone()))
                .await
        };
    }

    #[cfg(target_os = "windows")]
    if ctx.opt.vpn_mode == Some(VpnMode::WinDivert) {
        return windows_routing::start_routing(ctx).await;
    }

    smol::future::pending().await
}

#[cfg(target_os = "linux")]
fn configure_tun_device() -> tun::platform::Device {
    let device = tun::platform::Device::new(
        tun::Configuration::default()
            .name("tun-geph")
            .address("100.64.89.64")
            .netmask("255.255.255.0")
            .destination("100.64.0.1")
            .mtu(16384)
            .up(),
    )
    .expect("could not initialize TUN device");
    device
}

#[cfg(any(target_os = "linux", target_os = "android"))]
async unsafe fn fd_vpn_loop(ctx: ConnectContext, fd_num: i32) -> anyhow::Result<()> {
    log::info!("entering fd_vpn_loop");

    use futures_util::{AsyncReadExt, AsyncWriteExt};

    let mut up_file = async_dup::Arc::new(async_dup::Mutex::new(
        smol::Async::new(std::fs::File::from_raw_fd(fd_num)).context("cannot init up_file")?,
    ));

    let mut dn_file = up_file.clone();

    let up_loop = async {
        let mut bts = vec![0; 65536];
        loop {
            let n = up_file.read(&mut bts).await?;

            ctx.tunnel.send_vpn(&bts[..n]).await?;
        }
    };
    let dn_loop = async {
        loop {
            let bts = ctx.tunnel.recv_vpn().await?;
            dn_file.write_all(&bts).await?;
        }
    };
    up_loop.race(dn_loop).await
}