Xray-core新特性使用教程(更多最终伪装层类型、Hysteria2入站与更新、QUIC参数、根据路由规则发送WebHook)

更多最终伪装层类型

Xray-core的26.3.27更新增加许多的最终伪装层类型,且能够支持所有协议。(对于专注介绍“最终伪装层(Finalmask)”的文章,这里正在编写呀。)

自定义握手(TCP)(header-custom

此伪装层能够于实际数据传输之前增加一个自定义的“握手”过程,以将代理协议伪装为其它协议。这里将首先介绍配置,随后提供部分示例呀。

[!warning] 警告
此伪装层能够“模拟”其它协议,但是,具体实施中往往会出现明显的流量特征,且被主动探测时十分脆弱,请谨慎使用。

“自定义握手”伪装层包含2个主要配置:clientsservers

{
    "streamSettings": {
        "finalmask": {
            "tcp": [
                {
                    "type": "header-custom",
                    "settings": {
                        "clients": [],
                        "servers": []
                    }
                }
            ]
        }
    }
}

上述3个数组均用于容纳1个或多个“对话轮次”。

“对话轮次”

对于需要握手的协议,“握手”意味着“需要于实际数据前,通过多次往返数据以建立隧道或连接”[1]。此处的“对话轮次”便可理解为“握手阶段”,它通过1个“包含此轮应发送/接收数据的数组”定义。

出站将专注于向服务器发送clients数组中的内容,期望servers数组中的内容返回;入站反之,向客户端发送servers中的内容,期望得到clients中的内容。另外,存在1个errors数组,它仅适用于入站,用于定义每轮验证失败时回复的内容。

以下文本应该能够描述1个自定义握手过程呀:

{
    "type": "header-custom",
    "settings": {
        "clients": [
            [
                {
                    "type": "array",
                    "packet": [
                        0
                    ]
                },
                {
                    "type": "str",
                    "packet": "您好,这里需要建立连接。"
                }
            ],
            [
                {
                    "type": "str",
                    "packet": "以下为随机数据与密码:"
                },
                {
                    "rand": 32
                },
                {
                    "type": "hex",
                    "packet": "08FFFEFDFCFBFAF9F8"
                }
            ],
            [
                {
                    "type": "str",
                    "packet": "接下来是实际数据。"
                }
            ]
        ],
        "servers": [
            [
                {
                    "type": "str",
                    "packet": "请提供32字节的随机数据和密码。"
                }
            ],
            [
                {
                    "type": "str",
                    "packet": "验证成功。"
                }
            ]
        ],
        "errors": [
            [
                {
                    "type": "str",
                    "packet": "不是预期的协议版本。"
                }
            ],
            [
                {
                    "type": "str",
                    "packet": "畸形数据或密码错误。"
                }
            ]
        ]
    }
}
引号中的内容为字符串,否则为十六进制。
S:服务器
C:客户端

C → S:00 “您好,这里需要建立连接。”
S → C:“请提供32字节的随机数据和密码。”
C → S:“以下为随机数据与密码:” BA 83 05 27 A6 (26字节) 4A 08 FF FE FD FC FB FA F9 F8
S → C:“验证成功。”
C → S:“接下来是实际数据。”

示例配置

以下为部分示例配置呀。

SSH版本标识
{
    "clients": [],
    "servers": [
        [
            {
                "type": "str",
                "packet": "SSH-2.0-OpenSSH_10.0p2 Debian-7\r\n"
            }
        ]
    ]
}
使用用户密码认证的SOCKS5协议
{
    "clients": [
        [
            {
                "type": "hex",
                "packet": "050102"
            }
        ],
        [
            {
                "type": "hex",
                "packet": "0104757365720470617373"
            }
        ],
        [
            {
                "type": "hex",
                "packet": "050100030b6578616d706c652e636f6d01bb"
            }
        ]
    ],
    "servers": [
        [
            {
                "type": "hex",
                "packet": "0502"
            }
        ],
        [
            {
                "type": "hex",
                "packet": "0100"
            }
        ],
        [
            {
                "type": "hex",
                "packet": "05000001000000000000"
            }
        ]
    ]
}
使用STARTTLS的SMTP协议
{
    "clients": [
        [],
        [
            {
                "type": "str",
                "packet": "EHLO client\r\n"
            }
        ],
        [
            {
                "type": "str",
                "packet": "STARTTLS\r\n"
            }
        ]
    ],
    "servers": [
        [
            {
                "type": "str",
                "packet": "220 foo.com ESMTP Postfix (Ubuntu)\r\n"
            }
        ],
        [
            {
                "type": "str",
                "packet": "250-foo.com\r\n"
            },
            {
                "type": "str",
                "packet": "250-STARTTLS\r\n"
            },
            {
                "type": "str",
                "packet": "250 AUTH PLAIN LOGIN\r\n"
            }
        ],
        [
            {
                "type": "str",
                "packet": "220 Ready to start TLS\r\n"
            }
        ]
    ],
    "errors": [
        [],
        [
            {
                "type": "str",
                "packet": "503 5.5.1 Bad sequence of commands\r\n"
            }
        ],
        [
            {
                "type": "str",
                "packet": "503 5.5.1 Bad sequence of commands\r\n"
            }
        ]
    ]
}
获取服务器信息的Minecraft协议
{
    "clients": [
        [
            {
                "type": "hex",
                "packet": "1c00d4020e"
            },
            {
                "rand": 12
            },
            {
                "type": "str",
                "packet": ".org"
            },
            {
                "type": "hex",
                "packet": "00464d4c00276601"
            },
            {
                "type": "hex",
                "delay": 10,
                "packet": "0100"
            }
        ]
    ],
    "servers": [
        [
            {
                "type": "hex",
                "packet": "0300"
            },
            {
                "type": "str",
                "packet": "{}"
            }
        ]
    ]
}

自定义头部(UDP)(header-custom

UDP的“自定义头部”相比TCP的同名伪装层简单得多,它没有“对话轮次”,仅仅是为实际数据加入头部,远端将会剔除头部以得到实际数据。

以下配置模仿了1个“查询example.comA记录”的DNS请求与响应。

[!tip] 提示
不必使用此方式将流量伪装为DNS协议,header-dns伪装层能够更加便携地实现类似行为,XDNS伪装层则能够使用合法DNS查询传输数据。

{
    "finalmask": {
        "udp": [
            {
                "type": "header-custom",
                "settings": {
                    "client": [
                        {
                            "rand": 2
                        },
                        {
                            "type": "hex",
                            "packet": "01000001000000000000"
                        },
                        {
                            "type": "hex",
                            "packet": "036578616d706c6503636f6d0000010001"
                        }
                    ],
                    "server": [
                        {
                            "rand": 2
                        },
                        {
                            "type": "hex",
                            "packet": "81800001000100000000"
                        },
                        {
                            "type": "hex",
                            "packet": "036578616d706c6503636f6d0000010001c00c000100010000003b0004"
                        }
                    ]
                }
            }
        ]
    }
}

分片(TCP)(fragment

先前属于“Freedom”出站的“分片”功能被迁移至此最终伪装层,具体配置与先前基本相同,仅interval字段更名为delay

此更改使分片的配置更加直观,以v2rayN中的“启用分片”选项为例,它指定TLS协议的ClientHello部分以分片的多个TCP数据包发送,试图规避SNI黑名单。先前需要创建1个拥有分片相关配置的“Freedom”出站,并于实际的代理服务器出站中 指定dialerProxy字段为此“Freedom”出站;更改后,只需于代理服务器出站中增加此伪装层,便可达到目的呀。

{
    "finalmask": {
        "tcp": [
            {
                "type": "fragment",
                "settings": {
                    "packets": "tlshello",
                    "length": "100-200",
                    "delay": "10-20"
                }
            }
        ]
    }
}

噪音(UDP)(noise

此伪装层同样迁移自“Freedom”出站,它针对UDP协议,于UDP联协前发送自定义的噪音数据,以防止流量特征被探测,达到“流量整形”之目的。移动至此同样能够简化先前的某些配置。

新增的reset字段允许指定时间或范围时间(单位:秒),它意味着“于指定时间或范围内随机时间后,允许为先前已被发送噪音的主机 再次发送噪音”,以增强“流量整形”的效果。

{
    "finalmask": {
        "udp": [
            {
                "type": "noise",
                "settings": {
                    "reset": "300-600",
                    "noise": [
                        {
                            "type": "rand",
                            "packet": "50-100"
                        },
                        {
                            "type": "str",
                            "packet": "hello",
                            "delay": 50
                        },
                        {
                            "type": "base64",
                            "packet": "U29tZURhdGE="
                        }
                    ]
                }
            }
        ]
    }
}

Hysteria2入站与更新

Xray-core于26.3.27版本完善了对Hysteria2的支持,增加Hysteria2入站。建立Hysteria2服务器无需再依赖SIng-box等应用。顺带一提,配合使用“最终伪装层”,能够实现相比Sing-box更多的伪装类型,甚至“使用DNS协议传输”等极端需求。

配置

与通常的Hysteria2服务器相同,Hysteria2入站需要1个TLS证书。可以选择使用Let’s Encrypt签发证书,此处为便于演示,便使用自签发证书啦[2]

以下命令将为example.com签发1个持续15年的证书:

> xray tls cert --domain=example.com --name="Hysteria2 Test" --file=cert --expire=131400h

工作目录下将出现2个文件,分别为证书(cert.crt)与其私钥(cert.key)。

[!tip] 提示
以下命令能够计算证书的SHA256散列值,主要用于出站的pinnedPeerCertSha256字段:

> xray tls hash --cert .\cert.crt
Leaf SHA256:  4021f655324d5dbf191cc19408dc2db82f9b72363147c5ad51c0c0b97a206a25

示例配置:

{
    "log": {
        "loglevel": "info"
    },
    "inbounds": [
        {
            "tag": "hysteria",
            "listen": "::",
            "port": 443,
            "protocol": "hysteria",
            "settings": {
                "version": 2,
                "clients": [
                    {
                        "auth": "用于验证的UUID"
                    }
                ]
            },
            "streamSettings": {
                "network": "hysteria",
                "hysteriaSettings": {
                    "version": 2
                },
                "security": "tls",
                "tlsSettings": {
                    "alpn": [
                        "h3"
                    ],
                    "certificates": [
                        {
                            "certificateFile": "cert.crt",
                            "keyFile": "cert.key"
                        }
                    ]
                },
                "finalmask": {}
            }
        }
    ],
    "outbounds": [
        {
            "tag": "freedom",
            "protocol": "freedom"
        },
        {
            "tag": "blackhole",
            "protocol": "blackhole"
        }
    ]
}

由于目前仅支持Hysteria2,上述配置中的version字段仅允许为2;因为Hysteria2修改自QUIC协议,alpn数组仅允许为h3,与出站方面基本相同。

对于拥塞控制、“Brutal”拥塞控制配置和端口跳跃等功能,请查看“QUIC参数”部分呀。

QUIC参数

Xray-core于26.3.27版本增加了streamSettingsfinalmaskquicParams对象,以统一QUIC与Hysteria的各个配置,包含拥塞控制、“Brutal”拥塞控制相关配置与端口跳跃。基本上,此更改使得基于QUIC协议的传输方式均可使用以上功能,例如XHTTP(ALPN=HTTP/3)。

拥塞控制

通过congestion字段指定需要的拥塞控制:

{
    "streamSettings": {
        "finalmask": {
            "quicParams": {
                "congestion": "bbr"
            }
        }
    }
}

与修改前的配置相同,值应当为renocubicbbrbrutalforce-brutal之一。

[!attention] 注意
network字段不是hysteria,允许的选项将剔除brutal,因为其它传输方式没有Hysteria2传输方式的“带宽协商”过程。

“Brutal”拥塞控制

“Brutal”拥塞控制需要配置最大上传带宽与最大下载带宽,分别通过brutalUpbrutalDown指定:

{
    "quicParams": {
        "brutalUp": "1000mbps",
        "brutalDown": "1000mbps"
    }
}

同时存在以上字段且未明确指定congestion字段时,将使用brutal(使用Hysteria2传输方式时)或force-brutal,后者将忽略“带宽协商”的结果。

端口跳跃

与更改前的配置几乎相同,ports用于指定端口范围,interval用于指定切换端口的时间或时间范围(单位:秒)。

{
    "quicParams": {
        "udpHop": {
            "ports": "10000-60000",
            "interval": "10-60"
        }
    }
}

根据路由规则发送WebHook

Xray-core在26.3.27版本中为路由增加了WebHook功能,当收到符合路由规则的流量时,将向指定的URL发送POST请求。

此功能主要面向机场提供者,可用于“暂时封禁使用BitTorrent的用户”等审计功能呀。

配置

于路由规则中配置webhook对象便可:

{
    "type": "field",
    "protocol": [
        "bittorrent"
    ],
    "webhook": {
        "url": "https://api.example.com",
        "deduplication": 10,
        "headers": {
            "Authorization": "Bearer KEY"
        }
    }
}

deduplication字段将停止发送指定秒数内的相同事件。

以上路由规则将于嗅探到BitTorrent协议时,向api.example.com发送以下结构的WebHook事件:

{
    "email": "邮箱",                        // string | null
    "level": null,                       // number | null
    "protocol": "tls",                   // string | null
    "network": "tcp",                    // string
    "source": "tcp:127.0.0.1:54203",     // string | null
    "destination": "tcp:dns.google:443", // string
    "routeTarget": null,                 // string | null
    "originalTarget": "tcp:8.8.8.8:443",// string | null
    "inboundTag": "入站",           // string | null
    "inboundName": "vless",              // string | null
    "inboundLocal": "tcp:192.168.108.1:443", // string | null
    "outboundTag": "出站",  // string | null
    "ts": 1771886901                     // number
}


  1. 需要澄清的是,大多数所谓“0-RTT”的实现方式,客户端便是将实际数据于首个握手阶段便发送,此即“早期数据(Early Data)”。其目的便是减少握手导致的延迟,实际仍需要至少1次往返,毕竟,主机之间并没有心灵感应的能力。 ↩︎

  2. 若打算同样使用自签发证书,请于客户端指定tlsSettingspinnedPeerCertSha256字段为证书的散列值,以防止中间人攻击。 ↩︎

1 个赞