Xray-core 现在使用了 reality 传输协议。这具有更好的隐蔽特性,可以极大地模仿普通网页的流量。引用其官方介绍:
若用 REALITY 取代 TLS,可消除服务端 TLS 指纹特征,仍有前向保密性等,且证书链攻击无效,安全性超越常规 TLS可以指向别人的网站,无需自己买域名、配置 TLS 服务端,更方便,实现向中间人呈现指定 SNI 的全程真实 TLS。
模仿的网站也可以在配置文件中指定。对于服务端、客户端使用的 xray,只要使用最新版本(例如 pre-release v1.8.3)的就可以支持 reality 协议,并不需要单独安装 reality 相关插件。下面是在 PVE 上使用 LXC 容器搭建一个 xray 客户端并使用 reality 传输协议,并将其用作透明网关。
首先在 PVE 创建一个 debian LXC 容器。之所以选择 debian,是因为它的文件系统里集成的工具较为齐全。如果追求精简,那么在 alpine 容器上开始搭建也可以,但中间需要解决一堆软件依赖问题。CPU 使用 1 核心,1GB RAM 和 16GB disk。Xray-core 在运行时使用的内存其实不大,一般不超过 200MB。创建容器时可以开启特权模式、关闭防火墙。为了便于后面往容器里复制文件,在安装完启动后,开启 ROOT 用户的 SSH 登录。在 /etc/ssh/sshd_config 中添加:
PermitRootLogin yes
在 debiam 容器里 Xray 客户端配置文件 local.json 如下,由于 json 不支持注释,所以下面文件分段说明。
{
"log": {
"loglevel": "warning",
"error": "/root/xray/error.log",
"access": "/root/xray/access.log"
},
日志记录基本为 warning,刚开始配置或者检查问题时可以设置为 debug,记录详细的信息。
"inbounds": [
{
"tag": "all-in",
"port": 35791,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
inbounds 时入站条目。Xray 客户端侦听 35791 端口上的所有数据,由于做透明网关,所以 protocol 为 dokodemo-door,即入站的数据格式不限。
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"streamSettings": {
"sockopt": {
"mark": 2
}
}
},
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "example.com",
"port": 443,
"users": [
{
"id": "XXXXXXXXX",
"flow": "xtls-rprx-vision",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"fingerprint": "chrome",
"serverName": "www.microsoft.com",
"publicKey": "xxxxxxxxxx",
"shortId": "xxxx",
"spiderX": "/"
},
"sockopt": {
"mark": 2
}
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"address": "8.8.8.8",
"clientIP": "1.2.3.4"
},
"proxySettings": {
"tag": "proxy"
},
"streamSettings": {
"sockopt": {
"mark": 2
}
}
}
],
outbounds 是出站条目。tag:direct 是默认出站条目,不匹配规则的流量都从这个出去,不经过代理。tag:block 是黑洞条目,将广告等流量引导到这里。tag:dns-out 用于 DNS 查询。在这个配置里面将劫持所有发送到本网关 53 端口的 DNS 查询,然后通过代理发送到 8.8.8.8 查询。由于代理服务器通常位于海外,所以clientIP 可以用于通知服务器以指定 IP 位置查询 DNS。这里的 IP 可以使用离你最近的某个公网 IP,如电信、联通给你家光猫、路由器分配的 DNS 服务器 IP 地址。tag:proxy 就是和代理服务器的 reality 连接配置。"address": "example.com" 里面改为自己的代理服务器的 IP 或者域名。port 建议使用 443。id 用于服务器区分不同的客户端,可以使用 xray uuid 生成。streamSettings 的 security 设置使用 reality 协议。serverName 是将要模仿的流量对象网站。publicKey 密钥使用 xray x25519 生成,这里填写公钥,私钥则填写在服务端的配置文件。shortid 可使用十六进制的 0 到 f,长度为 2 的倍数,长度上限为 16。这里的 shortid 需要出现在服务端配置的 shortids 中。
"dns": {
"hosts": {
"my.own.domain": "6.6.6.6"
},
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn"
],
"expectIPs": [
"geoip:cn"
]
},
"8.8.8.8",
"8.8.4.4",
"https+local://doh.dns.sb/dns-query"
]
},
配置内置的 DNS,由于在路由阶段, 解析域名为 IP, 并且根据域名解析得到的 IP 进行规则匹配以分流。hosts 可以手动配置 DNS 条目,例如内部网络使用的域名。
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"all-in"
],
"port": 53,
"outboundTag": "dns-out"
},
{
"type": "field",
"ip": [
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"domain": [
"geosite:geolocation-!cn"
],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": [
"91.108.0.0/16",
"109.239.140.0/24",
"149.154.160.0/20",
"2001:67c:4e8::/48",
"2001:b28:f23d::/48",
"2001:b28:f23f::/48"
],
"outboundTag": "proxy"
}
]
}
}
路由规则,其实是数据分流规则。将不同类型的数据转发到代理、直连或者黑洞。最后一部分是 TG 相关的 IP,可以酌情使用。
服务端的配置则相对简单,功能和上面一样,就不再分段解释。如果有多个客户端使用的话,在 inbounds->settings->clients 中添加多个对应的 id,shortIds 也是同样。
{
"log": {
"loglevel": "warning",
"access": "/var/log/xray/access.log",
"error": "/var/log/xray/error.log"
},
"dns": {
"servers": [
"https+local://dns.google/dns-query",
"https+local://1.1.1.1/dns-query",
"localhost"
]
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "block"
},
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
}
]
},
"inbounds": [
{
"listen": "0.0.0.0",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "XXXXXXXXX",
"flow": "xtls-rprx-vision"
},
{
"id": "XXXXXXXXX",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "www.microsoft.com:443",
"xver": 0,
"serverNames": [
"www.microsoft.com"
],
"privateKey": "xxxxxxxxx",
"minClientVer": "",
"maxClientVer": "",
"maxTimeDiff": 0,
"shortIds": [
"xxxx",
"xxxx"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"policy": {
"levels": {
"0": {
"handshake": 3,
"connIdle": 180
}
}
}
}
在客户端做透明代理时,需要运行下面命令:
ip route add local default dev lo table 100
ip rule add fwmark 1 table 100
将下面文件保存为 nft.conf,并设置可执行权限 chmod a+x nft.conf,然后运行该文件。其中RESERVED_IP 定义的私有地址,以及侦听 53 端口的网关地址根据实际情况调整。
#!/usr/sbin/nft -f
flush ruleset
define RESERVED_IP = {
10.0.0.0/16,
10.16.0.0/16,
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,
224.0.0.0/4,
240.0.0.0/4,
255.255.255.255/32
}
table ip xray {
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ip daddr $RESERVED_IP return
ip daddr 10.20.1.0/24 tcp dport != 53 return
ip daddr 10.20.1.0/24 udp dport != 53 return
ip protocol tcp tproxy to 127.0.0.1:35791 meta mark set 1
ip protocol udp tproxy to 127.0.0.1:35791 meta mark set 1
}
chain output {
type route hook output priority mangle; policy accept;
ip daddr $RESERVED_IP return
ip daddr 10.20.1.0/24 tcp dport != 53 return
ip daddr 10.20.1.0/24 udp dport != 53 return
meta mark 2 return
ip protocol tcp meta mark set 1
ip protocol udp meta mark set 1
}
}
在客户端和服务器上运行 xray -c config.json。