shadowsocks-org
shadowsocks-org copied to clipboard
About SIP003 - get client address from server side?
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?
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.
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 It would require some changes in both the plugin and protocol details. We should probably think more carefully to be future-proof.
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.
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.
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.
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.
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.