Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Support CloudFlare Warp in VPN block #2100

Open
Bad3r opened this issue Nov 9, 2024 · 1 comment
Open

[Feature] Support CloudFlare Warp in VPN block #2100

Bad3r opened this issue Nov 9, 2024 · 1 comment

Comments

@Bad3r
Copy link

Bad3r commented Nov 9, 2024

It would be great if the VPN block could indicate if CloudFlare Warp is connected.

@Bad3r
Copy link
Author

Bad3r commented Dec 7, 2024

my bad attempt using AI to do this since I don't know rust:

use std::process::Stdio;
use tokio::process::Command;

use crate::blocks::prelude::*;

use super::{Driver, Status};

pub struct WarpDriver;

impl WarpDriver {
    pub async fn new() -> WarpDriver {
        WarpDriver
    }

    async fn run_network_command(arg: &str) -> Result<()> {
        Command::new("warp-cli")
            .args([arg])
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .spawn()
            .error(format!("Problem running warp-cli command: {arg}"))?
            .wait()
            .await
            .error(format!("Problem running warp-cli command: {arg}"))?;
        Ok(())
    }

    async fn find_line(stdout: &str, needle: &str) -> Option<String> {
        stdout
            .lines()
            .find(|s| s.contains(needle))
            .map(|s| s.to_owned())
    }
}

#[async_trait]
impl Driver for WarpDriver {
    async fn get_status(&self) -> Result<Status> {
        let stdout = Command::new("warp-cli")
            .args(["status"])
            .output()
            .await
            .error("Problem running warp-cli command")?
            .stdout;

        let stdout = String::from_utf8(stdout).error("warp-cli produced non-UTF8 output")?;
        let line_status = Self::find_line(&stdout, "Status:").await;

        if line_status.is_none() {
            return Ok(Status::Error);
        }
        let line_status = line_status.unwrap();

        if line_status.ends_with("Disconnected") {
            return Ok(Status::Disconnected);
        } else if line_status.ends_with("Connected") {
            return Ok(Status::Connected { country: String::from("Unknown"), country_flag: String::from("🌐") });
        }
        Ok(Status::Error)
    }

    async fn toggle_connection(&self, status: &Status) -> Result<()> {
        match status {
            Status::Connected { .. } => Self::run_network_command("disconnect").await?,
            Status::Disconnected => Self::run_network_command("connect").await?,
            Status::Error => (),
        }
        Ok(())
    }
}

issues and limitations:

  1. warp does not show up in network interfaces i.e it doesn't use something like tun0
  2. region and country does not affect warp since it just connects to the closest server.

currently I am using a shell script to monitor it instead:

#!/bin/sh

log_file="/var/log/cloudflare-warp/cfwarp_service_log.txt"
last_status=""

tail -F "$log_file" | {
    while IFS= read -r line; do
        case "$line" in
        *ResponseStatus:*)
            current_status=$(printf "%s" "$line" | awk -F'ResponseStatus: ' '{print $2}' | awk '{print $1}')
            if [ "$current_status" != "$last_status" ]; then
                if [ "$current_status" = "Connected" ] || [ "$current_status" = "Connecting" ]; then
                    notify-send -u normal "Warp Status" "$current_status"
                else
                    notify-send -u critical -t 10000 "Warp Status" "$current_status"
                fi
                last_status="$current_status"
            fi
            ;;
        esac
    done
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant