mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-19 13:29:09 +00:00
Implement HTTP proxy authentication
This commit is contained in:
parent
d2aef08e3c
commit
0fb58bec5d
4 changed files with 57 additions and 27 deletions
|
@ -5,6 +5,7 @@ name = "tun2proxy"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base64 = { version = "0.21" }
|
||||||
clap = { version = "4.1", features = ["derive"] }
|
clap = { version = "4.1", features = ["derive"] }
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
34
README.md
34
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
|
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.
|
configured to listen on a local UDP port and communicates with the upstream DNS server via TCP.
|
||||||
|
|
||||||
## CLI
|
## CLI (unstable)
|
||||||
```
|
```
|
||||||
Tunnel interface to proxy.
|
Tunnel interface to proxy.
|
||||||
|
|
||||||
Usage: tun2proxy --tun <name> --proxy <type> --addr <ip:port>
|
Usage: tun2proxy [OPTIONS] --tun <name> --proxy <type> --addr <ip:port>
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-t, --tun <name> Name of the tun interface
|
-t, --tun <name>
|
||||||
-p, --proxy <type> What proxy type to run [possible values: socks5, http]
|
Name of the tun interface
|
||||||
-a, --addr <ip:port> Server address with format ip:port
|
|
||||||
-h, --help Print help (see more with '--help')
|
-p, --proxy <type>
|
||||||
-V, --version Print version
|
What proxy type to run
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
- socks5: SOCKS5 server to use
|
||||||
|
- http: HTTP server to use
|
||||||
|
|
||||||
|
-a, --addr <ip:port>
|
||||||
|
Server address with format ip:port
|
||||||
|
|
||||||
|
--username <username>
|
||||||
|
Username for authentication
|
||||||
|
|
||||||
|
--password <password>
|
||||||
|
Password for authentication
|
||||||
|
|
||||||
|
-h, --help
|
||||||
|
Print help (see a summary with '-h')
|
||||||
|
|
||||||
|
-V, --version
|
||||||
|
Print version
|
||||||
```
|
```
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Authentication for SOCKS (plain) and HTTP (base64)
|
|
||||||
- UDP support for SOCKS
|
- UDP support for SOCKS
|
||||||
- Virtual DNS
|
- Virtual DNS
|
||||||
|
|
47
src/http.rs
47
src/http.rs
|
@ -2,6 +2,7 @@ use crate::tun2proxy::{
|
||||||
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
|
Connection, ConnectionManager, Credentials, IncomingDataEvent, IncomingDirection,
|
||||||
OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy,
|
OutgoingDataEvent, OutgoingDirection, ProxyError, TcpProxy,
|
||||||
};
|
};
|
||||||
|
use base64::Engine;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
@ -25,28 +26,36 @@ pub struct HttpConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpConnection {
|
impl HttpConnection {
|
||||||
fn new(connection: &Connection) -> Self {
|
fn new(connection: &Connection, manager: std::rc::Rc<dyn ConnectionManager>) -> Self {
|
||||||
let mut result = Self {
|
let mut server_outbuf: VecDeque<u8> = 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,
|
state: HttpState::ExpectStatusCode,
|
||||||
client_inbuf: Default::default(),
|
client_inbuf: Default::default(),
|
||||||
server_inbuf: Default::default(),
|
server_inbuf: Default::default(),
|
||||||
client_outbuf: Default::default(),
|
client_outbuf: Default::default(),
|
||||||
server_outbuf: Default::default(),
|
server_outbuf,
|
||||||
data_buf: Default::default(),
|
data_buf: Default::default(),
|
||||||
crlf_state: 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> {
|
fn state_change(&mut self) -> Result<(), ProxyError> {
|
||||||
|
@ -167,12 +176,14 @@ impl ConnectionManager for HttpManager {
|
||||||
fn new_connection(
|
fn new_connection(
|
||||||
&self,
|
&self,
|
||||||
connection: &Connection,
|
connection: &Connection,
|
||||||
_manager: std::rc::Rc<dyn ConnectionManager>,
|
manager: std::rc::Rc<dyn ConnectionManager>,
|
||||||
) -> Option<std::boxed::Box<dyn TcpProxy>> {
|
) -> Option<std::boxed::Box<dyn TcpProxy>> {
|
||||||
if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() {
|
if connection.proto != smoltcp::wire::IpProtocol::Tcp.into() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(std::boxed::Box::new(HttpConnection::new(connection)))
|
Some(std::boxed::Box::new(HttpConnection::new(
|
||||||
|
connection, manager,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_connection(&self, _: &Connection) {}
|
fn close_connection(&self, _: &Connection) {}
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct Args {
|
||||||
#[clap(long, value_name = "username")]
|
#[clap(long, value_name = "username")]
|
||||||
username: Option<String>,
|
username: Option<String>,
|
||||||
|
|
||||||
/// Username for authentication
|
/// Password for authentication
|
||||||
#[clap(long, value_name = "password")]
|
#[clap(long, value_name = "password")]
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue