zfl9 / ipt2socks

将 iptables/nftables 传入的透明代理流量转为 socks5 流量的实用工具

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

请求增加fake dns功能

opened this issue · comments

查询真实ip是透明代理要解决的一个重要问题,想必不违背kiss原则。这项工作完全可以在本地完成,只需内置一个简易的DNS服务器,对每个域名返回唯一的假IP,并维护假IP到域名的映射。而走代理查询需要另外准备通道如ss-tunnel,延迟较高。

常见FQ软件中,clash支持fake dns。v2ray支持tls域名探测,但经常有抓不到域名的情况,而且不支持其他类型的流量如udp。v2ray也有人提交了这项功能的PR,暂未被接受。

commented

有什么用处呢

有什么用处呢

你好,这个是解决DNS污染的一种方法,流程如下:

  1. 客户端向ipt2socks查询www.google.com
  2. ipt2socks返回1.2.3.4
  3. 客户端向1.2.3.4发出TCP连接
  4. ipt2socks拿到该连接,查表知1.2.3.4对应的是www.google.com
  5. ipt2socks向socks端口发起请求,目标地址为domain=www.google.com

ipt2socks要查询映射表,所以fake dns必须集成在ipt2socks中。这个功能默认是关闭的。DNS服务器的话,只要支持A记录就够了,也可以用开源项目。

commented

ipt2socks 只想做最纯粹的 tproxy/redirect -> socks5 转发。不太喜欢加其他东西哈,见谅。


关于 fake dns,按照我的理解,如果要在 ipt2socks 中实现,应该会是这样:

  1. 在 ipt2socks 中拦截 dns query 数据包(可以只考虑 udp,因为 tcp 做了 splice 优化,不适合拦截)

  2. 由于 fake dns 需要占用一个 ip 地址段,ip 数量有限,因此 ipt2socks 需要一份域名列表,如 gfwlist.txt,只对 gfw 域名做 fake dns 拦截。(如果不提供列表,那就默认全部 domain 的 dns 请求都拦截,走 fake dns 流程)

  3. 解析 步骤1 拦截到的 dns query 包,提取出查询的 domain name,检查 domain name 是否位于 gfwlist.txt;如果是,则继续;如果不是,则跳过 fake dns 子系统,处理流程同普通 udp 流量(走 socks5 的 udp 代理)。

  4. ipt2socks 需要在内存中维护 3 个主要的数据结构:

    • 已分配的 domain_name -> fake_ip 映射,对同一域名的 query,返回相同的 fake_ip。
    • 已分配的 fake_ip -> domain_name 映射,用于判断后续 tcp/udp 请求是否为之前的 fake_ip,以及对应的域名。
    • 空闲的(未分配的)ip 地址池,用于给后续的新 dns 请求 分配新的 fake ip。需要考虑 空闲ip池不够 时,如何处理?
  5. 将 步骤3 拿到的 domain_name,放到 domain_name -> fake_ip 数据结构中查询,检查是否已经存在映射关系:

    • 如果已存在,则构造一个 dns reply 并发送给查询客户端,fake_ip 就是缓存中的那个 ip
    • 如果不存在,则从 空闲ip池 中分配一个 fake_ip,并加入 domain_name -> fake_ip 映射,然后构造一个 dns reply 并发送给查询客户端
  6. 监听后续的 tcp/udp 请求,检查目的 ip 是否为 fake_ip,如果是,则根据 fake_ip -> domain_name 映射,拿出对应的 domain_name,然后构造一个 address_type = 0x03 的 socks5 请求(需要考虑一个问题,后端 socks5 服务器如果不支持 0x03 地址类型,该如何处理;或者后端 socks5 服务支持 0x03 地址类型,但域名解析是在本地解析的,没有走代理,也会有问题,因为拿到了受污染的地址)


上面是关于如何实现 fake dns 的一些东西,现在说一下为什么我不太喜欢 fake dns:

  • 我个人喜欢使用独立的 dns 组件(chinadns-ng、dns2tcp、dnsproxy等)来处理 dns 解析,实现 域名gfwlist分流、域名chnroute分流、DoH、DoT、DNS over TCP 等等。并且 dns 通常都是带本地缓存的,不存在你说的延迟较高问题,也不需要引入 ss-tunnel,因为现在 udp tproxy 已经非常成熟,完全没必要引入这样一个 udp tunnel 组件。

  • 如果使用 fake dns,相当于把 dns 解析交给后端的 socks5 代理,这引入了不确定性,比如后端 socks5 是否支持 0x03 类型(domain name 格式)的目的地址、后端 socks5 是否支持在远程(即境外主机)解析对应的域名、是否支持
    DoH、DoT、DNS over TCP、是否支持 ipset/nftset 操作(与 iptables 规则联动)等等。

  • 而且引入 fake dns 后,会使得透明代理的 dns 解析流程不明朗,因为 dns 解析流被分散到了很多地方(ipt2socks、后端的socks5服务等),使用其他解决方案(如 dnsmasq/chinadns-ng/dnsproxy)则没有这个问题,dns 解析全部在这些 dns 组件之中,后续维护和扩展也容易,也更不容易出错。


综上,我个人认为 fake dns 解决方案并不是很完美,因为我们有其他更成熟的 dns 解决方案,所以暂不考虑加入,抱歉。

您可以不接受,这没问题。我解释几个点:

  1. 这个方法是rfc3089中定义的,不是FQ工作者发明的。
  2. 只有gfwlist的域名需要fake ip。
  3. fake ip通常使用的是保留地址,网段也是可以配置的。

代理工具套上fakedns上网体验变得好很多,还顺便解决ios擅自查询type 65 (HTTPS BINDING)的问题。
现在有fakedns功能的代理工具只有v2ray(xray)跟naiveproxy,其他trojan, hysteria都没有整合fakedns的功能。
我目前是用hysteria开socks5,然后开v2ray只做ipt2socks的工作,只是因为能支援fakedns,但这样肥得不得了,很多内存少的旧机器上跑不了。
如果能新开一条ipt2socks with fakedns 就太感激了。