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

Q: Possible to use an arbitrary tunnelling program as plugin by passing CLI args? #3064

Open
spyophobia opened this issue Jan 7, 2021 · 17 comments
Labels
enhancement plugins Issues related to SIP003 and non-SIP003 plugins.
Milestone

Comments

@spyophobia
Copy link

spyophobia commented Jan 7, 2021

I am attempting to use an arbitrary tunnelling program as the plugin of ss-windows. This program does not implement SIP003, so until now I have been running it as a standalone program. However, after reading the SIP003 standard and seeing its simplicity, I was wondering whether it is possible to manually configure the tunnelling program using ss-windows's "CLI parameters", thereby bypassing the need to write a custom adapter for it.

For simplicity's sake, let's take this simple tunnelling program as an example: gnolizuh/quictun. My actual program works similarly to this example.

This program (on the client side) takes two parameters: -l <local_addr>:<local_port> and -r <remote_addr>:<remote_port>. If I understand correctly, these parameters are one-to-one mapping of the required ENV parameters described in SIP003: SS_REMOTE_HOST, SS_REMOTE_PORT, SS_LOCAL_HOST and SS_LOCAL_PORT. Therefore something like the following should work:

Screencap
... and I can just ignore those four ENVs.

However when I attempt to start Shadowsocks with this configuration, I was prompted that the port is occupied. Therefore I suspected that maybe ss-windows is handling the local port configuration a little differently than I thought. Can you please confirm whether this is or isn't the case? In addition, would it be possible to configure a tunnelling program (that was not specifically designed to comply with SIP003) to run as a plugin this way? If so, how?

@spyophobia
Copy link
Author

spyophobia commented Jan 7, 2021

Also I would like to clarify that by running quictun_client as a standalone program with args -l ":1081" -r "example.org:port", and setting ss-windows's server address and port as localhost and 1081, the setup does work, as if the tunnelling program is running as a plugin. Serverside setup is essentially analogous. Then I can use something like pm2 to run the tunnelling program in the background.

However as you can imagine this is quite a complicated setup, not to mention that I need to keep many instances of the tunnelling program running (each connecting to a different server) if I want to hot-swap servers in Shadowsocks. I would love to take full advantage of Shadowsocks's built-in plugin system if possible.

@DuckSoft
Copy link

DuckSoft commented Jan 8, 2021

Read the SIP003 specifications my friend. You may want to make a change to upstream or write a wrapper to adapt to SIP003 specification. If not, you can roll your own wheels.

@spyophobia
Copy link
Author

spyophobia commented Jan 9, 2021

You may want to make a change to upstream or write a wrapper to adapt to SIP003 specification.

I'm specifically asking for a way to circumvent that, if possible.

And if not possible, what technical reason is preventing me from doing that?

@DuckSoft
Copy link

DuckSoft commented Jan 9, 2021

You may want to make a change to upstream or write a wrapper to adapt to SIP003 specification.

I'm specifically asking for a way to circumvent that, if possible.

And if not possible, what technical reason is preventing me from doing that?

The root cause is that plugins work as slave process of Shadowsocks-Windows. Shadowsocks windows will have its own listening port and, when the connection is established, the wrapped Shadowsocks payload will be sent to the slave port, where the slave listening port is passed by SS_LOCAL_PORT but not hardcoded.

var localPort = GetNextFreeTcpPort();
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort);
_pluginProcess.StartInfo.Environment["SS_LOCAL_HOST"] = LocalEndPoint.Address.ToString();
_pluginProcess.StartInfo.Environment["SS_LOCAL_PORT"] = LocalEndPoint.Port.ToString();
_pluginProcess.StartInfo.Arguments = ExpandEnvironmentVariables(_pluginProcess.StartInfo.Arguments, _pluginProcess.StartInfo.EnvironmentVariables);

The port is generated, not hardcoded, so your method won't work at all. The only non-intrusive to Shadowsocks-windows way is to wrap your tunnel program.

Finally, the exact technical reason is that you have to make your own wheels if you don't follow the standards and specifications.

@DuckSoft
Copy link

DuckSoft commented Jan 9, 2021

I've drawn a chart to illustrate this. The core problem is that Shadowsocks-Windows will decide the listen port and pass the port as SS_LOCAL_PORT to plugins, while your vanilla tunnel program won't recognise that.

图片

Just wrap your programs. It's not that hard.

@DuckSoft
Copy link

DuckSoft commented Jan 9, 2021

But actually, maybe Shadowsocks-Windows can consider introducing some variable substitution mechanism to enable use cases like that. For example, if we would replace ${SS_LOCAL_PORT} into actual value in plugin command-line argument, this can be solved elegantly, without a huge break.

Update: I saw the invocation of ExpandEnvironmentVariables. You can try replace your hardcoded port 1080 with %SS_LOCAL_PORT% and see if this worked.

Example Commandline:

-l %SS_LOCAL_HOST%:%SS_LOCAL_PORT% -r %SS_REMOTE_HOST%:%SS_REMOTE_PORT%

@spyophobia
Copy link
Author

Shadowsocks windows will have its own listening port and, when the connection is established, the wrapped Shadowsocks payload will be sent to the slave port, where the slave listening port is passed by SS_LOCAL_PORT but not hardcoded.

Yep that was what I suspected too. You worded it much clearer than I did though.

Update: I saw the invocation of ExpandEnvironmentVariables. You can try replace your hardcoded port 1080 with %SS_LOCAL_PORT% and see if this worked.

Oh that's just wonderful. Funnily enough, I was going to suggest some similar var substitution system too, had this not been the case.

... And I tested it with both the example program quictun and my actual tunnelling program in production. Seems to be working okay now so that's awesome.

@spyophobia
Copy link
Author

One extra thing

Should we perhaps consider documenting this env substitution behaviour in README? I feel like this could be useful to some other users.

@DuckSoft
Copy link

DuckSoft commented Jan 9, 2021

Should we perhaps consider documenting this env substitution behaviour in README? I feel like this could be useful to some other users.

I see your point. But before that, we must have documentation first. Currently I don't see one.
If I were the developer, I would put a tooltip over that editor box instead of writing into documentation.

@zonyitoo
Copy link

Maybe we could extend SIP003 for supporting customization of plugins' listen port.

@database64128
Copy link
Contributor

Since almost all SIP003 plugins that are being actively maintained have UDP support, we should add UDP to SIP003 as well.

@spyophobia
Copy link
Author

Apologies. I just realised that I have overlooked a pretty prominent page in SS-Windows Wiki written in 2019 or earlier. It literally answers my question with comprehensive explanations and examples.

Working with non SIP003 standard Plugin

I will now close this issue out of unnecessity and a sliver of shame.

@database64128
Copy link
Contributor

No need to apologize. Repository wiki is not a good place for docs anyway. I'd like to keep the issue open, so I won't forget when I start to refactor the related code.

@database64128 database64128 reopened this Jan 17, 2021
@database64128 database64128 added enhancement plugins Issues related to SIP003 and non-SIP003 plugins. labels Jan 17, 2021
@database64128 database64128 added this to the v5 milestone Jan 17, 2021
@spyophobia
Copy link
Author

@zonyitoo Out of curiosity, seen that you are the primary contributor to shadowsocks-rust, does a similar workaround exist in shadowsocks-rust as well? Or do I have to write a bash script as a wrapper for the plugin binary?

@zonyitoo
Copy link

Nope. shadowsocks-rust only supports standard SIP003 plugins. And yes, you will have to make a wrapper program.

@Thuem26
Copy link

Thuem26 commented Mar 25, 2024

😊

1 similar comment
@Thuem26
Copy link

Thuem26 commented Mar 25, 2024

😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement plugins Issues related to SIP003 and non-SIP003 plugins.
Projects
None yet
Development

No branches or pull requests

5 participants