A fully-featured V2Ray client for Android.
You must first build the tun2socks.aar
library from this repo and copy it into app/libs
, get geoip.dat
and geosite.dat
from the latest v2ray-core release and copy them into app/src/main/res/raw
.
这个 V2Ray Android 客户端利用 go-tun2socks
把所有的 TCP/UDP 流量转给到 V2Ray 处理,所用的 v2ray-core
是没经过任何修改的官方版本,所以在配置和体验方面不会有太大差别。但在 Android 上有一些东西需要特殊处理,这也是在配置和使用上造成一些差别的地方。
- UDP 流量在转给 V2Ray 之前,会先在
go-tun2socks
里面经过一个嗅探步骤,如果嗅探出来是 DNS 流量,这些 UDP 流量就不会直接转给 V2Ray,而是把其中需要解析的域名抽取出来再通过 V2Ray 的 DNS 去解析,这时 V2Ray 所用的 DNS 服务器是按照配置文件上的配置来选取,也就是说所用的 DNS 服务器不需要跟原来 UDP 流量的目的地址相同。 - 在 Android 上有几个情况会造成流量/请求的死循环,目前就我所知的有以下几个:
- 通过 VpnService 的 TUN 接口读取数据,再由代理程序代为发出时,如果不 protect 代理程序用来发数据的 socket fd,代理程序发出的数据又会被转到 TUN 接口上,这个问题基本可以用 v2ray-core 提供的
RegisterDialerController()
和RegisterListenerController()
两个接口完美解决 - 当代理服务器的地址是域名的时候,如果要转发数据给代理服务器,就必须先把代理服务器的 IP 地址解析出来,但这个 DNS 解析本身又有可能是另一个代理请求(考虑下全局模式),就出现死循环了,这个问题大概可以有两种解决方法:一是在启动 VPN 前把所有代理服务器的 IP 预先解析出来,之后如果碰到要解析这些域名的请求,就直接替换/返回预先解析好的 IP,二是强制所有这些域名不走代理(结合
go-tun2socks
的 DNS 请求拦截特性,利用 V2Ray 的 DNS 和路由功能可以比较容易实现)。本项目目前采用第一个方法,但这方法的缺点很明显就是当域名所对应的 DNS 记录中途被修改了的话就要重连 VPN - 还有一种会引起死循环的情况是 V2Ray 的 DNS 配置里用
localhost
(不配置 DNS 的话默认就是用localhost
,所以必须要配置),一方面因为go-tun2socks
的 DNS 流量拦截特性,另一方面因为本地 DNS
所发出的 UDP 流量不太容易 protect 起来,所以就会形成这样一个死循环:V2Ray 用本地 DNS
(localhost
) 发请求,UDP 流量没被 protect,发到 TUN 接口上,go-tun2socks
拦截下来,用 V2Ray 的 DNS 解析,V2Ray 用本地 DNS
(localhost
) 发请求......解决方法当然是要强制禁止用localhost
- 通过 VpnService 的 TUN 接口读取数据,再由代理程序代为发出时,如果不 protect 代理程序用来发数据的 socket fd,代理程序发出的数据又会被转到 TUN 接口上,这个问题基本可以用 v2ray-core 提供的
Github Releases: https://github.com/eycorsican/Kitsunebi4Android/releases
- App 使用较新的 v2ray-core 版本,你或许需要确保服务端也升级到相应的版本,具体版本号请看 Release Notes,
- 把配置文件复制粘贴至主界面后,点击连接按钮即可启动
- 如果配置文件不正确或者出错,通常不会有任何错误提示
- 配置文件可使用一个常见的 V2Ray 配置
- 配置文件的 freedom outbound 推荐使用
UseIP
策略 - 配置文件不需要有 Inbound,app 使用了
tun2socks
作为 inbound,并已开启 http,tls 流量嗅探 - 配置文件中必需至少配置 1 个 DNS 服务器,但绝对不能用 "localhost"(会引起死循环),国内或国外 DNS 都问题不大,V2Ray 的 sniffing 功能配合一些域名路由规则可以很大程序上解决染污问题
- 设备所有 DNS 请求均会由 V2Ray 的 DNS 服务器 来解析,正确设置了 DNS 服务器可以避免 DNS 污染以及 CDN 相关的 DNS 问题
- 非 VMess 的 outbound 必需用 IP 作服务器地址
- 下面是一个示例配置:
{
"log": {
"loglevel": "info"
},
"policy": {
"0": {
"bufferSize": 0
}
},
"dns": {
"clientIP": "115.239.211.92", # 你的对外地址(或者随便找个同地区的 IP),用来提示 DNS 服务器返回合适的 IP
"hosts": {
"localhost": "127.0.0.1"
},
"servers": [
"8.8.8.8",
"1.1.1.1",
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn" # 如果 DNS 请求的域名匹配了,就优先使用这个 DNS 服务器去解析
]
}
]
},
"outbounds": [
{
"mux": {
"concurrency": 8,
"enabled": false
},
"protocol": "vmess",
"settings": {
"vnext": [
{
"users": [
{
"id": "01f7abbf-1431-48d7-bc22-fd1d614d8dfe",
"alterId": 0,
"security": "chacha20-poly1305"
}
],
"address": "myserver.com",
"port": 10086
}
]
},
"streamSettings": {
"network": "tcp"
},
"tag": "proxy"
},
{
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP" # 为了把所有 DNS 请求都给到 V2Ray 处理
},
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "block"
}
],
"routing": {
"settings": {
"rules": [
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:cn",
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy" # 没匹配任何规则就转发给代理
}
],
"domainStrategy": "IPIfNonMatch"
},
"strategy": "rules"
}
}