Before Clash start we have following ip rules and routes
$ ip rule list |
After Clash start we have following ip rules and routes
$ ip rule list |
Now let us exaplsin what exactly every new lines do
9500: not from all dport 53 lookup main suppress_prefixlength 0 |
This rules means sending all non-DNS query packets are sent to lookup the main
table, but the default rule in the main
table is ignored due to suppress_prefixlength 0
. suppress_prefixlength 0
means ignore rules matches more than prefixlength bits. Here we have 0 so it just ignore 0.0.0.0/0. The point of this rule is 1. allowing we can communicate to other machines under same LAN without clash; 2. send the packets with fake-ip addresses to TUN interface. However, we still need to hijack for example the gateway’s DNS (192.168.122.1:53 in this case), so it is only for non-DNS query packets.
9510: not from all iif lo lookup 1970566510 |
iif lo
means input interface lo
, this is a way of specifying rules for locally generated packets that have a specific source address. This rules filter out packets from other machines under same LAN which is being forwarded in the chains, here the machine running Clash acts as proxy-gateway, are send to the TUN interface With this rule, packtes don’t have fake-ip range destinations are also transmitted to Clash in case DNS hijack not working.
9520: from 0.0.0.0 iif lo uidrange 0-4294967294 lookup 1970566510 |
from 0.0.0.0 iif lo
means packets without source addresses and generated locally. In Linux, client-initiaed packets source address can not be decided before it reaches to the interface. This rule ensures the machine running Clash itself can be proxied.
9530: from 198.18.0.1 iif lo uidrange 0-4294967294 lookup 1970566510 |
This is my guess after reading sing-tun code: When use system stack, packets coming will be DNAT-ed inside TUN (} else if source.Addr() == s.inet4ServerAddress && source.Port() == s.tcpPort {
then packet goes out from TUN but goes back to TUN ip address using Linux networking stack on the listener at TUN device (e.g. tcpListener
). When clash received data from proxies, tun needs to reply transparent-proxied device/process, tcpListener server will send data to them from 198.18.0.1, now this packets needs go back to TUN device for another SNAT - this is the reason for this rule.
198.18.0.0/16 dev utun proto kernel scope link src 198.18.0.1 |
Send fake-ip range packets to TUN interface
default dev utun proto unspec |
A standalone ip table which sends all packet to TUN interface once looked up by. We already see it for several times.
One more thing
After we understand everything, we can try to disable the transparent proxy of the machine running Clash. Can you think up how to do that?
Answer:sudo ip rule del from 0.0.0.0 iif lo uidrange 0-4294967294 lookup 1970566510
Refs
[1] https://utcc.utoronto.ca/~cks/space/blog/linux/IsolatedInterfacesPrinciples
[2] https://utcc.utoronto.ca/~cks/space/blog/linux/IsolatingTestingInterface