1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2024 Google LLC 2*cf78ab8cSAndroid Build Coastguard Worker // 3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*cf78ab8cSAndroid Build Coastguard Worker // 7*cf78ab8cSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*cf78ab8cSAndroid Build Coastguard Worker // 9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License. 14*cf78ab8cSAndroid Build Coastguard Worker 15*cf78ab8cSAndroid Build Coastguard Worker use crate::util::{into_raw_descriptor, ProxyConfig}; 16*cf78ab8cSAndroid Build Coastguard Worker use crate::{connector::Connector, error::Error}; 17*cf78ab8cSAndroid Build Coastguard Worker use libslirp_rs::libslirp::{ProxyConnect, ProxyManager}; 18*cf78ab8cSAndroid Build Coastguard Worker use log::{debug, warn}; 19*cf78ab8cSAndroid Build Coastguard Worker use std::net::SocketAddr; 20*cf78ab8cSAndroid Build Coastguard Worker use std::sync::Arc; 21*cf78ab8cSAndroid Build Coastguard Worker use tokio::runtime::Runtime; 22*cf78ab8cSAndroid Build Coastguard Worker 23*cf78ab8cSAndroid Build Coastguard Worker /// # Manager 24*cf78ab8cSAndroid Build Coastguard Worker /// 25*cf78ab8cSAndroid Build Coastguard Worker /// The `Manager` struct implements the `ProxyManager` trait from 26*cf78ab8cSAndroid Build Coastguard Worker /// `libslirp_rs`. It is responsible for managing TCP connections 27*cf78ab8cSAndroid Build Coastguard Worker /// through an HTTP proxy using the `Connector` struct. 28*cf78ab8cSAndroid Build Coastguard Worker /// 29*cf78ab8cSAndroid Build Coastguard Worker /// The `Manager` uses a `tokio::runtime::Runtime` to spawn tasks for 30*cf78ab8cSAndroid Build Coastguard Worker /// establishing proxy connections. It takes a proxy configuration 31*cf78ab8cSAndroid Build Coastguard Worker /// string as input, which is parsed into a `ProxyConfig` to create a 32*cf78ab8cSAndroid Build Coastguard Worker /// `Connector` instance. 33*cf78ab8cSAndroid Build Coastguard Worker /// 34*cf78ab8cSAndroid Build Coastguard Worker /// The `try_connect` method attempts to establish a connection to the 35*cf78ab8cSAndroid Build Coastguard Worker /// given `SocketAddr` through the proxy. If successful, it calls the 36*cf78ab8cSAndroid Build Coastguard Worker /// `proxy_connect` function with the raw file descriptor of the 37*cf78ab8cSAndroid Build Coastguard Worker /// connected socket. 38*cf78ab8cSAndroid Build Coastguard Worker /// 39*cf78ab8cSAndroid Build Coastguard Worker /// # Example 40*cf78ab8cSAndroid Build Coastguard Worker /// 41*cf78ab8cSAndroid Build Coastguard Worker /// ``` 42*cf78ab8cSAndroid Build Coastguard Worker /// use std::net::SocketAddr; 43*cf78ab8cSAndroid Build Coastguard Worker /// use libslirp_rs::libslirp::ProxyConnect; 44*cf78ab8cSAndroid Build Coastguard Worker /// 45*cf78ab8cSAndroid Build Coastguard Worker /// struct MyProxyConnect; 46*cf78ab8cSAndroid Build Coastguard Worker /// 47*cf78ab8cSAndroid Build Coastguard Worker /// impl ProxyConnect for MyProxyConnect { 48*cf78ab8cSAndroid Build Coastguard Worker /// fn proxy_connect(&self, fd: i32, sockaddr: SocketAddr) { 49*cf78ab8cSAndroid Build Coastguard Worker /// // Handle the connected socket 50*cf78ab8cSAndroid Build Coastguard Worker /// } 51*cf78ab8cSAndroid Build Coastguard Worker /// } 52*cf78ab8cSAndroid Build Coastguard Worker /// 53*cf78ab8cSAndroid Build Coastguard Worker /// #[tokio::main] 54*cf78ab8cSAndroid Build Coastguard Worker /// async fn main() { 55*cf78ab8cSAndroid Build Coastguard Worker /// } 56*cf78ab8cSAndroid Build Coastguard Worker /// ``` 57*cf78ab8cSAndroid Build Coastguard Worker pub struct Manager { 58*cf78ab8cSAndroid Build Coastguard Worker runtime: Arc<Runtime>, 59*cf78ab8cSAndroid Build Coastguard Worker connector: Connector, 60*cf78ab8cSAndroid Build Coastguard Worker } 61*cf78ab8cSAndroid Build Coastguard Worker 62*cf78ab8cSAndroid Build Coastguard Worker impl Manager { new(proxy: &str) -> Result<Self, Error>63*cf78ab8cSAndroid Build Coastguard Worker pub fn new(proxy: &str) -> Result<Self, Error> { 64*cf78ab8cSAndroid Build Coastguard Worker let config = ProxyConfig::from_string(&proxy)?; 65*cf78ab8cSAndroid Build Coastguard Worker Ok(Self { 66*cf78ab8cSAndroid Build Coastguard Worker runtime: Arc::new(Runtime::new()?), 67*cf78ab8cSAndroid Build Coastguard Worker connector: Connector::new(config.addr, config.username, config.password), 68*cf78ab8cSAndroid Build Coastguard Worker }) 69*cf78ab8cSAndroid Build Coastguard Worker } 70*cf78ab8cSAndroid Build Coastguard Worker } 71*cf78ab8cSAndroid Build Coastguard Worker 72*cf78ab8cSAndroid Build Coastguard Worker impl ProxyManager for Manager { 73*cf78ab8cSAndroid Build Coastguard Worker /// Attempts to establish a TCP connection to the given `sockaddr` through the proxy. 74*cf78ab8cSAndroid Build Coastguard Worker /// 75*cf78ab8cSAndroid Build Coastguard Worker /// This function spawns a new task in the `tokio` runtime to handle the connection process. 76*cf78ab8cSAndroid Build Coastguard Worker /// If the connection is successful, it calls the `proxy_connect` function of the provided 77*cf78ab8cSAndroid Build Coastguard Worker /// `ProxyConnect` object with the raw file descriptor of the connected socket. 78*cf78ab8cSAndroid Build Coastguard Worker /// 79*cf78ab8cSAndroid Build Coastguard Worker /// # Arguments 80*cf78ab8cSAndroid Build Coastguard Worker /// 81*cf78ab8cSAndroid Build Coastguard Worker /// * `sockaddr` - The target socket address to connect to. 82*cf78ab8cSAndroid Build Coastguard Worker /// * `connect_id` - An identifier for the connection. 83*cf78ab8cSAndroid Build Coastguard Worker /// * `connect_func` - A `ProxyConnect` object that will be called with the connected socket. 84*cf78ab8cSAndroid Build Coastguard Worker /// 85*cf78ab8cSAndroid Build Coastguard Worker /// # Returns 86*cf78ab8cSAndroid Build Coastguard Worker /// 87*cf78ab8cSAndroid Build Coastguard Worker /// `true` if the connection attempt was initiated, `false` otherwise. try_connect( &self, sockaddr: SocketAddr, connect_id: usize, connect_func: Box<dyn ProxyConnect + Send>, ) -> bool88*cf78ab8cSAndroid Build Coastguard Worker fn try_connect( 89*cf78ab8cSAndroid Build Coastguard Worker &self, 90*cf78ab8cSAndroid Build Coastguard Worker sockaddr: SocketAddr, 91*cf78ab8cSAndroid Build Coastguard Worker connect_id: usize, 92*cf78ab8cSAndroid Build Coastguard Worker connect_func: Box<dyn ProxyConnect + Send>, 93*cf78ab8cSAndroid Build Coastguard Worker ) -> bool { 94*cf78ab8cSAndroid Build Coastguard Worker debug!("Connecting to {sockaddr:?} with connect ID {connect_id}"); 95*cf78ab8cSAndroid Build Coastguard Worker let connector = self.connector.clone(); 96*cf78ab8cSAndroid Build Coastguard Worker 97*cf78ab8cSAndroid Build Coastguard Worker self.runtime.handle().spawn(async move { 98*cf78ab8cSAndroid Build Coastguard Worker let fd = match connector.connect(sockaddr).await { 99*cf78ab8cSAndroid Build Coastguard Worker Ok(tcp_stream) => into_raw_descriptor(tcp_stream), 100*cf78ab8cSAndroid Build Coastguard Worker Err(e) => { 101*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to connect to proxy {}. {}", sockaddr, e); 102*cf78ab8cSAndroid Build Coastguard Worker -1 103*cf78ab8cSAndroid Build Coastguard Worker } 104*cf78ab8cSAndroid Build Coastguard Worker }; 105*cf78ab8cSAndroid Build Coastguard Worker connect_func.proxy_connect(fd, sockaddr); 106*cf78ab8cSAndroid Build Coastguard Worker }); 107*cf78ab8cSAndroid Build Coastguard Worker 108*cf78ab8cSAndroid Build Coastguard Worker true 109*cf78ab8cSAndroid Build Coastguard Worker } 110*cf78ab8cSAndroid Build Coastguard Worker 111*cf78ab8cSAndroid Build Coastguard Worker /// Removes a connection with the given `connect_id`. 112*cf78ab8cSAndroid Build Coastguard Worker /// 113*cf78ab8cSAndroid Build Coastguard Worker /// Currently, this function only logs a debug message. 114*cf78ab8cSAndroid Build Coastguard Worker /// 115*cf78ab8cSAndroid Build Coastguard Worker /// # Arguments 116*cf78ab8cSAndroid Build Coastguard Worker /// 117*cf78ab8cSAndroid Build Coastguard Worker /// * `connect_id` - The identifier of the connection to remove. remove(&self, connect_id: usize)118*cf78ab8cSAndroid Build Coastguard Worker fn remove(&self, connect_id: usize) { 119*cf78ab8cSAndroid Build Coastguard Worker debug!("Remove connect ID {}", connect_id); 120*cf78ab8cSAndroid Build Coastguard Worker } 121*cf78ab8cSAndroid Build Coastguard Worker } 122