Open cattyhouse opened 5 months ago
After browsing the Trojan docs, and not willing to look at the source code yet :D I'm unsure whether the UDP streams are forwarded over TCP? To me that would make the most sense, if the goal is to pretend to be a normal HTTPS connection, but I could be wrong
i use this client daily, it is also written in rust, maybe you could take a look at how it does UDP, for your reference: https://github.com/p4gefau1t/trojan-r/tree/main/src/protocol/trojan
Thanks! I'll take a look.
A user on the forums has mentioned that UDP is implemented as UDP over TCP.
the issue with p4gefau1t(who is also the author of trojan-go)'s trojan-r project is that:
write()
with write_all()
method where possible in the codeopenssl pkcs8 -topk8 -nocrypt -in ECC.key -out pkcs8.key
for it to use, but i don't use it's server feature, caddy-trojan
as a server is more convenient. but since rustls has many breaking changes since then, it is not easy to upgrade to the latest version.everything else is perfect, latency / performance / memory usage etc.
here is the patch i used on that project:
diff --git a/Cargo.toml b/Cargo.toml
index d6691b5..9ef02cb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
name = "trojan-r"
version = "0.1.0"
authors = ["Page Fault <p4gefau1t@gmail.com>"]
-edition = "2018"
+edition = "2021"
[dependencies]
bytes = "1.0"
@@ -25,8 +25,8 @@ futures-util = "0.3"
lto = true
[features]
-default = ["full"]
+default = ["client"]
client = []
server = []
forward = []
-full = ["client", "server", "forward"]
\ No newline at end of file
+full = ["client", "server", "forward"]
diff --git a/src/protocol/dokodemo/acceptor.rs b/src/protocol/dokodemo/acceptor.rs
index a0437ad..e0ef456 100644
--- a/src/protocol/dokodemo/acceptor.rs
+++ b/src/protocol/dokodemo/acceptor.rs
@@ -69,8 +69,7 @@ impl ProxyAcceptor for DokodemoAcceptor {
type US = DokodemoUdpStream;
async fn accept(&self) -> Result<AcceptResult<Self::TS, Self::US>> {
- if !self.udp_spawned.load(Ordering::Relaxed) {
- self.udp_spawned.store(true, Ordering::Relaxed);
+ if !self.udp_spawned.swap(true,Ordering::Relaxed) {
let socket = Arc::new(UdpSocket::bind(self.tcp_listener.local_addr().unwrap()).await?);
let udp_stream = DokodemoUdpStream {
inner: socket,
diff --git a/src/protocol/mux/mod.rs b/src/protocol/mux/mod.rs
index 882a42e..35c0e98 100644
--- a/src/protocol/mux/mod.rs
+++ b/src/protocol/mux/mod.rs
@@ -89,7 +89,7 @@ impl RequestHeader {
cursor.put_u8(cmd);
addr.write_to_buf(cursor);
- w.write(&buf).await?;
+ w.write_all(&buf).await?;
Ok(())
}
}
@@ -138,9 +138,9 @@ impl MuxFrame {
cursor.put_u8(command);
cursor.put_u16_le(data_length as u16);
cursor.put_u32_le(stream_id);
- writer.write(&buf).await?;
+ writer.write_all(&buf).await?;
if let MuxFrame::Push(f) = self {
- writer.write(&f.data).await?;
+ writer.write_all(&f.data).await?;
}
writer.flush().await?;
Ok(())
diff --git a/src/protocol/socks5/mod.rs b/src/protocol/socks5/mod.rs
index fe6fd1c..2a6b587 100644
--- a/src/protocol/socks5/mod.rs
+++ b/src/protocol/socks5/mod.rs
@@ -114,7 +114,7 @@ impl TcpResponseHeader {
{
let mut buf = BytesMut::with_capacity(self.serialized_len());
self.write_to_buf(&mut buf);
- w.write(&buf).await?;
+ w.write_all(&buf).await?;
Ok(())
}
diff --git a/src/protocol/trojan/mod.rs b/src/protocol/trojan/mod.rs
index 1ab97b4..72e7e7a 100644
--- a/src/protocol/trojan/mod.rs
+++ b/src/protocol/trojan/mod.rs
@@ -122,7 +122,7 @@ impl RequestHeader {
addr.write_to_buf(cursor);
cursor.put_slice(crlf);
- w.write(&buf).await?;
+ w.write_all(&buf).await?;
Ok(())
}
}
@@ -173,7 +173,7 @@ impl UdpHeader {
self.address.write_to_buf(cursor);
cursor.put_u16(self.payload_len);
cursor.put_slice(b"\r\n");
- w.write(&buf).await?;
+ w.write_all(&buf).await?;
Ok(())
}
}
diff --git a/src/proxy/mod.rs b/src/proxy/mod.rs
index d0e3342..0f7736a 100644
--- a/src/proxy/mod.rs
+++ b/src/proxy/mod.rs
@@ -36,7 +36,7 @@ use crate::{
},
};
-const RELAY_BUFFER_SIZE: usize = 0x4000;
+const RELAY_BUFFER_SIZE: usize = 0x2000;
async fn copy_udp<R: UdpRead, W: UdpWrite>(r: &mut R, w: &mut W) -> io::Result<()> {
let mut buf = [0u8; RELAY_BUFFER_SIZE];
@@ -61,7 +61,7 @@ async fn copy_tcp<R: AsyncRead + Unpin, W: AsyncWrite + Unpin>(
if len == 0 {
break;
}
- w.write(&buf[..len]).await?;
+ w.write_all(&buf[..len]).await?;
w.flush().await?;
}
Ok(())
For my implementation, I think I will work on latency, performance and memory once I finish all the features that I think are important.
What are some things about the caddy-trojan
server that you find very convenient? I would like to make this software convenient to use as well.
caddy-trojan is a plugin for caddy, so it does these all in one:
Down side is that ( usually not a problem on server side):
These are some good features, I would like to implement the following
@cattyhouse regarding the UDP socks proxy, I'm curious about your use case. There doesn't seem to be many UDP SOCKS5 proxy clients out there, how do you usually use UDP over SOCKS5?
it is used in some cases like:
actually, there are other cases, but i don't use them.
right now i am using a tool called ipt2socks to turn socks5 to tproxy which does transparent proxying: {tcp udp} -> ipt2socks -> socks5 -> trojan client -> trojan server -> out, if udp is missing, this chain is not complete...
Yes, 1. and 2. are certainly interesting use cases.
For your use case with ipt2socks: your use case may also be satisfied if the client natively supported incoming transparent proxy connections (tcp & udp), correct?
Yes, that's right, if trojan client supports tproxy( trojan-go for instance ) then ipt2socks is not needed
trojan protocol can handle udp traffic, but this software does not support UDP.
For example dig @1.1.1.1 example.com via socks5 proxy.