AndroidLibV2ray
AndroidLibV2ray copied to clipboard
libv2ray处理DNS请求的方式有问题
在Android中,开启VPN后,OS仍会负责发起域名解析请求。libv2ray会将DNS请求当作UDP报文直接进行路由,而在默认使用8.8.8.8访问geoip:cn的情况下,在远端发送DNS请求会导致返回不适合本地的IP地址,导致网页访问缓慢或者返回了面向海外的页面。而在PC上,Socks客户端向服务端发送的只有域名信息,域名的解析由v2ray全权负责。tun2socks虽然将tun界面转换为了socks界面,却并不能良好的处理DNS请求,导致DNS请求全部被无脑转发、返回了不适合直连的CDN。比如,通过Actinium访问淘宝,在全局代理下会被重定向到国际版,而在PC上是正常的。原文一开始发在了v2ray/core下,但我感觉应该是libv2ray的实现方式有问题,和v2ray本身应该没有关系。所以稍加编辑、发在了这里。
环境:
- 服务器端:2.47
- PC端:2.47,传入连接使用Socks协议。
- Android端:2.50+libv2ray 25+Actinium。
下面是我的猜测。
首先,Firefox在创建连接时是直接向v2ray发送的域名,本身并没有生成DNS请求。Socks协议允许客户端建立TCP连接时直接请求域名而无须预先将域名解析成IP地址,而Firefox则完全没有参与域名的解析过程,在访问某个页面时只是把域名直接发送给了Socks服务器。若访问的域名属于geosite:cn
,则wireshark中可发现对该网站的DNS请求。若访问的域名不属于geosite:cn
,wireshark中就不能发现对该网站的DNS请求,而v2ray的log中可见通过隧道向8.8.8.8:53
发起的的DNS请求。真正生成DNS请求的应该是v2ray本身。V2ray将会通过路由规则来选择将DNS请求送给OS中设置的DNS服务器或v2ray的配置文件中指定的DNS服务器。
PC环境下Wireshark所获取的Socks报文如下。
Transmission Control Protocol, Src Port: 14696, Dst Port: 1082, Seq: 1, Ack: 1, Len: 3
Socks Protocol
Version: 5
Client Authentication Methods
Transmission Control Protocol, Src Port: 1082, Dst Port: 14696, Seq: 1, Ack: 4, Len: 2
Socks Protocol
Version: 5
Accepted Auth Method: 0x0 (No authentication)
Transmission Control Protocol, Src Port: 14696, Dst Port: 1082, Seq: 4, Ack: 3, Len: 17
Socks Protocol
Version: 5
Command: Connect (1)
Reserved: 0
Address Type: Domain Name (3)(注意这一行)
Remote name: google.com(注意这一行)
Port: 80
……
通过v2ray访问twitter和淘宝的日志输出如下(测试前已清空DNS缓存)。
2017/11/23 11:22:11 [Info]Proxy|Socks: TCP Connect request to tcp:twitter.com:443
2017/11/23 11:22:11 [Info]App|Router: looking up IP for tcp:twitter.com:443
2017/11/23 11:22:11 [Debug]App|DNS|Server: add pending request id 64489
2017/11/23 11:22:11 [Debug]Transport|Internet|UDP: dispatch request to: udp:8.8.8.8:53
2017/11/23 11:22:11 [Info]Transport|Internet|UDP: establishing new connection for udp:8.8.8.8:53
2017/11/23 11:22:11 [Info]App|Dispatcher|Default: default route for udp:8.8.8.8:53
2017/11/23 11:22:11 [Info]App|Proxyman|Mux: dispatching request to udp:8.8.8.8:53
2017/11/23 11:22:11 [Debug]App|DNS|Server: handling response for id 64489 content: ;; opcode: QUERY, status: NOERROR, id: 64489
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;twitter.com. IN A
;; ANSWER SECTION:
twitter.com. 466 IN A 104.244.42.1
twitter.com. 466 IN A 104.244.42.193
2017/11/23 11:22:11 [Debug]App|DNS|Server: returning 2 IPs for domain twitter.com.
2017/11/23 11:22:11 [Info]App|Dispatcher|Default: default route for tcp:twitter.com:443
2017/11/23 11:22:11 [Info]App|Proxyman|Mux: dispatching request to tcp:twitter.com:443
2017/11/23 11:22:11 [Info]Proxy|Socks: TCP Connect request to tcp:twitter.com:443
2017/11/23 11:22:11 [Info]App|Router: looking up IP for tcp:twitter.com:443
2017/11/23 11:22:11 [Info]App|Dispatcher|Default: default route for tcp:twitter.com:443
2017/11/23 11:24:06 [Info]Proxy|Socks: TCP Connect request to tcp:taobao.com:80
2017/11/23 11:24:06 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:taobao.com:80]
2017/11/23 11:24:06 [Info]Proxy|Freedom: opening connection to tcp:taobao.com:80
2017/11/23 11:24:06 [Info]Transport|Internet|TCP: dailing TCP to tcp:taobao.com:80
2017/11/23 11:24:07 [Info]Proxy|Socks: TCP Connect request to tcp:taobao.com:80
2017/11/23 11:24:07 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:taobao.com:80]
2017/11/23 11:24:07 [Info]Proxy|Freedom: opening connection to tcp:taobao.com:80
2017/11/23 11:24:07 [Info]Transport|Internet|TCP: dailing TCP to tcp:taobao.com:80
2017/11/23 11:24:07 [Info]Proxy|Socks: TCP Connect request to tcp:www.taobao.com:443
2017/11/23 11:24:07 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:www.taobao.com:443]
2017/11/23 11:24:07 [Info]Proxy|Freedom: opening connection to tcp:www.taobao.com:443
2017/11/23 11:24:07 [Info]Transport|Internet|TCP: dailing TCP to tcp:www.taobao.com:443
2017/11/23 11:24:08 [Info]Proxy|Socks: TCP Connect request to tcp:www.taobao.com:443
2017/11/23 11:24:08 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:www.taobao.com:443]
2017/11/23 11:24:08 [Info]Proxy|Freedom: opening connection to tcp:www.taobao.com:443
但是在Android平台上,建立TCP链接的流程与PC+Firefox+v2ray有者很大的差别。libv2ray是通过tun2socks将隧道设备转换为socks链接的,而Android OS本身依旧在按照正常的流程(DNS解析、建立连接)对外建立TCP链接,所有的DNS请求都是由OS本身发出的,v2ray本身只能将DNS报文当作普通的UDP报文、按照路由设置机械的转发。Android在建立连接时将会直接使用IP建立连接。
通过v2ray访问twitter和淘宝的日志输出如下。
2017/11/23 05:21:30 [Info]Proxy|Socks: client UDP connection from udp:127.0.0.1:43520
2017/11/23 05:21:30 [Debug]Proxy|Socks: send packet to udp:8.8.8.8:53 with 28 bytes
2017/11/23 05:21:30 [Debug]Transport|Internet|UDP: dispatch request to: udp:8.8.8.8:53
2017/11/23 05:21:30 [Info]Transport|Internet|UDP: establishing new connection for udp:8.8.8.8:53
2017/11/23 05:21:30 [Info]App|Dispatcher|Default: default route for udp:8.8.8.8:53
2017/11/23 05:21:30 [Info]App|Proxyman|Mux: dispatching request to udp:8.8.8.8:53
………………
2017/11/23 05:21:30 [Info]Proxy|Socks: TCP Connect request to tcp:202.47.28.119:443
2017/11/23 05:21:30 [Info]App|Dispatcher|Default: sniffed domain: taobao.com
2017/11/23 05:21:30 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:taobao.com:80]
2017/11/23 05:21:30 [Info]Proxy|Freedom: opening connection to tcp:taobao.com:80
2017/11/23 05:21:30 [Info]Transport|Internet|TCP: dailing TCP to tcp:taobao.com:80
………………
2017/11/23 05:21:30 [Info]Proxy|Socks: TCP Connect request to tcp:47.89.66.254:443
2017/11/23 05:21:31 [Info]App|Dispatcher|Default: sniffed domain: m.taobao.com
2017/11/23 05:21:31 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:m.taobao.com:443]
2017/11/23 05:21:31 [Info]Proxy|Freedom: opening connection to tcp:m.taobao.com:443
2017/11/23 05:21:31 [Info]Transport|Internet|TCP: dailing TCP to tcp:m.taobao.com:443
………………
2017/11/23 05:21:38 [Info]Proxy|Socks: client UDP connection from udp:127.0.0.1:55957
2017/11/23 05:21:38 [Debug]Proxy|Socks: send packet to udp:8.8.8.8:53 with 19 bytes
2017/11/23 05:21:38 [Debug]Transport|Internet|UDP: dispatch request to: udp:8.8.8.8:53
2017/11/23 05:21:38 [Info]Transport|Internet|UDP: establishing new connection for udp:8.8.8.8:53
2017/11/23 05:21:38 [Info]App|Dispatcher|Default: default route for udp:8.8.8.8:53
2017/11/23 05:21:38 [Info]App|Proxyman|Mux: dispatching request to udp:8.8.8.8:53
2017/11/23 05:21:38 [Info]App|Dispatcher|Default: sniffed domain: m.intl.taobao.com
2017/11/23 05:21:38 [Info]App|Dispatcher|Default: taking detour [direct] for [tcp:m.intl.taobao.com:443]
2017/11/23 05:21:38 [Info]Proxy|Freedom: opening connection to tcp:m.intl.taobao.com:443
2017/11/23 05:21:38 [Info]Transport|Internet|TCP: dailing TCP to tcp:m.intl.taobao.com:443
2017/11/23 04:47:54 [Info]Proxy|Socks: client UDP connection from udp:127.0.0.1:35010
2017/11/23 04:47:54 [Info]Transport|Internet|UDP: establishing new connection for udp:8.8.8.8:53
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: default route for udp:8.8.8.8:53
2017/11/23 04:47:54 [Info]App|Proxyman|Mux: dispatching request to udp:8.8.8.8:53
2017/11/23 04:47:54 [Info]Proxy|Socks: TCP Connect request to tcp:104.244.42.65:443
2017/11/23 04:47:54 [Info]Proxy|Socks: TCP Connect request to tcp:104.244.42.65:443
2017/11/23 04:47:54 [Info]Proxy|Socks: TCP Connect request to tcp:104.244.42.65:443
2017/11/23 04:47:54 [Info]Proxy|Socks: TCP Connect request to tcp:104.244.42.65:443
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: sniffed domain: twitter.com
2017/11/23 04:47:54 [Info]App|Router: looking for IP for domain: twitter.com
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: default route for tcp:twitter.com:443
2017/11/23 04:47:54 [Info]App|Proxyman|Mux: dispatching request to tcp:twitter.com:443
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: sniffed domain: twitter.com
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: sniffed domain: twitter.com
2017/11/23 04:47:54 [Info]App|Router: looking for IP for domain: twitter.com
2017/11/23 04:47:54 [Info]App|Router: looking for IP for domain: twitter.com
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: default route for tcp:twitter.com:443
2017/11/23 04:47:54 [Info]App|Proxyman|Mux: dispatching request to tcp:twitter.com:443
2017/11/23 04:47:54 [Info]App|Router: looking for IP for domain: twitter.com
2017/11/23 04:47:54 [Info]App|Dispatcher|Default: default route for tcp:twitter.com:443
2017/11/23 04:47:54 [Info]App|Proxyman|Mux: dispatching request to tcp:twitter.com:443
2017/11/23 04:47:54 [Info]Transport|Internet|WebSocket: creating connection to tcp:wodeipdizhi:80
2017/11/23 04:47:55 [Info]Proxy|VMess|Outbound: tunneling request to tcp:v1.mux.cool:9527 via tcp:wodeipdizhi:80
因此v2ray在这个情况下就不能将域名与按照路由规则送给不同的服务器解析。如果DNS设置为海外的服务器就会导致淘宝返回海外版页面。即使是设置了domainOverride也只能是在建立连接时再通过嗅探选择直连或走隧道,无法解决问题。
Android端配置文件
{
"port": 10808,
"log": {
"loglevel": "debug"
},
"inbound": {
"domainOverride": [
"http",
"tls"
],
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"allowPassive": true
},
"inboundDetour": [
{
"protocol": "http",
"port": 10845,
"settings": {},
"listen": "127.0.0.1"
},
{
"protocol": "dokodemo-door",
"port": 10846,
"listen": "0.0.0.0",
"settings": {
"network": "tcp",
"timeout": 0,
"followRedirect": true
}
}
],
"outbound": {
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "<ws.address>",
"port": <ws.port>,
"users": [
{
"id": "<id>",
"alterId": 64,
"security": "auto"
}
]
}
]
},
"mux":{
"enabled":true
}
},
"outboundDetour": [
{
"protocol": "freedom",
"settings": {},
"tag": "direct"
}
],
"dns": {
"servers": [
"8.8.8.8",
"8.8.4.4",
"localhost"
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"port": "1-52",
"outboundTag": "direct"
},
{
"type": "field",
"port": "54-79",
"outboundTag": "direct"
},
{
"type": "field",
"port": "81-442",
"outboundTag": "direct"
},
{
"type": "field",
"port": "444-65535",
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"::1/128",
"fc00::/7",
"fe80::/10",
"geoip:cn"
],
"outboundTag": "direct"
}
]
}
},
"transport": {},
"#lib2ray": {
"enabled": true,
"listener": {
"onUp": "#none",
"onDown": "#none"
},
"env": [
"V2RayDNSPort=5353",
"DNSForwardingProxyPort=5350",
"V2RaySocksPort=10808"
],
"render": [],
"escort": [],
"vpnservice": {
"Target": "${datadir}tun2socks",
"Args": [
"--netif-ipaddr",
"26.26.26.2",
"--netif-netmask",
"255.255.255.0",
"--socks-server-addr",
"127.0.0.1:$V2RaySocksPort",
"--tunfd",
"3",
"--tunmtu",
"1500",
"--sock-path",
"/dev/null",
"--loglevel",
"4",
"--enable-udprelay"
],
"VPNSetupArg": "m,1500 a,26.26.26.1,24 r,0.0.0.0,0 d,208.67.222.222"
},
"preparedDomainName": {
"domainName": [
"<ws.address>:<ws.port>"
],
"tcpVersion": "tcp4",
"udpVersion": "udp4"
}
}
}
PC端配置文件
{
"log": {
"loglevel": "debug"
},
"inbound": {
"port": 1082,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true,
"ip": "127.0.0.1",
"timeout": 0
}
},
"outbound": {
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "<ws.address>",
"port": <ws.port>,
"users": [
{
"id": "<id>",
"alterId": 64,
"security": "auto"
}
]
}
]
},
"mux":{
"enabled":true
}
},
"outboundDetour": [
{
"protocol": "freedom",
"settings": {},
"tag": "direct"
}
],
"dns": {
"servers": [
"8.8.8.8",
"8.8.4.4",
"localhost"
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"port": "1-52",
"outboundTag": "direct"
},
{
"type": "field",
"port": "54-79",
"outboundTag": "direct"
},
{
"type": "field",
"port": "81-442",
"outboundTag": "direct"
},
{
"type": "field",
"port": "444-65535",
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"::1/128",
"fc00::/7",
"fe80::/10",
"geoip:cn"
],
"outboundTag": "direct"
}
]
}
}
}
(两者的路由、DNS、传出规则都是一致的)
我对这个问题的解决办法,就是白名单。 翻墙白名单内的走 vps,其他的走 direct。
@cnperi 你指的是app白名单还是config.json里设置域名白名单?
@yoshikotama config.json 白名单。虽然仍有问题,但可用。 不过,好像只能用 v2raygo。
@cnperi 我试过,依旧会用8.8.8.8解析白名单的域名。
对啊,不就是要用墙外 DNS 解析这些被墙域名吗?那些不需要的,走默认 direct 啊。
哦。我理解你的意思了。这个问题,估计需要在 libv2ray里面加 pdnsd 或是 dnsmasq 来解决了。或者 iptables。
是否可以使用core的domain override功能来解决这个问题呢?(对于HTTP|TLS数据)
@xiaokangwang 已经用了 domain override 了。 关键是所有的 UDP 数据都导到 TUN 里面了。 不知 vpn 环境里面用 墙内 DNS 的方式可行不?
有DNS投毒的。。。 你是希望DNS快还是返回兼容的结果?
@xiaokangwang 若是 v2ray core 的 domian override 能修正 DNS 投毒结果的话,就可以这么干啊。
有可能能修正,你可以尝试一下。。。。会让兼容性下降的
@xiaokangwang domainOverride是事后诸葛亮,原文里写过了。
这个其实是Android系统机制决定的,因此之前提到的方法都是对于这个情况的一种修补
@xiaokangwang 能不能把 libv2ray 的 pdnsd 换成 dnsmasq,把 udpgw 中目标地址 53 端口的 udp 包转给 dnsmasq。这样让 dnsmasq 来做 dns 分流的事儿?
libv2ray里的pdnsd已经不在被使用了,现在所有的udp流量都作为udp数据直接转发
我也發現同樣的問題,但我測試v2rayNG似乎解決了這個問題,不知道用什麼方法。這方面做得最好的還是Shadowsocks Android,用overture分流。