diff --git a/README-EN.md b/README-EN.md index f7ebc78..f4a072c 100644 --- a/README-EN.md +++ b/README-EN.md @@ -33,34 +33,31 @@ $ cargo install fourth ## Configuration -Fourth will read yaml format configuration file from `/etc/fourth/config.yaml`, here is an example: +Fourth will read yaml format configuration file from `/etc/fourth/config.yaml`, here is an minimal viable example: ```yaml version: 1 log: info servers: - example_server: - listen: - - "0.0.0.0:443" - - "[::]:443" - tls: true # Enable TLS features like SNI - sni: - proxy.example.com: proxy - www.example.com: nginx - default: ban - relay_server: + proxy_server: listen: - "127.0.0.1:8081" default: remote upstream: - nginx: "127.0.0.1:8080" - proxy: "127.0.0.1:1024" - remote: "www.remote.example.com:8082" # proxy to remote address + remote: "tcp://www.remote.example.com:8082" # proxy to remote address ``` -Built-in two upstreams: ban(terminate connection immediately), echo +Built-in two upstreams: ban(terminate connection immediately), echo. For detailed configuration, check [this example](./example-config.yaml). + +## Performance Benchmark + +Tested on 4C2G server: + +Use fourth to proxy to Nginx(QPS of direct connection: ~120000): ~70000 req/s (Command: `wrk -t200 -c1000 -d120s --latency http://proxy-server:8081`) + +Use fourth to proxy to local iperf3: 8Gbps ## Thanks diff --git a/src/servers/protocol/kcp.rs b/src/servers/protocol/kcp.rs index f587431..c5d3028 100644 --- a/src/servers/protocol/kcp.rs +++ b/src/servers/protocol/kcp.rs @@ -67,31 +67,33 @@ async fn process( match upstream { Upstream::Ban => { let _ = inbound.shutdown(); - Ok(()) } Upstream::Echo => { let (mut ri, mut wi) = io::split(inbound); let inbound_to_inbound = copy(&mut ri, &mut wi); let bytes_tx = inbound_to_inbound.await; debug!("Bytes read: {:?}", bytes_tx); - Ok(()) } Upstream::Custom(custom) => { - let outbound = TcpStream::connect(custom.addr.clone()).await?; + match custom.protocol.as_ref() { + "tcp" => { + let outbound = TcpStream::connect(custom.addr.clone()).await?; - let (mut ri, mut wi) = io::split(inbound); - let (mut ro, mut wo) = io::split(outbound); + let (mut ri, mut wi) = io::split(inbound); + let (mut ro, mut wo) = io::split(outbound); - let inbound_to_outbound = copy(&mut ri, &mut wo); - let outbound_to_inbound = copy(&mut ro, &mut wi); + let inbound_to_outbound = copy(&mut ri, &mut wo); + let outbound_to_inbound = copy(&mut ro, &mut wi); - let (bytes_tx, bytes_rx) = try_join(inbound_to_outbound, outbound_to_inbound).await?; + let (bytes_tx, bytes_rx) = try_join(inbound_to_outbound, outbound_to_inbound).await?; - debug!("Bytes read: {:?} write: {:?}", bytes_tx, bytes_rx); - - Ok(()) + debug!("Bytes read: {:?} write: {:?}", bytes_tx, bytes_rx); + } + _ => {} + } } - } + }; + Ok(()) } async fn copy<'a, R, W>(reader: &'a mut R, writer: &'a mut W) -> io::Result diff --git a/src/servers/protocol/tcp.rs b/src/servers/protocol/tcp.rs index 2340881..99465bd 100644 --- a/src/servers/protocol/tcp.rs +++ b/src/servers/protocol/tcp.rs @@ -86,31 +86,33 @@ async fn process( match upstream { Upstream::Ban => { let _ = inbound.shutdown(); - Ok(()) } Upstream::Echo => { let (mut ri, mut wi) = io::split(inbound); let inbound_to_inbound = copy(&mut ri, &mut wi); let bytes_tx = inbound_to_inbound.await; debug!("Bytes read: {:?}", bytes_tx); - Ok(()) } Upstream::Custom(custom) => { - let outbound = TcpStream::connect(custom.addr.clone()).await?; + match custom.protocol.as_ref() { + "tcp" => { + let outbound = TcpStream::connect(custom.addr.clone()).await?; - let (mut ri, mut wi) = io::split(inbound); - let (mut ro, mut wo) = io::split(outbound); + let (mut ri, mut wi) = io::split(inbound); + let (mut ro, mut wo) = io::split(outbound); - let inbound_to_outbound = copy(&mut ri, &mut wo); - let outbound_to_inbound = copy(&mut ro, &mut wi); + let inbound_to_outbound = copy(&mut ri, &mut wo); + let outbound_to_inbound = copy(&mut ro, &mut wi); - let (bytes_tx, bytes_rx) = try_join(inbound_to_outbound, outbound_to_inbound).await?; + let (bytes_tx, bytes_rx) = try_join(inbound_to_outbound, outbound_to_inbound).await?; - debug!("Bytes read: {:?} write: {:?}", bytes_tx, bytes_rx); - - Ok(()) + debug!("Bytes read: {:?} write: {:?}", bytes_tx, bytes_rx); + } + _ => {} + } } - } + }; + Ok(()) } async fn copy<'a, R, W>(reader: &'a mut R, writer: &'a mut W) -> io::Result