Repository navigation
[Feature request] SOCKS Proxy Support for sslocal #1962
Description
Summary
Currently, sslocal does not natively support forwarding traffic through another SOCKS proxy.
I am requesting a new feature and config option that allows sslocal to route its traffic through a specified SOCKS5 proxy.
Use Case
The use case involves chaining sslocal traffic through another SOCKS proxy. For example, if a local SOCKS proxy is exposed on 127.0.0.1:1234 and only this socks proxy allowed to connect to the internet, I would like to configure sslocal to route its traffic through this proxy natively (without relying on other package/binary).
This feature is especially useful in scenarios like SSH tunneling (ssh -D) to a VPS, where sslocal could utilize the local SSH SOCKS proxy for further forwarding.
Workarounds Tried
local-tunnel
openbsd# sslocal -v --protocol tunnel -b "127.0.0.1:1080" -f "127.0.0.1:1234" ...
2025-05-27T04:59:22.080355343-04:00 DEBUG main ThreadId(01) shadowsocks_rust::sys: rlimit NOFILE adjusted rlimit { rlim_cur: 1024, rlim_max: 1024 }
2025-05-27T04:59:22.080621565-04:00 INFO main ThreadId(01) shadowsocks_rust::service::local: shadowsocks local 1.23.4 build 2025-05-27T08:01:34.889851441+00:00
2025-05-27T04:59:22.081944065-04:00 INFO tokio-runtime-worker ThreadId(02) shadowsocks_service::local::tunnel::tcprelay: shadowsocks TCP tunnel listening on 127.0.0.1:1080But the service that try to get through don't succeed:
socks_handshake: TCP port read failed on recv(): Operation now in progress (errno=36)
- External binary/package
I attempted to use socksify (similar to proxychains on BSD) to achieve this, but it results in the following error:
openbsd# socksify sslocal -v ....
2025-05-27T04:44:45.61702666-04:00 DEBUG main ThreadId(01) shadowsocks_rust::sys: rlimit NOFILE adjusted rlimit { rlim_cur: 1024, rlim_max: 1024 }
2025-05-27T04:44:45.617247157-04:00 INFO main ThreadId(01) shadowsocks_rust::service::local: shadowsocks local 1.23.4 build 2025-05-27T08:01:34.889851441+00:00
thread 'main' panicked at /home/shadowsocks-rust/src/service/local.rs:1002:50:
create local: Os { code: 61, kind: ConnectionRefused, message: "Connection refused" }
stack backtrace:
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Abort trapNote: I also got sslocal to start but probably due to socksify hooking, sslocal start listening on 0.0.0.0:XXXX where “XXXX” is a random port. It doesn't seem to apply the config file.
Proposed Solution
Add native support for specifying a SOCKS proxy in sslocal's configuration or command-line arguments.
For example:
sslocal --socks-proxy 127.0.0.1:1234 ...Or allow forward to support socks5?
This would ensure sslocal encapsulates its traffic within the specified SOCKS5 proxy without requiring external tools like socksify, proxychains, etc...
Benefits
- Simplifies integration in environments where a SOCKS proxy is the only allowed outbound connection.
- Reduces dependency on third-party tools for SOCKS chaining.
- Improves usability and flexibility for users requiring advanced routing scenarios.
Environment
- Version:
shadowsocks local 1.23.4(commit c28c40c) - Platform: OpenBSD 7.7
- Additional Context: SSH-based SOCKS proxy (
ssh -D).
Thank you for considering this feature request!
Activity
zonyitoo commentedon May 27, 2025
Similar request is #1397 .
I personally totally Ok with this feature. But it may require quite a lot of work. Adding a proxy option inside
ConnectOptsand makesTcpStreamas anenumtype.database64128 commentedon May 27, 2025
All you need is a tool that listens on a port and forwards traffic via a SOCKS server to an arbitrary destination, which in this case is the Shadowsocks server. Easy. With shadowsocks-go, you can have:
{ "servers": [ { "name": "ss-via-socks5", "protocol": "direct", "tcpListeners": [ { "network": "tcp", "address": ":1234" } ], "udpListeners": [ { "network": "udp", "address": ":1234" } ], "mtu": 1500, "tunnelRemoteAddress": "ssserverhost:port" } ], "clients": [ { "name": "socks5", "protocol": "socks5", "endpoint": "socks5host:port", "enableTCP": true, "enableUDP": true, "mtu": 1500, "socks5": { "username": "username", "password": "password", "enableUserPassAuth": true } } ] }Then you ask
sslocalto connect to[::1]:1234. Of course, you can just add your Shadowsocks configuration to the above example and run the whole thing in a single instance.database64128 commentedon May 27, 2025
Sounds like a lot of engineering effort for seemingly little to no benefit other than supporting very niche use cases like this.
In fact, there are so many different ways of combining protocols, that you can keep making changes to add support, and users will keep finding new unsupported combinations.
I recently made some changes in shadowsocks-go that had incidentally made it possible to write code to "chain" clients indefinitely. However, I have decided against exposing this capability through configuration. Doing so would just add extra complexity and failure modes with little to no practical value to users.
Pyvonix commentedon Jun 1, 2025
Thank you both for your responses.
@zonyitoo, I agree to close this issue in favor of #1397 but I will answer here to keep the conversation follow.
I have no idea how much work this would require, but I'm just in favor of it. 😄
@database64128, regarding your first comment: if I understand correctly, the shadowsocks's Rust implementation separates
ssslocalandssserver, which means running two binaries to have the excepted feature. Is that accurate? I want to ensure I'm understanding this correctly what you suggest.As for your second comment: unfortunately, I can't give an opinion on "lot of engineering effort". I find it interesting that two issues already exist for this same feature. That suggests it may have more merit than "seemingly little to no benefit".
From a practical perspective, the most widely used proxy protocols—SOCKS and HTTP/HTTPS—are standard enough to be directly exportable as environment variables on modern Linux and macOS systems. It's a bit ironic for a proxy service like shadowsocks to lack support for other proxies, considering their ubiquity. 😅
While I want to avoid introducing "risky features" into shadowsocks, I do see value in enabling SOCKS proxy support for outgoing traffic. It will provide a flexible way to root the client traffic without requiring further changes in shadowsocks in near future 😃
database64128 commentedon Jun 1, 2025
I'm not sure I understand what you mean. You are already running an
ssserverinstance on your server, and you want your localsslocalinstance to forward encapsulated Shadowsocks traffic via your SOCKS server tossserver. Did I get that right? My first comment suggests that you use another tool like shadowsocks-go to do the forwarding via SOCKS part. You could also just use shadowsocks-go for the whole thing, since it speaks the encrypted proxy protocols as well.zonyitoo commentedon Jun 2, 2025
I just remember that I made a "proxy plugin":
https://github.com/zonyitoo/shadowsocks-proxy-plugin
It should fix this issue perfectly.
Pyvonix commentedon Jun 2, 2025
@zonyitoo this is exactly what I expected!
This should be mentioned somewhere in the README.md and/or included in the project as feature (in my opinion).
Thank you for sharing it
Pyvonix commentedon Aug 24, 2025
After having had time to seriously consider the suggested solution, I am forced to reopen this issue because shadowsocks-proxy-plugin opens a random port that I cannot know in advance in order to authorize it in my firewall.
With the following configuration file:
I get the following debug logs:
Where
started plugin "proxy-plugin-local" on <IP>changes each time it is run.So I ask again, is it not possible to consider chaining socks5 directly with shadowsocks? 😅
zonyitoo commentedon Aug 25, 2025
The port
44027is only for communicating withsslocalin local network. You could bypass all traffics in the local network (IP:::1and127.0.0.1).Pyvonix commentedon Aug 25, 2025
I understood what the random port (here
44027) was for, but I preferred “native chaining” withsslocalrather than binding/opening a new port that would change at each execution.I admit that I am a bit biased due to the “constraints” I set 😄
However, I support the value of such a native feature to avoid the use of an external plugin, the opening of an additional port and to facilitate the usage of
sslocalthrough an HTTP or SOCKS5 proxy.zonyitoo commentedon Aug 26, 2025
Wrapping shadowsocks' data traffic with other protocols are supported by "plugin", which allow other "plugin" implementations to provide services as a separated project instead of commiting all of them into shadowsocks' repository.
yjd commentedon Feb 2, 2026
@zonyitoo
Question: Is this plugin suitable for the ssserver side?
I need the outbound traffic from ssserver to be converted to socks5 and sent to local sing-box, then sing-box handles rule-based routing and forwards to different IPs according to the rules.
I know sing-box can be configured as a Shadowsocks server, but I prefer using the native/original program.
I don't want to use ss-local on the client side and sing-box on the server side. Thanks!
zonyitoo commentedon Feb 3, 2026
No. The SIP003 plugin framework is for the connection between
sslocalandssserver.yjd commentedon Feb 3, 2026
Got it, thanks! In the end, I settled for using sing-box directly as the server.