Add proxy subscription runtime support

Add daemon RPCs, Apple and GTK import flows, packet proxy runtime support, diagnostics, and BEPs for proxy subscription handling.

Redact subscription URL secrets from fetch errors before they reach logs or UI surfaces.
This commit is contained in:
JettChenT 2026-06-01 15:23:17 +08:00
parent 97c569fb35
commit d1638726ca
46 changed files with 15079 additions and 456 deletions

View file

@ -4,7 +4,9 @@ use burrow::{
grpc_defs::{
Empty, Network, NetworkType, State, TailnetDiscoverRequest, TailnetLoginCancelRequest,
TailnetLoginStartRequest, TailnetLoginStatusRequest, TailnetProbeRequest,
ProxySubscriptionApplyRequest, ProxySubscriptionImportRequest,
},
proxy_subscription::ProxySubscriptionPayload,
BurrowClient,
};
use std::{path::PathBuf, sync::OnceLock};
@ -54,6 +56,27 @@ pub struct TailnetLoginStatus {
pub health: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ProxySubscriptionPreview {
pub suggested_name: String,
pub detected_format: String,
pub compatible_count: i32,
pub rejected_count: i32,
pub nodes: Vec<ProxyNodePreview>,
pub warnings: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ProxyNodePreview {
pub ordinal: i32,
pub name: String,
pub protocol: String,
pub server: String,
pub port: i32,
pub warnings: Vec<String>,
pub runtime_supported: bool,
}
pub fn default_tailnet_authority() -> &'static str {
MANAGED_TAILSCALE_AUTHORITY
}
@ -216,6 +239,63 @@ pub async fn add_tailnet(
add_network(NetworkType::Tailnet, payload).await
}
pub async fn preview_proxy_subscription(url: String) -> Result<ProxySubscriptionPreview> {
let mut client = BurrowClient::from_uds().await?;
let response = timeout(
Duration::from_secs(20),
client
.proxy_subscription_client
.preview_import(ProxySubscriptionImportRequest { url }),
)
.await
.context("timed out previewing proxy subscription")??
.into_inner();
Ok(ProxySubscriptionPreview {
suggested_name: response.suggested_name,
detected_format: response.detected_format,
compatible_count: response.compatible_count,
rejected_count: response.rejected_count,
nodes: response
.node
.into_iter()
.map(|node| ProxyNodePreview {
ordinal: node.ordinal,
name: node.name,
protocol: node.protocol,
server: node.server,
port: node.port,
warnings: node.warnings,
runtime_supported: node.runtime_supported,
})
.collect(),
warnings: response.warnings,
})
}
pub async fn add_proxy_subscription(
url: String,
name: String,
selected_ordinal: Option<i32>,
) -> Result<i32> {
let id = next_network_id().await?;
let mut client = BurrowClient::from_uds().await?;
timeout(
Duration::from_secs(25),
client
.proxy_subscription_client
.apply_import(ProxySubscriptionApplyRequest {
id,
url,
name,
selected_ordinal: selected_ordinal.unwrap_or(-1),
}),
)
.await
.context("timed out importing proxy subscription")??;
Ok(id)
}
pub async fn discover_tailnet(email: String) -> Result<TailnetDiscovery> {
let mut client = BurrowClient::from_uds().await?;
let response = timeout(
@ -328,6 +408,12 @@ fn summarize_network(network: &Network) -> NetworkSummary {
match network.r#type() {
NetworkType::WireGuard => summarize_wireguard(network),
NetworkType::Tailnet => summarize_tailnet(network),
NetworkType::Trojan => NetworkSummary {
id: network.id,
title: "Legacy Trojan Proxy".to_owned(),
detail: "Unsupported SOCKS-era profile. Import a proxy subscription instead.".to_owned(),
},
NetworkType::ProxySubscription => summarize_proxy_subscription(network),
}
}
@ -372,6 +458,21 @@ fn summarize_tailnet(network: &Network) -> NetworkSummary {
}
}
fn summarize_proxy_subscription(network: &Network) -> NetworkSummary {
match serde_json::from_slice::<ProxySubscriptionPayload>(&network.payload) {
Ok(payload) => NetworkSummary {
id: network.id,
title: payload.name.clone(),
detail: burrow::proxy_subscription::summarize_payload(&payload),
},
Err(error) => NetworkSummary {
id: network.id,
title: "Proxy Subscription".to_owned(),
detail: format!("Unable to read proxy subscription payload: {error}"),
},
}
}
fn decode_tailnet_status(
response: burrow::grpc_defs::TailnetLoginStatusResponse,
) -> TailnetLoginStatus {