diff --git a/Cargo.toml b/Cargo.toml index 3b70be0..66c04ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ name = "tun2proxy" version = "0.1.1" [dependencies] +base64 = { version = "0.21" } clap = { version = "4.1", features = ["derive"] } env_logger = "0.10" log = "0.4" diff --git a/README.md b/README.md index 28818dc..4e214d4 100644 --- a/README.md +++ b/README.md @@ -36,21 +36,39 @@ Note that if you paste these commands into a shell script, which you then run wi For DNS to work, you might need an additional tool like [dnsproxy](https://github.com/AdguardTeam/dnsproxy) that is configured to listen on a local UDP port and communicates with the upstream DNS server via TCP. -## CLI +## CLI (unstable) ``` Tunnel interface to proxy. -Usage: tun2proxy --tun --proxy --addr +Usage: tun2proxy [OPTIONS] --tun --proxy --addr Options: - -t, --tun Name of the tun interface - -p, --proxy What proxy type to run [possible values: socks5, http] - -a, --addr Server address with format ip:port - -h, --help Print help (see more with '--help') - -V, --version Print version + -t, --tun + Name of the tun interface + + -p, --proxy + What proxy type to run + + Possible values: + - socks5: SOCKS5 server to use + - http: HTTP server to use + + -a, --addr + Server address with format ip:port + + --username + Username for authentication + + --password + Password for authentication + + -h, --help + Print help (see a summary with '-h') + + -V, --version + Print version ``` ## TODO -- Authentication for SOCKS (plain) and HTTP (base64) - UDP support for SOCKS - Virtual DNS diff --git a/src/http.rs b/src/http.rs index dc3c610..fe72044 100644 --- a/src/http.rs +++ b/src/http.rs @@ -2,6 +2,7 @@ use crate::tun2proxy::{ Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection, OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy, }; +use base64::Engine; use std::collections::VecDeque; use std::net::SocketAddr; @@ -25,28 +26,36 @@ pub struct HttpConnection { } impl HttpConnection { - fn new(connection: &Connection) -> Self { - let mut result = Self { + fn new(connection: &Connection, manager: std::rc::Rc) -> Self { + let mut server_outbuf: VecDeque = VecDeque::new(); + { + let credentials = manager.get_credentials(); + server_outbuf.extend(b"CONNECT ".iter()); + server_outbuf.extend(connection.dst.to_string().as_bytes()); + server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter()); + server_outbuf.extend(connection.dst.to_string().as_bytes()); + server_outbuf.extend(b"\r\n".iter()); + if credentials.authenticate { + server_outbuf.extend(b"Proxy-Authorization: Basic "); + let mut auth_plain = credentials.username.clone(); + auth_plain.extend(b":".iter()); + auth_plain.extend(&credentials.password); + let auth_b64 = base64::engine::general_purpose::STANDARD.encode(auth_plain); + server_outbuf.extend(auth_b64.as_bytes().iter()); + server_outbuf.extend(b"\r\n".iter()); + } + server_outbuf.extend(b"\r\n".iter()); + } + + Self { state: HttpState::ExpectStatusCode, client_inbuf: Default::default(), server_inbuf: Default::default(), client_outbuf: Default::default(), - server_outbuf: Default::default(), + server_outbuf, data_buf: Default::default(), crlf_state: Default::default(), - }; - - result.server_outbuf.extend(b"CONNECT ".iter()); - result - .server_outbuf - .extend(connection.dst.to_string().as_bytes()); - result.server_outbuf.extend(b" HTTP/1.1\r\nHost: ".iter()); - result - .server_outbuf - .extend(connection.dst.to_string().as_bytes()); - result.server_outbuf.extend(b"\r\n\r\n".iter()); - - result + } } fn state_change(&mut self) -> Result<(), ProxyError> { @@ -167,12 +176,14 @@ impl ConnectionManager for HttpManager { fn new_connection( &self, connection: &Connection, - _manager: std::rc::Rc, + manager: std::rc::Rc, ) -> Option> { if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() { return None; } - Some(std::boxed::Box::new(HttpConnection::new(connection))) + Some(std::boxed::Box::new(HttpConnection::new( + connection, manager, + ))) } fn close_connection(&self, _: &Connection) {} diff --git a/src/main.rs b/src/main.rs index 9a68d07..b1fa359 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ struct Args { #[clap(long, value_name = "username")] username: Option, - /// Username for authentication + /// Password for authentication #[clap(long, value_name = "password")] password: Option, }