SIP003u - UDP Extension for SIP003 Plugins
database64128 opened this issue Β· 28 comments
As a new generation of proxy protocols emerges, good robust UDP support has become a holy grail when designing a new proxy protocol. XTLS/Xray-core makes aggressive architectural changes and adds patches over v2ray to make the proxy act like a full-cone NAT when handling UDP traffic. Qv2ray/gun is an experimental proxy implementation that utilizes gRPC to proxy TCP and UDP traffic.
However, the original proposal of SIP003 didn't include support for UDP. The lack of UDP support has significantly limited the possible use cases of SIP003.
I'm starting this discussion in the community to draft an UDP extension for SIP003 plugins. Feel free to post your ideas and suggestions down there.
TODO
Edit to add draft proposal details.
Related issues/discussions
Mentions
Shadowsocks
Qv2ray
V2Fly
XTLS
Preliminary proposal by @studentmain:
- For Shadowsocks clients that can check local ports, before starting the plugin, check to make sure both TCP and UDP are available for the specified port. When the plugin is started, check if the plugin is listening for UDP on
SS_LOCAL_PORT
.- If the plugin is listening for UDP, the Shadowsocks client must proxy UDP traffic to the port.
- Otherwise, treat it as a vanilla SIP003 plugin.
- For Shadowsocks clients that cannot check local ports, the plugin must resort to other means to communicate its UDP support status to the Shadowsocks client.
- An SIP003u-compliant plugin must use
SS_LOCAL_ADDR
andSS_LOCAL_PORT
as the listening address and port for UDP. Client-side plugins must have UDP support. - No modifications are needed at Shadowsocks servers.
When the plugin is started, check if the plugin is listening for UDP on
SS_LOCAL_PORT
.
Why not just add a flag in configuration? For example, "plugin_mode": "tcp_and_udp"
.
The new plugin_mode
option in shadowsocks-rust does not communicate to plugins about UDP support. Plugins would have to define their own option, which could cause fragmentation.
Maybe we should reserve a special key in SS_PLUGIN_OPTIONS
for this purpose, and require that the shadowsocks client/server prepends the key-value pair to SS_PLUGIN_OPTIONS
when plugin_mode
is tcp_and_udp
. A few things to keep in mind:
- We must be very careful when choosing the special key. Collision with existing plugins could cause issues.
SIP003u=true
might be a good candidate. - How do existing plugins handle unknown keys in
SS_PLUGIN_OPTIONS
? Do they simply ignore them or abort? Maybe this should be clarified in an update to the SIP003 spec. SS_PLUGIN_OPTIONS
is not mandatory and some plugins might not check it at all.- We could also just drop
plugin_mode
and have the shadowsocks client and server check whetherSS_PLUGIN_OPTIONS
contains the special key. But that could confuse users of implementations or versions without SIP003u support.
So many caveats! We might as well start over and define new environment variables.
SS_CLIENT_PLUGIN_LISTEN_UDP
: Plugin's listen address inhost:port
form.IPV6_V6ONLY
MUST be turned off on supported platforms.SS_SERVER_PLUGIN_CONNECT_UDP
: The plugin forwards decrypted packets to this address.SS_PLUGIN_UDP_NAT_TIMEOUT_SEC
: UDP NAT timeout in seconds. Required when UDP is enabled.
The life cycle section in the spec also needs some clarification. What signal to send to the plugin process? How long to wait before sending SIGKILL? What about Windows?
- Send SIGTERM on Unix platforms.
- Wait up to 5 seconds.
- Windows support is optional. (
AttachConsole(plugin_pid)
+SetConsoleCtrlHandler(null, true)
+GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)
+SetConsoleCtrlHandler(null, false)
+FreeConsole()
)
If a plugin supports SIP003u, it will only need to provide a UDP tunnel, the process steps would be:
For the local plugin:
recv()
a UDP packet fromsslocal
, withpeer_addr
(A)- Check if there is an existed UDP tunnel for (A), if no, create one.
- Send all packets received with
peer_addr
= (A) into this tunnel.
For the server plugin:
- Accept a new connection (maybe a TCP connection)
- Create a new UDP socket that
connect()
tossserver
's UDP port - Read UDP packets from the connection and then
sendto
the UDP socket
So the implementation would be quite simple, and I don't think it actually need a NAT. Well, there should be a full-cone NAT in it.
https://github.com/zonyitoo/shadowsocks-yamux-plugin
This is a plugin that supports SIP003u. It use YAMUX protocol as TCP stream multiplexer.
I don't think plugins should know "plugin_mode"
, because it only affects the behavior of sslocal
and sserver
about which address to connect or listen. If a plugin supports SIP003u, it can just listen to both TCP and UDP.
Fair enough. I guess you could open a PR to update the spec doc and then close this issue?
It is still an experimental feature. Let's keep it open and see if there are any other comments.
I used this feature with shadowsocks-yamux-plugin for more than a week, everything works perfect as expected.
UDP (H3) felt more stable with UoT (supported by the shadowsocks-yamux-plugin) than direct UDP mode.
I came here by searching why whatsapp call is not working as calls happen over UDP and the outgoing udp is blocked, then it won't work. any update on udp over tcp support? this comment sums it up.
#180 (comment)
Does v2ray-plugin support UDP Extension ? I want something like v2ray-plugin work behind in nginx proxy but with UoT support.
Does v2ray-plugin support UDP Extension ? I want something like v2ray-plugin work behind in nginx proxy but with UoT support.
did you have any success? I tried with shadowsock-rust
and v2ray pluging for android. no luck. udp over tcp doesn't work at all.
Refined proposal:
SIP011: UDP Extension for SIP003 Plugins
1. Abstract
The original proposal of SIP003 didn't include support for UDP. The lack of UDP support has significantly limited the possible use cases of SIP003. There are reports that shadowsocks UDP data flows are blocked or detected by malicious third-parties. By allowing Plugins to support transporting UDP, it will be possible to implement features like UDP obfuscation, UDP-over-TCP.
2. Implementation Requirements
- The Plugin that supports SIP011 MUST supports SIP003.
Passing Arguments to a Plugin
Arguments are exactly the same as SIP003.
3. Implementation Details
3.1. Default Behavior
SIP011 is disabled by default in all shadowsocks implementations. Any plugins that support SIP011 should be able to run independently with implementations that only support SIP003.
3.2. Configuration
Shadowsocks implementation should add a new configuration key to enable SIP011. A recommended configuration key is "plugin_mode": "tcp_and_udp"
in the Basic Configuration format:
{
"plugin": "PLUGIN program",
"plugin_opts": "PLUGIN options",
// plugin_mode can be:
// - "tcp_only" (default) - SIP003
// - "tcp_and_udp" - SIP011
// - "udp_only" - SIP011
"plugin_mode": "tcp_and_udp"
}
3.3. Implementation
Plugins should start a UDP listener bind()
s to the same address and port exactly the same as SIP003. Specifically:
- For Plugin runs in local server (or client), it should create a UDP socket
bind()
s to the address specfied bySS_LOCAL_HOST
andSS_LOCAL_PORT
and receives local UDP packets from this address. - For Plugin runs in remote server (or server), it should send received UDP packets to the address specified by
SS_LOCAL_HOST
andSS_LOCAL_PORT
.
Does v2ray-plugin support UDP Extension ? I want something like v2ray-plugin work behind in nginx proxy but with UoT support.
Unfortunately no. V2Ray itself doesn't support UoT as far as I know.
@jan-bar hi, could I buy that plugin from you? Trying to setup UDP too.
@jan-bar if you dont mind, please update your readme page with contact details, we have custom case, perhaps we could hire you for some consultation. :)
Refined proposal:
SIP011: UDP Extension for SIP003 Plugins
1. Abstract
The original proposal of SIP003 didn't include support for UDP. The lack of UDP support has significantly limited the possible use cases of SIP003. There are reports that shadowsocks UDP data flows are blocked or detected by malicious third-parties. By allowing Plugins to support transporting UDP, it will be possible to implement features like UDP obfuscation, UDP-over-TCP.
2. Implementation Requirements
1. The Plugin that supports SIP011 **MUST** supports [SIP003](https://shadowsocks.org/guide/sip003.html).
Passing Arguments to a Plugin
Arguments are exactly the same as SIP003.
3. Implementation Details
3.1. Default Behavior
SIP011 is disabled by default in all shadowsocks implementations. Any plugins that support SIP011 should be able to run independently with implementations that only support SIP003.
3.2. Configuration
Shadowsocks implementation should add a new configuration key to enable SIP011. A recommended configuration key is
"plugin_mode": "tcp_and_udp"
in the Basic Configuration format:{ "plugin": "PLUGIN program", "plugin_opts": "PLUGIN options", // plugin_mode can be: // - "tcp_only" (default) - SIP003 // - "tcp_and_udp" - SIP011 // - "udp_only" - SIP011 "plugin_mode": "tcp_and_udp" }3.3. Implementation
Plugins should start a UDP listener
bind()
s to the same address and port exactly the same as SIP003. Specifically:1. For Plugin runs in local server (or client), it should create a UDP socket `bind()`s to the address specfied by `SS_LOCAL_HOST` and `SS_LOCAL_PORT` and receives local UDP packets from this address. 2. For Plugin runs in remote server (or server), it should send received UDP packets to the address specified by `SS_LOCAL_HOST` and `SS_LOCAL_PORT`.
last update was some time ago, may I ask what is the status of this proposal? I see the issue still open, but at the same time some references already to SIP003u in shadowsocks-rust Readme.
so far my understanding is this feature is supported by following plugins
-v2ray-plugin (mode=quic)
-yamux plugin
appreciate if you could provide an update and confirm my understanding
thanks
Just implement a sip003u plugin over websockets based on libevent.
@zonyitoo It seems there is no way for the plugin to know the plugin mode.
Could this spec add an environment like SS_PLUGIN_MODE
or so?
Why would the plugin need to know the plugin mode? It can always run in SIP003u even if the shadowsocks client only supports SIP003.
@zonyitoo As sip003u is not implemented by all shadowsocks implementations, and it's not default even in shadowsocks-rust, if the plugin know it's not supported, then it can fast fail instead of the udp timeout.
last update was some time ago, may I ask what is the status of this proposal? I see the issue still open, but at the same time some references already to SIP003u in shadowsocks-rust Readme.
so far my understanding is this feature is supported by following plugins -v2ray-plugin (mode=quic) -yamux plugin
appreciate if you could provide an update and confirm my understanding thanks
And, finally, there is a new plugin support sip003u:
Refined proposal:
SIP011: UDP Extension for SIP003 Plugins
3.3. Implementation
Plugins should start a UDP listener
bind()
s to the same address and port exactly the same as SIP003. Specifically:1. For Plugin runs in local server (or client), it should create a UDP socket `bind()`s to the address specfied by `SS_LOCAL_HOST` and `SS_LOCAL_PORT` and receives local UDP packets from this address. 2. For Plugin runs in remote server (or server), it should send received UDP packets to the address specified by `SS_LOCAL_HOST` and `SS_LOCAL_PORT`.
@zonyitoo Could you edit your comment, modify the sip003 url to https://shadowsocks.org/doc/sip003.html
And, should this proposal add an implementation guide, like udp should always redirect the content of recvfrom / sendmsg and sendto / sendmsg in one udp packet?
I fork kcptun-android, Replaced the go program written by myself
The above is that I only use one plug-in to complete the forwarding logic of TCP and UDP at the same time. I used this method to test the WhatsApp video call and it works very well.And I will automatically divert tcp and udp traffic in my plug-in, and automatically judge tcp or udp direct connection or proxy
I think udp forwarding is not that difficult. I donβt know why UDP is not considered in the definition of SIP003 plug-in
@jan-bar Coud you replace the image by link (and with a mention it's in chinese) or decrease the default size?
Or hidden the image by default.
For the server plugin:
1. Accept a new connection (maybe a TCP connection) 2. Create a new UDP socket that `connect()` to `ssserver`'s UDP port 3. Read UDP packets from the connection and then `sendto` the UDP socket
@zonyitoo connect
may be ommited in udp socket if use sendto
.
I'm not sure what you mean. You can refer to the source code of my project, maybe you will get some inspiration.
Don't show large chinese image in this issues.
@jan-bar hi, could I buy that plugin from you? Trying to setup UDP too.
@janisblaus You can try the wss-proxy.
I came here by searching why whatsapp call is not working as calls happen over UDP and the outgoing udp is blocked, then it won't work. any update on udp over tcp support? this comment sums it up.
I didn't check whatsapp call, however, I check the wechat video call, and it works well.