clash-rs
clash-rs copied to clipboard
Feat: transparent proxy support (linux only)
🤔 This is a ...
- [x] New feature
- [ ] Bug fix
- [ ] Performance optimization
- [ ] Enhancement feature
- [ ] Refactoring
- [ ] Code style optimization
- [ ] Test Case
- [ ] Branch merge
- [ ] Workflow
- [ ] Other (about what?)
🔗 Related issue link
https://github.com/Watfaq/clash-rs/issues/73
💡 Background and solution
on linux, the system provides a native way of handling the global proxy: IP_TRANSPARENT & tproxy. compared with tun, it has a better performance, since it will not need one more traverse of network stack. some introductions and documents can be found bellow:
there are 3 main parts of this PR:
- support get_orig_dst option for udp socket
- utilize the
iptablesto redirect the socket to tproxy listener - use
so_markand policy routing to avoid the endless loop
i have test this PR on my linux machine, but the compatibility tests with other tools that depend on iptables, like docker, wireguard haven't been done
to be discussed
- should we support nftables as well?
- should we support
IP_RECVTOSoption in socket? - can we provide a better experience, to avoid the conflict in iptables' rules?
📝 Changelog
Support Transparent proxy on linux(Ipv4 only)
☑️ Self-Check before Merge
⚠️ Please check all items below before requesting a reviewing. ⚠️
- [ ] Doc is updated/provided or not needed
- [ ] Changelog is provided or not needed
i find this post is useful https://powerdns.org/tproxydoc/tproxy.md.html
this is the iptables created by the tproxy
-> % sudo iptables -L -t mangle
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
CLASH_TPROXY_PREROUTING tcp -- anywhere anywhere
CLASH_TPROXY_PREROUTING udp -- anywhere anywhere
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
CLASH_TPROXY_OUTPUT tcp -- anywhere anywhere
CLASH_TPROXY_OUTPUT udp -- anywhere anywhere
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
Chain CLASH_TPROXY_OUTPUT (2 references)
target prot opt source destination
RETURN all -- anywhere 0.0.0.0/8
RETURN all -- anywhere 10.0.0.0/8
RETURN all -- anywhere 100.64.0.0/10
RETURN all -- anywhere 127.0.0.0/8
RETURN all -- anywhere link-local/16
RETURN all -- anywhere 172.16.0.0/12
RETURN all -- anywhere 192.0.0.0/24
RETURN all -- anywhere 192.0.2.0/24
RETURN all -- anywhere 192.88.99.0/24
RETURN all -- anywhere 192.168.0.0/16
RETURN all -- anywhere 198.18.0.0/15
RETURN all -- anywhere 198.51.100.0/24
RETURN all -- anywhere 203.0.113.0/24
RETURN all -- anywhere base-address.mcast.net/4
RETURN all -- anywhere 240.0.0.0/4
RETURN all -- anywhere 255.255.255.255
RETURN all -- anywhere anywhere mark match 0xff
RETURN all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
RETURN all -- anywhere anywhere ADDRTYPE match dst-type BROADCAST
MARK tcp -- anywhere anywhere MARK set 0x1
MARK udp -- anywhere anywhere MARK set 0x1
Chain CLASH_TPROXY_OUTPUT_DIVERT (0 references)
target prot opt source destination
MARK all -- anywhere anywhere MARK set 0x1
ACCEPT all -- anywhere anywhere
Chain CLASH_TPROXY_PREROUTING (2 references)
target prot opt source destination
RETURN all -- anywhere 0.0.0.0/8
RETURN all -- anywhere 10.0.0.0/8
RETURN all -- anywhere 100.64.0.0/10
RETURN all -- anywhere 127.0.0.0/8
RETURN all -- anywhere link-local/16
RETURN all -- anywhere 172.16.0.0/12
RETURN all -- anywhere 192.0.0.0/24
RETURN all -- anywhere 192.0.2.0/24
RETURN all -- anywhere 192.88.99.0/24
RETURN all -- anywhere 192.168.0.0/16
RETURN all -- anywhere 198.18.0.0/15
RETURN all -- anywhere 198.51.100.0/24
RETURN all -- anywhere 203.0.113.0/24
RETURN all -- anywhere base-address.mcast.net/4
RETURN all -- anywhere 240.0.0.0/4
RETURN all -- anywhere 255.255.255.255
LOG all -- anywhere anywhere ADDRTYPE match dst-type LOCAL LOG level warning prefix ""LOCAL IN""
RETURN all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
RETURN all -- anywhere anywhere mark match 0xff
TPROXY tcp -- anywhere anywhere TPROXY redirect 0.0.0.0:7893 mark 0x1/0x1
TPROXY udp -- anywhere anywhere TPROXY redirect 0.0.0.0:7893 mark 0x1/0x1
to be discussed
1. should we support nftables as well? - let's only do iptables for now, it would be rather straighforward to impl using other commands when anyone requests.
2. should we support IP_RECVTOS option in socket? - is this for us to do advanced routing in the app or there's any other benefits to let the kernel do optimization? not very sure.
3. can we provide a better experience, to avoid the conflict in iptables' rules? - i think managing users' firewall rules can be tricky, but you currently have a name space for each chain which i think should be fine. some edge cases that i can think of is you are doing append here rather than insert which might be a lower match, but still I consider this to be fine until we hit a real issue
have tried this out on my box and it's working as expected!
overall looks good to me.
would be great please see the comments and clean up the code a bit esp the
#[allow(warning)]dead_code related things.
i will try my best to resolve some trivial issues and warnings here.
@VendettaReborn What's still missing for this to merge?
I created a new on on top of this without the iptables integration since the code base has changed a lot and it takes some effort to rebase #615