shadowsocks-org icon indicating copy to clipboard operation
shadowsocks-org copied to clipboard

About SIP003 - get client address from server side?

Open shinku721 opened this issue 7 years ago • 8 comments

If I'm right, by using the plugin, ss-server accepts requests from the local plugin server, so it cannot get the real client address. It seems that SIP003 does not provide any information about it. But sometimes this is necessary, e.g. access control, statistics, or even better logging. Is there any way?

shinku721 avatar Jul 25 '17 11:07 shinku721

It's indeed a limitation imposed by the current design. HTTP reverse proxies can add X-Real-IP header but we cannot really do that due to lack of header information in Shadowsocks protocol.

riobard avatar Jul 25 '17 16:07 riobard

Yes, I think it's a limitation. A quick fix is prepending an src address to each TCP stream.

We can make it optional, to be compatible with all the previous plugins.

madeye avatar Jul 25 '17 23:07 madeye

@madeye It would require some changes in both the plugin and protocol details. We should probably think more carefully to be future-proof.

riobard avatar Jul 26 '17 06:07 riobard

Yeah, it should be considered carefully. But I think we can adopt @madeye 's method at first and make it an experimental feature. Finally we stabilize a future-proof version. I think we can add an option for it to SS_PLUGIN_OPTIONS, and force plugins to check options. A plugin MUST exit immediately with error if there are incompatible or unrecognized options, in order to ensure that plugins are working correctly.

shinku721 avatar Jul 28 '17 16:07 shinku721

Another solution is to rework the plugin system so that ss launches a subprocess for the plugin, passing the received stream into the plugin's stdin and gets the output from its stdout (options can be passed as environment variables). This way, the plugin does not need to be a daemon by itself, and is truly "plugged-in" to ss.

It's basically a forking model. Not sure about the cost of creating a subprocess per connection, tho.

riobard avatar Aug 31 '17 11:08 riobard

On unix platforms, a process can pass/transfer its current file-descriptors to others with sendmsg/SCM_RIGHTS on AF_UNIX (pls see https://docs.python.org/3/library/socket.html for details). This is how inetd/xinetd/systemd listens for incoming connection and start the relevent service on-demand.

After simple_obfs finished its socket initialization and head-obfuscation, it can use this mechanism to send the established socket to ss-server, and relinquish itself from further store-forward duty. This would lower the workload for the obfuscator, and shadowsocks server can communicate with the remote party directly. The address of the remote party is therefore readable.

Caveat: won't work for kcptun, because kcptun should always stay in the communication path.

ccaapton avatar Sep 04 '17 04:09 ccaapton

For kcptun, there is also a way to pass the remote peer info with sendmsg: Instead of connecting to ss-server directly, kcptun create pipe-pair or socket pair, pass the receiving end to ss-server with sendmsg/SCM_RIGHTS. The remote peer information could be include the the sendmsg main body.

This is the sendmsg in python: socket.sendmsg(buffers[, ancdata[, flags[, address]]]), the socket/pipe is in ancdata, so buffers could contain additional information like remote peer info.

ccaapton avatar Sep 04 '17 04:09 ccaapton

One idea is to use the PROXY protocol, which is used by many systems: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

It essentially prepends the traffic with a header. The plugin would have to be aware of that, and the plugin config should specify that it expects the PROXY header, so the server can send it only to plugins that expect it.

fortuna avatar Aug 22 '19 14:08 fortuna