先看一下iptables,正经图
路由设置
ip rule add fwmark 1 table 100 #带有mark1的包都发到table 100
ip route add local 0.0.0.0/0 dev lo table 100 #所有包都走lo(本地回环)
不同场景
内网机器访问国内服务
A的请求到达路由器的PREROUTING链,根据链上规则
-m set --match-set reserved_ip dst -j RETURN
直接返回原来的PREROUTING连,走FORWARD以及后续的操作
内网机器访问国外服务
A的请求到达路由器的PREROUTING链,根据链上规则
-p tcp -j TPROXY --on-port 1081 --tproxy-mark 0x1/0x1
给TCP请求加上mark,然后重定向到1081,根据前面的路由设置,会直接到本地回环,请求会到达Transparent Proxy
-
判断需要走Proxy,那接下来的流程就是,包装原请求并发出,带上了0xff(即255)的mark
按照OUTPUT链上的规则
-m mark --mark 0xff -j RETURN
``
直接返回OUTPUT链,走POSTROUTING链出去
-
判断为直连,直接原封不动的请求真实服务器,也是带上0xff的mark,后面和情况1一样
路由器访问国内服务
路由器的请求会从OUTPUT开始,会匹配上OUTPUT链上规则
--match-set chnroute dst -j RETURN
直接返回OUTPUT链,走POSTROUTING链出去
路由器访问国外服务
路由器的请求会匹配上OUTPUT链上最后一条规则
-p tcp -j MARK --set-mark 0x1
给这个请求打上mark,然后打上mark的请求会重新走PREROUTING链,会匹配上如下规则
-p tcp -j TPROXY --on-port 1081 --tproxy-mark 0x1/0x1
也就是说,流量会绕一圈,重新进入Transparent Proxy
一个坑来了
当通过tproxy进入Transparent Proxy的时候,这个包的的remoteAddr是请求发起方的地址(即路由器IP),localAddr则是真实需要到达的服务器地址(比如Google.com),响应该请求的时候,DST会变成请求发起方的地址(正是路由器的地址)
如果我们不在OUTPUT对这个包做操作的话,这个包会再次被设置mark,都无法完成握手
最终成品:Github