Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIP003u - UDP Extension for SIP003 Plugins #180

Open
database64128 opened this issue Feb 8, 2021 · 28 comments
Open

SIP003u - UDP Extension for SIP003 Plugins #180

database64128 opened this issue Feb 8, 2021 · 28 comments

Comments

@database64128
Copy link
Contributor

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.

@database64128
Copy link
Contributor Author

database64128 commented Feb 8, 2021

Related issues/discussions

Mentions

Shadowsocks

Qv2ray

V2Fly

XTLS

@database64128
Copy link
Contributor Author

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 and SS_LOCAL_PORT as the listening address and port for UDP. Client-side plugins must have UDP support.
  • No modifications are needed at Shadowsocks servers.

@zonyitoo
Copy link
Contributor

zonyitoo commented Feb 8, 2021

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".

zonyitoo added a commit to shadowsocks/shadowsocks-rust that referenced this issue Apr 15, 2023
- ref shadowsocks/shadowsocks-org#180
- "plugin_mode" option in configuration file, and ssmanager API
- "plugin_mode" is "tcp_only" by default
zonyitoo added a commit to shadowsocks/shadowsocks-rust that referenced this issue Apr 15, 2023
- ref shadowsocks/shadowsocks-org#180
- "plugin_mode" option in configuration file, and ssmanager API
- "plugin_mode" is "tcp_only" by default
- ref #1127
zonyitoo added a commit to shadowsocks/shadowsocks-rust that referenced this issue Apr 15, 2023
- ref shadowsocks/shadowsocks-org#180
- "plugin_mode" option in configuration file, and ssmanager API
- "plugin_mode" is "tcp_only" by default
- ref #1127
@database64128
Copy link
Contributor Author

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:

  1. We must be very careful when choosing the special key. Collision with existing plugins could cause issues. SIP003u=true might be a good candidate.
  2. 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.
  3. SS_PLUGIN_OPTIONS is not mandatory and some plugins might not check it at all.
  4. We could also just drop plugin_mode and have the shadowsocks client and server check whether SS_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 in host: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())

@zonyitoo
Copy link
Contributor

zonyitoo commented Apr 15, 2023

If a plugin supports SIP003u, it will only need to provide a UDP tunnel, the process steps would be:

For the local plugin:

  1. recv() a UDP packet from sslocal, with peer_addr (A)
  2. Check if there is an existed UDP tunnel for (A), if no, create one.
  3. Send all packets received with peer_addr = (A) into this tunnel.

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

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.

@zonyitoo
Copy link
Contributor

https://github.com/zonyitoo/shadowsocks-yamux-plugin
This is a plugin that supports SIP003u. It use YAMUX protocol as TCP stream multiplexer.

@zonyitoo
Copy link
Contributor

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.

@database64128
Copy link
Contributor Author

Fair enough. I guess you could open a PR to update the spec doc and then close this issue?

@zonyitoo
Copy link
Contributor

It is still an experimental feature. Let's keep it open and see if there are any other comments.

@zonyitoo
Copy link
Contributor

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.

@vahobrsti
Copy link

vahobrsti commented Apr 29, 2023

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)

@Nullizer
Copy link

Does v2ray-plugin support UDP Extension ? I want something like v2ray-plugin work behind in nginx proxy but with UoT support.

@vahobrsti
Copy link

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.

@zonyitoo
Copy link
Contributor

zonyitoo commented May 7, 2023

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.

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.

@zonyitoo
Copy link
Contributor

zonyitoo commented May 7, 2023

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.

@janisblaus
Copy link

@jan-bar hi, could I buy that plugin from you? Trying to setup UDP too.

@janisblaus
Copy link

@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. :)

@boss1819
Copy link

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

@liudongmiao
Copy link

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?

@zonyitoo
Copy link
Contributor

zonyitoo commented Apr 6, 2024

Why would the plugin need to know the plugin mode? It can always run in SIP003u even if the shadowsocks client only supports SIP003.

@liudongmiao
Copy link

@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.

@liudongmiao
Copy link

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:

@boss1819

@liudongmiao
Copy link

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?

@liudongmiao
Copy link

liudongmiao commented Apr 8, 2024

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.

@liudongmiao
Copy link

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.

@liudongmiao
Copy link

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.

@liudongmiao
Copy link

@jan-bar hi, could I buy that plugin from you? Trying to setup UDP too.

@janisblaus You can try the wss-proxy.

@liudongmiao
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants