I want to implement a proxy server to forward traffic to upstream proxy server.
client <-> proxy server <-> upstream proxy server <-> ..... <-> target server
After searching for a long time, and ask GTP for help, below is http/https tunnel proxy
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
async fn handle_connection(mut inbound: TcpStream, target_addr: &str) -> io::Result<()> {
let mut buffer = [0; 1024];
let n = inbound.read(&mut buffer).await?;
let request = String::from_utf8_lossy(&buffer[..n]);
println!("request {:?}", request);
let mut outbound = TcpStream::connect(target_addr).await?;
println!("outbound {:?}", outbound);
if request.starts_with("CONNECT") {
inbound
.write_all(b"HTTP/1.1 200 Connection Established\r\n\r\n")
.await?;
}
let (mut ri, mut wi) = inbound.split();
let (mut ro, mut wo) = outbound.split();
let initial_data = &buffer[..n];
let write_initial = async {
if !initial_data.is_empty() {
wo.write_all(initial_data).await?;
}
io::copy(&mut ri, &mut wo).await
};
tokio::try_join!(write_initial, io::copy(&mut ro, &mut wi))?;
// tokio::try_join!(io::copy(&mut ri, &mut wo), io::copy(&mut ro, &mut wi))?;
Ok(())
}
#[tokio::main]
async fn main() -> io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8181").await?;
loop {
let (inbound, _) = listener.accept().await?;
tokio::spawn(async move {
let target_addr = "127.0.0.1:12345";
if let Err(e) = handle_connection(inbound, target_addr).await {
eprintln!("Failed to forward connection: {}", e);
}
});
}
}
This work for http traffic
$ curl -v 'http://httpbin.org/anything' -x http://localhost:8181
* Trying 127.0.0.1:8181...
* Connected to (nil) (127.0.0.1) port 8181 (#0)
> GET http://httpbin.org/anything HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.81.0
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Length: 373
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Connection: keep-alive
< Content-Type: application/json
< Date: Mon, 02 Sep 2024 12:39:53 GMT
< Keep-Alive: timeout=4
< Proxy-Connection: keep-alive
< Server: gunicorn/19.9.0
<
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Host": "httpbin.org",
"User-Agent": "curl/7.81.0",
"X-Amzn-Trace-Id": "Root=1-66d5b219-3fc519364e7b7fc100db86cc"
},
"json": null,
"method": "GET",
"origin": "x.y.z.k",
"url": "http://httpbin.org/anything"
}
* Connection #0 to host (nil) left intact
Not work on https traffic
$ curl -v 'https://httpbin.org/anything' -x http://localhost:8181
* Trying 127.0.0.1:8181...
* Connected to (nil) (127.0.0.1) port 8181 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to httpbin.org:443
> CONNECT httpbin.org:443 HTTP/1.1
> Host: httpbin.org:443
> User-Agent: curl/7.81.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 Connection Established
<
* Proxy replied 200 to CONNECT request
* CONNECT phase completed!
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* (5454) (IN), , Unknown (72):
* error:0A00010B:SSL routines::wrong version number
* Closing connection 0
curl: (35) error:0A00010B:SSL routines::wrong version number
I don't know where I went wrong, but when I asked gtp multiple times, it gave thesame and incorrect answers
I am very grateful for any suggestions.