Repository: fatedier/frp (language: go)

Issue:
建议默认不要启用DNS解析回退
### Bug Description

这个issue实际上就是个小建议，配置文件中提供参数关闭DNS回退，或者直接取消这个功能，以预防运营商针对指定DNS进行劫持。
复现过程（并不是被这样发现的，我的dns是185.222.222.222，因为我这里1.1.1.1被拦截了）：如果我把resolv.conf中的dns改成了1.1.1.1，frpc在解析域名失败后，不会提醒而会直接走8.8.8.8，运营商通过假的8.8.8.8返回一个特殊IP，导致frpc连接不上。

偶尔路由器重启，这时发现的
```
~ $ cat ../usr/etc/resolv.conf
nameserver 185.222.222.222
~ $ frpc
WARNING: ini format is deprecated and the support will be removed in the future, please use yaml/json/toml format instead!
2024-05-20 13:03:02.472 [I] [sub/root.go:142] start frpc service for config file [./frpc.ini]
2024-05-20 13:03:02.472 [I] [client/service.go:294] try to connect to server...
2024-05-20 13:03:02.475 [W] [client/service.go:297] connect to server error: dial tcp: lookup f on 185.222.222.222:53: dial udp 8.8.8.8:53: connect: network is unreachable
2024-05-20 13:03:02.475 [I] [sub/root.go:160] frpc service for config file [./frpc.ini] stopped
login to the server failed: dial tcp: lookup f on 185.222.222.222:53: dial udp 8.8.8.8:53: connect: network is unreachable. With loginFailExit enabled, no additional retries will be attempted
~ $
```
这也太危险了。Traceroute发现这个8.8.8.8根本不是谷歌DNS，完全是运营商内网。
```
~ $ traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
 1  192.168.1.1 (192.168.1.1)  69.506 ms  68.482 ms  67.884 ms
 2  100.77.64.1 (100.77.64.1)  67.018 ms  66.224 ms  65.476 ms
 3  8.8.8.8 (8.8.8.8)  64.777 ms  64.096 ms  63.404 ms
```
而且
```
~ $ nslookup termux.dev 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
Name:   termux.dev
Address: 124.236.16.201
Name:   termux.dev
Address: ::
```
还有
```
~ $ nslookup raw.githubusercontent.com 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
Name:   raw.githubusercontent.com
Address: 0.0.0.0
Name:   raw.githubusercontent.com
Address: ::

~ $
```
万一哪天网速慢了或者185.222.222.222挂了，这会直接导致token泄漏，或者宽带建站被运营商检测导致封宽带的情况。

### frpc Version

0.58.0

### frps Version

N/A

### System Architecture

android/arm64

### Configurations

[common]
server_addr = frpserverdomain*
server_port = 7000
token = 6666666666*
tls_enable = true
protocol = tcp

[6f3a0f37_http]
type = http
local_ip = 127.0.0.1
local_port = 8000
custom_domains = 1a*

[16455db9_https]
type = https
local_ip = 127.0.0.1
local_port = 44300
custom_domains = 2b*

### Logs

_No response_

### Steps to reproduce

1. 
2. 
3. 
...


### Affected area

- [ ] Docs
- [ ] Installation
- [ ] Performance and Scalability
- [X] Security
- [ ] User Experience
- [ ] Test and Release
- [ ] Developer Infrastructure
- [ ] Client Plugin
- [ ] Server Plugin
- [ ] Extensions
- [ ] Others


Discussion / hints:
`nslookup -type=TXT whoami.ds.akahelp.net` 可获得 DNS 出口 IP
~~frpc 有 DNS 退回机制吗？~~
token **不是**明文传输，它使用了**时间戳**等方法“加密”
> `nslookup -type=TXT whoami.ds.akahelp.net` 可获得 DNS 出口 IP ~frpc 有 DNS 退回机制吗？~ token **不是**明文传输，它使用了**时间戳**等方法“加密”

frpc老版本（0.55.0及以下版本）确实没有dns回退，但是https://github.com/fatedier/frp/commit/f16ef0097565f4835fb1fd04074c9310fa22a30b 这个commit给加上了，(0.56.0)然后让我apt update;apt upgrade出来了。

网上有报道宽带建站被运营商检测封宽带的......
另外我这里的"8.8.8.8"好像不能解析txt记录，但是185.222.222.222和运营商提供的DNS反而都能。
```
~ $ nslookup -type=TXT whoami.ds.akahelp.net 8.8.8.8
;; connection timed out; no servers could be reached


~ $ nslookup -type=TXT whoami.ds.akahelp.net
Server:         185.222.222.222
Address:        185.222.222.222#53

Non-authoritative answer:
whoami.ds.akahelp.net   text = "ns" "74.125.181.133"
whoami.ds.akahelp.net   text = "ip" "142.147.88.98"
whoami.ds.akahelp.net   text = "ecs" "142.147.88.0/24/24"

Authoritative answers can be found from:

~ $ nslookup -type=TXT whoami.ds.akahelp.net 192.168.10.1
Server:         192.168.10.1
Address:        192.168.10.1#53

Non-authoritative answer:
whoami.ds.akahelp.net   text = "ns" "111.11.1.147"

Authoritative answers can be found from:

~ $
```
我觉得也可以增加个开关，比如（这个是ini格式，只是个人猜想，还没写实现代码）
```
[common]
nodnsfallback = true
```
> 另外我这里的"8.8.8.8"好像不能解析txt记录

可能丢完了，多来几遍
> > 另外我这里的"8.8.8.8"好像不能解析txt记录
> 
> 可能丢完了，多来几遍


重试偶尔能出来个
```
~ $ nslookup -type=TXT whoami.ds.akahelp.net 8.8.8.8
Server:         8.8.8.8
Address:        8.8.8.8#53

Non-authoritative answer:
whoami.ds.akahelp.net   text = "ns" "111.11.11.160"

Authoritative answers can be found from:
```
## 上面的txt解析结果明显少了两行，ip，ecs

这个IP与运营商DNS网段是相同的，ping不通，而且DNS解析也不通
```
~ $ dig @111.11.11.160

; <<>> DiG 9.16.41 <<>> @111.11.11.160
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
```
测试手机数据网络是正常的，不过总不能用移动数据跑frpc吧，成本太高了。
> 上面的txt解析结果明显少了两行，ip，ecs
> 这个IP与运营商DNS网段是相同的

那就是 劫持了
> > 上面的txt解析结果明显少了两行，ip，ecs
> > 这个IP与运营商DNS网段是相同的
> 
> 那就是 劫持了

我知道是劫持。以前申请eu.org免费域名时遇到过网站打不开的情况，关掉火狐的HTTPS Only，一刷新网站出现了"下载国家反诈中心"的网页。....... 最终185.222.222.222+223.5.5.5+223.6.6.6解决。就这几个正常，其他全被劫持。

这个issue实际上就是个小建议，类似下面的配置文件中提供参数关闭DNS回退，或者直接取消这个功能，以预防运营商针对指定DNS进行劫持。
我原来2022年遇到过，现在也是一样：1.1.1.1这个DNS被直接拦截，ping都不通。如果我把resolv.conf中的dns改成了1.1.1.1，frpc在解析域名失败后，不会提醒而会直接走8.8.8.8，运营商通过假的8.8.8.8返回一个特殊IP，只要frpc连接上，运营商马上就会检测到。有可能宽带就被封了，我没被封，但就是连不上frps，因为我这里返回了0.0.0.0。如果运营商返回了某个"钓鱼"IP就惨了。
```
[common]
nodnsfallback = true
```
https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml#L121

```
# Specify a dns server, so frpc will use this instead of default one
# dnsServer = "8.8.8.8"
```

目前不会在这方面引入过多的参数。你可以通过上述配置主动配置你需要使用的 dns server。

如果你的路由器不是 android 系统，建议不要使用 android/arm64 的二进制包，这个包是针对 android 特别定制的。
> https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml#L121
> 
> ```
> # Specify a dns server, so frpc will use this instead of default one
> # dnsServer = "8.8.8.8"
> ```
> 
> 目前不会在这方面引入过多的参数。你可以通过上述配置主动配置你需要使用的 dns server。
> 
> 如果你的路由器不是 android 系统，建议不要使用 android/arm64 的二进制包，这个包是针对 android 特别定制的。

我是安卓手机Termux里的frpc。那个参数dnsServer = "185.222.222.222"我试一下，不管用呀，当我断网模拟解析失败时，发现它照样8.8.8.8去了
另外Linux/Arm64版本没有dns回退吗，如果仍然有的话，那我就弄个工具链自己编译一个。
你用 ini 格式的话，就参考旧的配置文件的写法，大概率是 `dns_server`。

这个功能的本意是 android 环境的特殊性，go 无法获取到 android 上默认的 dns server，所以会默认使用 127.0.0.1:53 ，导致 dns 解析失败。

你这个场景里，不确定你是用什么方式让 go 能识别到系统的 dns server。是否是你自己创建了 /etc/resolv.conf。不过既然你这个场景下可以识别出系统 dns server，那就没有必要使用 8.8.8.8 了，这个 case 会优化掉，预期应该是仅在当前 dns 地址为 127.0.0.1:53 的时候才使用。
OK

Fix patch:
diff --git a/Release.md b/Release.md
index ef65ec1ce5e..5cb27c3e17b 100644
--- a/Release.md
+++ b/Release.md
@@ -5,3 +5,4 @@
 ### Changes
 
 * Updated the default value of `transport.tcpMuxKeepaliveInterval` from 60 to 30.
+* On the Android platform, the Google DNS server is used only when the default DNS server cannot be obtained.
diff --git a/pkg/util/system/system_android.go b/pkg/util/system/system_android.go
index bfcf401dfb5..6fcfdbc1361 100644
--- a/pkg/util/system/system_android.go
+++ b/pkg/util/system/system_android.go
@@ -59,8 +59,12 @@ func fixDNSResolver() {
 	// Note: If there are other methods to obtain the default DNS servers, the default DNS servers should be used preferentially.
 	net.DefaultResolver = &net.Resolver{
 		PreferGo: true,
-		Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
-			return net.Dial(network, "8.8.8.8:53")
+		Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
+			if addr == "127.0.0.1:53" || addr == "[::1]:53" {
+				addr = "8.8.8.8:53"
+			}
+			var d net.Dialer
+			return d.DialContext(ctx, network, addr)
 		},
 	}
 }


Test patch: