iptables + tproxy 实现透明代理

type
status
date
slug
summary
tags
category
icon
password
先看一下iptables,正经图
notion image
路由设置

不同场景

内网机器访问国内服务

A的请求到达路由器的PREROUTING链,根据链上规则
直接返回原来的PREROUTING连,走FORWARD以及后续的操作

内网机器访问国外服务

A的请求到达路由器的PREROUTING链,根据链上规则
给TCP请求加上mark,然后重定向到1081,根据前面的路由设置,会直接到本地回环,请求会到达Transparent Proxy
  1. 判断需要走Proxy,那接下来的流程就是,包装原请求并发出,带上了0xff(即255)的mark
    1. 按照OUTPUT链上的规则
      直接返回OUTPUT链,走POSTROUTING链出去
  1. 判断为直连,直接原封不动的请求真实服务器,也是带上0xff的mark,后面和情况1一样

路由器访问国内服务

路由器的请求会从OUTPUT开始,会匹配上OUTPUT链上规则
直接返回OUTPUT链,走POSTROUTING链出去

路由器访问国外服务

路由器的请求会匹配上OUTPUT链上最后一条规则
给这个请求打上mark,然后打上mark的请求会重新走PREROUTING链,会匹配上如下规则
也就是说,流量会绕一圈,重新进入Transparent Proxy

一个坑来了

当通过tproxy进入Transparent Proxy的时候,这个包的的remoteAddr是请求发起方的地址(即路由器IP),localAddr则是真实需要到达的服务器地址(比如Google.com),响应该请求的时候,DST会变成请求发起方的地址(正是路由器的地址)
notion image
如果我们不在OUTPUT对这个包做操作的话,这个包会再次被设置mark,都无法完成握手
notion image
最终成品:Github
 

其他小插曲

TProxy在代理UDP流量的时候,比如,代理从192.168.2.100:1234到8.8.8.8:53的流量,会在本地监听(bind)8.8.8.8:53的流量,正常情况下是不允许这样bind的,但是如果设置了syscall.IP_TRANSPARENT 就能正常bind,但有个特例,如果本地已经有服务绑定了0.0.0.0:53的监听,那就会报错EADDRINUSE (address already in use)
Loading...

© XGFan 2012-2025