SagerNet / sing-box

The universal proxy platform
https://sing-box.sagernet.org/
Other
19.87k stars 2.36k forks source link

由于UDP DNS响应长度超过512B进行截取导致某些域名无法获取IP信息 #1448

Closed yvvw closed 4 months ago

yvvw commented 9 months ago

Operating system

Linux

System version

openwrt 23.05

Installation type

Original sing-box Command Line

If you are using a graphical client, please provide the version of the client.

No response

Version

sing-box version 1.8.5

Environment: go1.21.6 linux/arm64
Tags: with_gvisor,with_quic,with_dhcp,with_wireguard,with_ech,with_utls,with_reality_server,with_acme,with_clash_api
Revision: b27bc45cf2550e00823e799a313f8226443aa58e
CGO: disabled

Description

17aebc5cn-beijing-data.aliyundrive.net 这类响应超出 512B 的域名进行修复后,又出现 api.aliyundrive.com 连续AAAA记录,最后一个A类记录IP信息,由于sing-box DNS响应没有进行压缩,导致这类地址被截断后拿不到ip信息。我猜测压缩会影响处理性能,但又觉得能正确处理更重要些,是否可以在超出限制的情况下尝试压缩再去截取那。

$ nslookup api.aliyundrive.com
Server:         127.0.0.1
Address:        127.0.0.1:53

Non-authoritative answer:

Non-authoritative answer:
api.aliyundrive.com     canonical name = beijing.tfe.alibaba-clould.alibabacorp.com
beijing.tfe.alibaba-clould.alibabacorp.com      canonical name = beijing.tfe.alibaba-clould.alibabacorp.com.gds.alibabadns.com
beijing.tfe.alibaba-clould.alibabacorp.com.gds.alibabadns.com   canonical name = bj-static.tfe.alibaba-clould.alibabacorp.com
bj-static.tfe.alibaba-clould.alibabacorp.com    canonical name = bj-static.tfe.alibaba-clould.alibabacorp.com.gds.alibabadns.com

$ curl api.aliyundrive.com
curl: (6) Could not resolve host: api.aliyundrive.com
diff --git a/outbound/dns.go b/outbound/dns.go
index 0f003377..529c796c 100644
--- a/outbound/dns.go
+++ b/outbound/dns.go
@@ -241,7 +241,7 @@ func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWa
                                        return err
                                }
                                timeout.Update()
-                               response = truncateDNSMessage(response, 512) // TODO: add an option to custom UDP buffer size
+                               response = compressAndTruncateDNSMessage(response, 512) // TODO: add an option to custom UDP buffer size
                                responseBuffer := buf.NewSize(dns.FixedPacketSize)
                                responseBuffer.Resize(1024, 0)
                                n, err := response.PackBuffer(responseBuffer.FreeBytes())
@@ -265,12 +265,17 @@ func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWa
        return group.Run(fastClose)
 }

-func truncateDNSMessage(response *mDNS.Msg, maxLen int) *mDNS.Msg {
+func compressAndTruncateDNSMessage(response *mDNS.Msg, maxLen int) *mDNS.Msg {
        responseLen := response.Len()
        if responseLen <= maxLen {
                return response
        }
        response = response.Copy()
+       response.Compress = true
+       responseLen = response.Len()
+       if responseLen <= maxLen {
+               return response
+       }
        for len(response.Answer) > 0 && responseLen > maxLen {
                response.Answer = response.Answer[:len(response.Answer)-1]
                response.Truncated = true

Reproduction

如上

Logs

No response

Integrity requirements

mm11253 commented 8 months ago

最近遇到了一点问题 https://github.com/xiaorouji/openwrt-passwall/issues/2960 我比较好奇的是,为什么 Sing-Box DNS 的响应会比 dns2tcp/Xray DNS 大很多?

Sing-Box DNS

root@OpenWrt:~# dig www.youtube.com -p 15353
;; Truncated, retrying in TCP mode.

; <<>> DiG 9.18.24 <<>> www.youtube.com -p 15353
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48655
;; flags: qr rd ra; QUERY: 1, ANSWER: 17, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; MBZ: 0x0072, udp: 1232
;; QUESTION SECTION:
;www.youtube.com.       IN  A

;; ANSWER SECTION:
www.youtube.com.    114 IN  CNAME   youtube-ui.l.google.com.
youtube-ui.l.google.com. 114    IN  A   172.217.25.14
youtube-ui.l.google.com. 114    IN  A   142.250.66.46
youtube-ui.l.google.com. 114    IN  A   142.250.66.110
youtube-ui.l.google.com. 114    IN  A   142.250.204.110
youtube-ui.l.google.com. 114    IN  A   142.250.66.78
youtube-ui.l.google.com. 114    IN  A   142.250.207.78
youtube-ui.l.google.com. 114    IN  A   172.217.24.238
youtube-ui.l.google.com. 114    IN  A   142.250.204.46
youtube-ui.l.google.com. 114    IN  A   172.217.27.46
youtube-ui.l.google.com. 114    IN  A   172.217.24.110
youtube-ui.l.google.com. 114    IN  A   142.250.204.78
youtube-ui.l.google.com. 114    IN  A   142.250.199.78
youtube-ui.l.google.com. 114    IN  A   142.251.222.206
youtube-ui.l.google.com. 114    IN  A   142.250.66.142
youtube-ui.l.google.com. 114    IN  A   172.217.31.14
youtube-ui.l.google.com. 114    IN  A   172.217.27.14

;; Query time: 29 msec
;; SERVER: 127.0.0.1#15353(127.0.0.1) (TCP)
;; WHEN: Sat Feb 24 02:05:13 CST 2024
;; MSG SIZE  rcvd: 720

dns2tcp

root@OpenWrt:~# dig www.youtube.com -p 15353

; <<>> DiG 9.18.24 <<>> www.youtube.com -p 15353
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7423
;; flags: qr rd ra; QUERY: 1, ANSWER: 17, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.youtube.com.       IN  A

;; ANSWER SECTION:
www.youtube.com.    86  IN  CNAME   youtube-ui.l.google.com.
youtube-ui.l.google.com. 86 IN  A   142.250.204.142
youtube-ui.l.google.com. 86 IN  A   142.250.204.46
youtube-ui.l.google.com. 86 IN  A   172.217.24.78
youtube-ui.l.google.com. 86 IN  A   142.250.204.78
youtube-ui.l.google.com. 86 IN  A   216.58.200.238
youtube-ui.l.google.com. 86 IN  A   172.217.27.46
youtube-ui.l.google.com. 86 IN  A   142.250.204.110
youtube-ui.l.google.com. 86 IN  A   142.251.220.46
youtube-ui.l.google.com. 86 IN  A   172.217.31.14
youtube-ui.l.google.com. 86 IN  A   172.217.25.14
youtube-ui.l.google.com. 86 IN  A   172.217.24.238
youtube-ui.l.google.com. 86 IN  A   172.217.27.14
youtube-ui.l.google.com. 86 IN  A   172.217.24.110
youtube-ui.l.google.com. 86 IN  A   216.58.203.78
youtube-ui.l.google.com. 86 IN  A   142.251.220.14
youtube-ui.l.google.com. 86 IN  A   142.250.199.78

;; Query time: 59 msec
;; SERVER: 127.0.0.1#15353(127.0.0.1) (UDP)
;; WHEN: Sat Feb 24 02:17:57 CST 2024
;; MSG SIZE  rcvd: 334

Xray DNS

root@OpenWrt:~# dig www.youtube.com -p 15353

; <<>> DiG 9.18.24 <<>> www.youtube.com -p 15353
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13693
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 16, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.youtube.com.       IN  A

;; ANSWER SECTION:
www.youtube.com.    600 IN  A   142.250.199.78
www.youtube.com.    600 IN  A   172.217.24.238
www.youtube.com.    600 IN  A   172.217.24.78
www.youtube.com.    600 IN  A   142.250.204.110
www.youtube.com.    600 IN  A   142.250.204.46
www.youtube.com.    600 IN  A   142.250.207.78
www.youtube.com.    600 IN  A   142.250.204.78
www.youtube.com.    600 IN  A   172.217.27.46
www.youtube.com.    600 IN  A   172.217.31.14
www.youtube.com.    600 IN  A   142.250.204.142
www.youtube.com.    600 IN  A   172.217.24.110
www.youtube.com.    600 IN  A   216.58.200.238
www.youtube.com.    600 IN  A   172.217.25.14
www.youtube.com.    600 IN  A   216.58.203.78
www.youtube.com.    600 IN  A   172.217.27.14
www.youtube.com.    600 IN  A   142.250.66.142

;; Query time: 0 msec
;; SERVER: 127.0.0.1#15353(127.0.0.1) (UDP)
;; WHEN: Sat Feb 24 14:46:15 CST 2024
;; MSG SIZE  rcvd: 289
yvvw commented 8 months ago

@mm11253 sing-box没有对dns响应体进行压缩,可能出于性能考虑,目前还没选项进行设置,还在等开发者回复 https://github.com/SagerNet/sing-box/pull/1442

mm11253 commented 8 months ago

@mm11253 sing-box没有对dns响应体进行压缩,可能出于性能考虑,目前还没选项进行设置,还在等开发者回复 #1442

引用隔壁 ChinaDNS-NG 作者的回复 https://github.com/zfl9/chinadns-ng/issues/144#issuecomment-1962291623

拒绝连接是因为 chinadns-ng 目前还没实施 tcp 监听。用 zig 重写的 1.0/2.0 版本已经加入 tcp 支持了。

结合你引用的几个 issue 推测,有这几方面的原因:

  1. 上游未遵循 EDNS 的 udp bufsz 扩展信息,你给出的示例显示 dig 的 bufsz 是 1232 字节,即使超过 512 字节的响应,也不应该设置 TC 标志,因为实际缓冲区大小是 1232 字节,并不会“截断”
  2. 上游未实施 DNS 域名压缩导致响应消息比较大,容易超出传统的 512 字节限制,而又由于第 1 条原因,导致很多“不必要的截断,然后通过 TCP 重试”的行为
  3. chinadns-ng 目前尚未支持 TCP 监听/上游,导致 dig(查询客户端)在收到带 TC 标志的udp响应后,通过 tcp 重试查询时,未能连接上 chinadns-ng,于是出现连接被拒,查询超时。
mm11253 commented 8 months ago

所以压缩还是有必要的吧

mm11253 commented 8 months ago

Still in Todo.

https://github.com/SagerNet/sing-box/blob/ab272cd9533ecb699743502ebb1a169fc6d1655d/outbound/dns.go#L244

https://www.rfc-editor.org/rfc/rfc2671 https://www.rfc-editor.org/rfc/rfc1035

I gotcha, but I reckon compressing the response takes precedence over customizing the UDP buffer size.

nekohasekai commented 8 months ago

应已在最新版本修复。

lux5am commented 8 months ago

Most DNS related issues had been fixed. but DNS response still not compressed by default? Even when the request buffer size larger than 512 bytes it should try to get the response under 512 bytes. The 512 bytes guarantees the DNS packets can be reassembled if fragmented in the transit.

The first one from dnsmasq which is also hijacked by singbox.

root@sam46:~# kdig www.youtube.com
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 43430
;; Flags: qr rd ra; QUERY: 1; ANSWER: 17; AUTHORITY: 0; ADDITIONAL: 0

;; QUESTION SECTION:
;; www.youtube.com.             IN      A

;; ANSWER SECTION:
www.youtube.com.        1794    IN      CNAME   youtube-ui.l.google.com.
youtube-ui.l.google.com.        1794    IN      A       64.233.170.93
youtube-ui.l.google.com.        1794    IN      A       64.233.170.190
youtube-ui.l.google.com.        1794    IN      A       142.251.175.190
youtube-ui.l.google.com.        1794    IN      A       142.251.175.91
youtube-ui.l.google.com.        1794    IN      A       142.251.175.136
youtube-ui.l.google.com.        1794    IN      A       142.251.175.93
youtube-ui.l.google.com.        1794    IN      A       74.125.24.190
youtube-ui.l.google.com.        1794    IN      A       74.125.24.93
youtube-ui.l.google.com.        1794    IN      A       74.125.24.136
youtube-ui.l.google.com.        1794    IN      A       74.125.130.136
youtube-ui.l.google.com.        1794    IN      A       74.125.68.136
youtube-ui.l.google.com.        1794    IN      A       74.125.68.190
youtube-ui.l.google.com.        1794    IN      A       74.125.68.93
youtube-ui.l.google.com.        1794    IN      A       74.125.68.91
youtube-ui.l.google.com.        1794    IN      A       64.233.170.91
youtube-ui.l.google.com.        1794    IN      A       64.233.170.136

;; Received 326 B
;; Time 2024-02-29 17:41:50 WITA
;; From 127.0.0.1@53(UDP) in 0.6 ms
root@sam46:~# kdig www.youtube.com @1.1.1.1
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 23934
;; Flags: qr rd ra; QUERY: 1; ANSWER: 17; AUTHORITY: 0; ADDITIONAL: 0

;; QUESTION SECTION:
;; www.youtube.com.             IN      A

;; ANSWER SECTION:
www.youtube.com.        300     IN      CNAME   youtube-ui.l.google.com.
youtube-ui.l.google.com.        300     IN      A       64.233.170.91
youtube-ui.l.google.com.        300     IN      A       64.233.170.136
youtube-ui.l.google.com.        300     IN      A       64.233.170.93
youtube-ui.l.google.com.        300     IN      A       64.233.170.190
youtube-ui.l.google.com.        300     IN      A       142.251.175.190
youtube-ui.l.google.com.        300     IN      A       142.251.175.91
youtube-ui.l.google.com.        300     IN      A       142.251.175.136
youtube-ui.l.google.com.        300     IN      A       142.251.175.93
youtube-ui.l.google.com.        300     IN      A       74.125.24.190
youtube-ui.l.google.com.        300     IN      A       74.125.24.93
youtube-ui.l.google.com.        300     IN      A       74.125.24.136
youtube-ui.l.google.com.        300     IN      A       74.125.130.136
youtube-ui.l.google.com.        300     IN      A       74.125.68.136
youtube-ui.l.google.com.        300     IN      A       74.125.68.190
youtube-ui.l.google.com.        300     IN      A       74.125.68.93
youtube-ui.l.google.com.        300     IN      A       74.125.68.91

;; Received 709 B
;; Time 2024-02-29 17:41:57 WITA
;; From 1.1.1.1@53(UDP) in 150.9 ms
nekohasekai commented 8 months ago

https://github.com/miekg/dns/blob/2230854ba97edcf29ac55a1f274e49cec11bf9bb/msg_truncate.go#L46

lux5am commented 8 months ago

Looking at popular DNS solution like blocky and adguardhome it force enable compression. Maybe we should follow that?

diff --git a/client_truncate.go b/client_truncate.go
index a0b4afd..90cf3dd 100644
--- a/client_truncate.go
+++ b/client_truncate.go
@@ -14,6 +14,7 @@ func TruncateDNSMessage(request *dns.Msg, response *dns.Msg, frontHeadroom int)
                }
        }
        response.Truncate(maxLen)
+       response.Compress = true
        buffer := buf.NewSize(frontHeadroom + 1 + maxLen)
        buffer.Resize(frontHeadroom, 0)
        rawMessage, err := response.PackBuffer(buffer.FreeBytes())

https://github.com/0xERR0R/blocky/blob/efc14d25ca57dbc0652d4e9784ba2e61646caeaa/server/server.go#L652 Screenshot_20240301-093309_Kiwi Browser

https://github.com/AdguardTeam/dnsproxy/blob/68d417bfdc10e87e5d268aca3bd055e9fd88d206/proxy/dnscontext.go#L128 Screenshot_20240301-093403_Kiwi Browser

https://github.com/XTLS/Xray-core/blob/8fe8aa5432d6f14f62aaecd57d7f35fda04d5c0e/proxy/dns/dns.go#L276

https://github.com/MetaCubeX/mihomo/blob/7eb16a098a92e43c4a8871c0103d670462252bbc/dns/server.go#L35

InspoOnU commented 6 months ago

这种情况不是应该用TCP重传吗?为啥要改UDP响应?

github-actions[bot] commented 4 months ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days