协议与传输层
每个 katana 节点运行一个监听器,它使用什么协议由两方面决定。[node.api] 中的 node_type 选定协议族;其余部分由面板对 katana 节点信息请求的应答补全:端口、传输层、是否启用 TLS,以及 Shadowsocks 加密方式等协议细节。katana 根据这份应答构建监听器;如果应答要求的功能 katana 没有实现,就拒绝构建。
当你在面板中配置节点,想知道 katana 会遵循哪些设置时,或者节点无法启动、日志显示 node requests kernel-unsupported feature 时,请阅读本页。面板 API 本身见各面板页面(Xboard 与 V2board、SSPanel)。
node_type |
协议 | 传输层 | TLS | UDP 中继 | 多路复用 | 面板 |
|---|---|---|---|---|---|---|
V2ray |
VMess,仅 AEAD(alter_id 为 0) |
TCP、WebSocket、gRPC | 可选 | 支持 | mux.cool 和 XUDP | UniProxy、SSPanel |
V2ray 且 enable_vless = true |
VLESS,不支持 flow |
TCP、WebSocket、gRPC | 可选 | 支持 | mux.cool 和 XUDP | UniProxy、SSPanel |
Trojan |
Trojan,密码为用户的 UUID | UniProxy:TCP。SSPanel:TCP、WebSocket、gRPC | 始终启用 | 支持 | mux.cool 和 XUDP | UniProxy、SSPanel |
Shadowsocks |
AEAD(SIP004)或 2022 多用户(SIP022) | TCP | 从不启用 | 不支持 | 不支持 | 仅 UniProxy |
Hysteria2 |
Hysteria 2 | 基于 UDP 的 QUIC | 始终启用,在 QUIC 内部 | [node.hysteria].udp = true 时支持 |
不适用 | UniProxy、SSPanel(custom_config)或本地设置 |
“UniProxy”指 Xboard 和 V2board 提供的 newV2board API(panel_type = "NewV2board",或其别名 "V2board")。Hysteria 2 有单独的页面 Hysteria 2 节点;本页其余部分讨论四种基于流的协议。
katana 如何构建节点
Section titled “katana 如何构建节点”katana 在绑定端口之前先检查所有可能失败的环节,因此被拒绝的节点不会启动到一半:
flowchart TB P["面板节点信息"] --> N["按节点类型解析"] N -->|"Shadowsocks obfs、SSPanel Shadowsocks"| E1["node_info failed"] N --> T["构建传输层:TCP、WebSocket、gRPC、TLS"] T -->|"REALITY、ACME、缺少证书、未知传输层"| E2["initial start failed"] T --> R["构建协议用户表"] R -->|"XTLS flow、未知加密方式"| E2 R --> B["绑定 TCP 端口并提供服务"]
证书在构建传输层这一步读取,因此缺少证书的 TLS 节点在检查协议设置之前就会被拒绝。
选择节点类型
Section titled “选择节点类型”node_type 在 katana 的配置文件中设置,而不是在面板中。取值不区分大小写:
| 写法 | 节点类型 | 说明 |
|---|---|---|
V2ray、vmess、vless |
V2ray | 提供 VMess;enable_vless = true 时提供 VLESS。 |
Trojan |
Trojan | |
Shadowsocks |
Shadowsocks | 仅限 UniProxy 面板。 |
Hysteria2、hysteria、hy2 |
Hysteria 2 | 见 Hysteria 2 节点。katana 会把 hy2 原样发给 UniProxy 面板,而 Xboard 不接受这个类型,所以在 Xboard 上请写 Hysteria2。 |
其他任何值(包括空值)都会被拒绝。katana --test 输出:
configuration error: unknown node_type "Socks"启动时 katana 会记录 node 1: unknown node_type "Socks" 并跳过该节点,其他节点照常启动。
如果热重载的文件中含有这样的节点,整次重载都会被拒绝:katana 不会应用新文件中的任何内容,所有节点保持原样运行。日志会用面板、主机、ID 标明该节点,在 UniProxy 面板上还会带上所请求的类型:
reload: node newv2board@https://panel.example.com#1/socks: unknown node_type "Socks"; keeping current config启动时被跳过的节点只要还留在文件中,情况也一样:在修正该节点的 node_type 之前,对文件的任何修改都不会生效。
UniProxy 面板上的一个 VLESS 节点如下:
[[node]]panel_type = "NewV2board"
[node.api]host = "https://panel.example.com"node_id = 1key = "replace-with-the-panel-key"node_type = "V2ray"enable_vless = true
[node.controller.cert]mode = "file"cert_file = "/etc/katana/fullchain.pem"key_file = "/etc/katana/privkey.pem"在 UniProxy 面板上,节点类型还会出现在每个请求中:对于 enable_vless = true 的 V2ray 节点,katana 发送 node_type=vless,否则发送小写的 node_type。Xboard 通过节点 ID 和这个类型来查找节点,因此同一个 node_id 以 vless 和以 v2ray 请求时,指向的是面板中两个不同的节点。因此,改变 katana 所请求类型的修改(例如为 V2ray 节点打开 enable_vless)会在热重载时重启该节点,流量计数从零开始;见节点身份与热重载。
面板的 network 值决定传输层。katana 在匹配前会先将其转为小写:
面板 network |
传输层 | 行为 |
|---|---|---|
空、tcp、raw |
TCP | 协议直接运行在 TCP 连接上,或运行在其上的 TLS 之上。 |
ws、websocket |
WebSocket | 只在配置的路径上接受升级请求。空路径即 /;不以 / 开头的路径会自动补上;?ed= 查询参数会被去掉,因为它用于配置 early data,而 katana 通过 Sec-WebSocket-Protocol 接收 early data(最多 16 KiB,超出时以 HTTP 413 应答)。面板给出 host 时,请求的 Host 头必须与之匹配(不区分大小写,忽略端口)。路径或 host 不符时以 HTTP 404 应答。 |
grpc、gun |
gRPC | 在 /<serviceName>/Tun 上提供 gun 隧道,在 /<serviceName>/TunMulti 上提供 multi-hunk 隧道,service name 严格按面板给出的值使用。其他路径上的 stream 会被重置。每个 HTTP/2 stream 是一条被代理的连接,因此一条 TCP 连接可以承载多条。 |
httpupgrade |
拒绝 | node requests kernel-unsupported feature: httpupgrade transport |
splithttp、xhttp |
拒绝 | node requests kernel-unsupported feature: splithttp transport |
| 其他任何值 | 拒绝 | node requests kernel-unsupported feature: transport "quic",其中给出实际的值 |
只有 V2ray 节点和 SSPanel 的 Trojan 节点读取 network。UniProxy 的 Trojan 节点始终使用 TCP,Shadowsocks 节点也始终使用 TCP。
节点是否使用 TLS 取决于其类型;对于 V2ray,还取决于面板:
| 节点类型 | TLS |
|---|---|
| V2ray | 由面板决定是否启用:UniProxy 的 tls = 1,SSPanel 的 security = "tls" 或 "xtls",或 SSPanel 旧式字符串中的 tls。 |
| Trojan | 始终启用,无论面板如何设置。 |
| Shadowsocks | 从不启用。 |
| Hysteria 2 | 始终启用;TLS 握手是 QUIC 的一部分。 |
证书从不来自面板。katana 从 [node.controller.cert] 读取证书,面板的 tls_settings、server_name 等字段都不会被使用:
| 键 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
mode | string (enum) | 视情况 | "none" | "none"(不用证书)或 "file"(读取 cert_file 和 key_file),区分大小写。所有使用 TLS 的节点都必须用 "file";否则流式节点报 TLS node requires cert.mode = "file",Hysteria 2 节点报 hysteria2 node requires cert.mode = "file"。ACME 模式 "dns"、"http"、"tls" 在任何流式节点上都会被拒绝,不论它是否用 TLS:node requests kernel-unsupported feature: ACME cert mode "dns";在 Hysteria 2 节点上,它们和其他不是 "file" 的值一样报错。在流式节点上,其他值的效果与 "none" 相同。 |
cert_file | path | 视情况 | "" | PEM 格式的证书链:服务器证书在前,中间证书在后(即 fullchain.pem)。mode = "file" 时必填;它或 key_file 为空时,使用 TLS 的节点或 Hysteria 2 节点报 TLS node requires cert.cert_file and cert.key_file。每次构建监听器时读取,文件变化本身不会触发读取。文件不存在时只报操作系统的错误,例如 No such file or directory (os error 2),错误里不含路径。 |
key_file | path | 视情况 | "" | 与 cert_file 配对的 PEM 私钥。mode = "file" 时必填。读取时机与 cert_file 相同;私钥与证书不匹配时,监听器构建失败。 |
reject_unknown_sni | bool | 否 | false | 没有实现,所以写 true 会被拒绝,而不是悄悄忽略:节点报 node requests kernel-unsupported feature: cert.reject_unknown_sni。请保持 false。 |
TLS 服务端的细节:
- 版本: TLS 1.2 和 1.3,更早的版本会被拒绝。
- 证书:
cert_file中的第一张证书作为服务端证书,其余证书作为证书链发送。 - ALPN: gRPC 节点选择
h2,这正是 HTTP/2 客户端所提供的。TCP 和 WebSocket 节点不配置 ALPN,因此会接受客户端的 ALPN 列表,但不选定任何协议。 - SNI: 不检查。任何 server name 都会得到同一张证书。如上表所述,
reject_unknown_sni = true会被拒绝。
katana 从各面板读取的内容
Section titled “katana 从各面板读取的内容”只有下列字段会影响流式节点的监听器(Hysteria 2 的字段见 Hysteria 2 节点页面)。面板应答中的其他字段一律忽略,包括 Xboard 的 tls_settings、multiplex、decryption、plugin 和 plugin_opts,因此只存在于这些字段中的设置对 katana 节点没有任何作用。
| 字段 | 节点类型 | 用途 |
|---|---|---|
server_port |
全部 | 监听端口。为 0 或缺失时报错 newV2board: server port must be > 0。 |
network |
V2ray | 传输层,取值见上表。 |
networkSettings |
V2ray,VMess | path(WebSocket)、headers.Host(WebSocket host 检查)、serviceName(gRPC)、header(TCP,忽略)。 |
network_settings |
V2ray,VLESS | 字段相同;enable_vless = true 时读取它,而不是 networkSettings。 |
tls |
V2ray | 0 或缺失:不启用 TLS。1:TLS。2:REALITY,拒绝。 |
flow |
V2ray | 必须为空。任何值都会作为 XTLS flow 被拒绝。 |
cipher |
Shadowsocks | 加密方式,取值见下方 Shadowsocks 表格。 |
server_key |
Shadowsocks | 2022 加密方式的服务端 PSK,base64 编码。 |
obfs |
Shadowsocks | 空、plain 或 none(必须完全一致,小写)。其他值都会被拒绝。 |
Trojan 节点在这里只读取 server_port,并以 TCP 加 TLS 提供服务。
当面板报告的版本为 2021.11 或更高,且 [node.api].disable_custom_config 为 false 时,katana 读取 custom_config;否则读取旧式 server 字符串。如果 katana 应当读取 custom_config 但面板没有发送,节点会报错 custom_config is empty, disable custom config。
custom_config 字段 |
节点类型 | 用途 |
|---|---|---|
offset_port_node |
全部 | 监听端口,以 JSON 字符串表示,例如 "443"。 |
network |
V2ray、Trojan | 传输层。对 Trojan 来说,空值表示 TCP。 |
security |
V2ray | tls 或 xtls 会启用 TLS。Trojan 忽略此字段,因为它始终使用 TLS。 |
path、host |
V2ray、Trojan | WebSocket 路径和 host 检查。 |
servicename |
V2ray、Trojan | gRPC service name。 |
enable_vless |
V2ray | 字符串 "1" 表示提供 VLESS。它和 [node.api].enable_vless 任设其一即可。 |
flow |
V2ray、Trojan | 必须为空。任何值都会作为 XTLS flow 被拒绝。 |
enable_reality |
V2ray、Trojan | JSON 布尔值。true 会作为 REALITY 被拒绝。 |
header |
V2ray | TCP header,忽略。 |
V2ray 节点的旧式字符串以 ; 分隔:地址、端口、alter ID(忽略),然后是 network 和 tls(顺序不限),最后是以 | 分隔的 key=value 附加项(path、host、servicename、headerType)。少于六段的字符串会报错 malformed legacy v2ray server string。旧式字符串中没有 VLESS 或 flow 字段,因此对于旧式节点,katana 从 [node.api](enable_vless 和 vless_flow)读取这两项,非空的 vless_flow 会导致节点被拒绝。
192.0.2.10;443;0;ws;tls;path=/ws|host=proxy.example.com对于 Trojan 节点,katana 从 port= 中取端口:port=443#8443 取 # 之后的端口(8443),port=443 则取 443。传输层默认为 TCP;如果第一个 ; 之后以 | 分隔的附加项中含有 grpc 键(无论其值为何),则改用 gRPC,并以 servicename 作为 service name:
proxy.example.com;port=443#8443|host=proxy.example.com|grpc=1|servicename=tunnelSSPanel 上的 Shadowsocks 节点会被拒绝,报错 sspanel: Shadowsocks node type is not supported。
未设置 enable_vless 的 V2ray 节点提供 VMess。
- 仅支持 AEAD 头部。 未实现与大于
0的alterId配套的旧式 MD5 头部。katana 为每个用户设置的 alter ID 都是0,并忽略 SSPanel 旧式字符串中的值,因此客户端必须使用alterId: 0。 - 数据加密:
aes-128-gcm或chacha20-poly1305。设为auto的客户端会从中选择其一。不接受none和zero,连接会在握手阶段被关闭。 - 时钟: VMess 头部带有时间戳,katana 只接受与自身时钟相差 120 秒以内的时间戳。请保持服务器时钟同步。
- 用户: 账户 ID 即用户的 UUID。UUID 无法解析的用户会被跳过,并记录
skipping user 7: uuid is not a valid UUID,其他用户照常提供服务。 - 命令: TCP、UDP 和 mux(见多路复用)。
Etemenanki 的 VMess 页面更详细地介绍了协议实现。
设置了 enable_vless = true,或在 SSPanel 的 custom_config 中设置了 enable_vless = "1" 的 V2ray 节点提供 VLESS。
- 不支持 flow。 未实现
xtls-rprx-vision等 XTLS flow。面板的flow(SSPanel 发送旧式字符串时则为[node.api].vless_flow)会使整个节点被拒绝,报错node requests kernel-unsupported feature: VLESS XTLS flow。如果客户端仍然发送 flow,会握手失败。 - 加密: 客户端必须使用
encryption: "none"。 - 用户: ID 即用户的 UUID。与 VMess 相同,UUID 无法解析的用户会被跳过。
- 命令: TCP、UDP 和 mux。
协议实现见 VLESS。
Trojan
Section titled “Trojan”- 密码: 面板中用户的 UUID,与面板列出的完全一致。这是 XrayR 的约定,也是 Xboard 下发给 Trojan 客户端的密码。
- TLS: 始终启用,因此 Trojan 节点需要配置
mode = "file"的[node.controller.cert]。 - 传输层: UniProxy 面板上为 TCP;SSPanel 上为 TCP、WebSocket 或 gRPC。
- UDP: 通过 Trojan 的 UDP associate 命令提供。
- Mux: 客户端通过连接
v1.mux.cool来表示使用 mux.cool,katana 会把这条连接当作 mux 载体。
协议实现见 Trojan。
Shadowsocks
Section titled “Shadowsocks”Shadowsocks 节点仅在 UniProxy 面板上可用,并且只支持 TCP:katana 不会为它绑定 UDP socket,因此客户端的 UDP 中继无法通过 katana 的 Shadowsocks 节点工作。
面板的 cipher 决定使用哪一代 Shadowsocks:
cipher |
类别 | 用户密钥 |
|---|---|---|
aes-128-gcm、aes-256-gcm |
AEAD(SIP004) | 用户的 UUID,作为密码 |
chacha20-ietf-poly1305(也可写作 chacha20-poly1305) |
AEAD(SIP004) | 用户的 UUID,作为密码 |
xchacha20-ietf-poly1305(也可写作 xchacha20-poly1305) |
AEAD(SIP004) | 用户的 UUID,作为密码 |
2022-blake3-aes-128-gcm |
2022 多用户(SIP022) | UUID 的前 16 个字符 |
2022-blake3-aes-256-gcm |
2022 多用户(SIP022) | UUID 的前 32 个字符 |
2022-blake3-chacha20-poly1305 |
拒绝 | 2022 规范只为 AES 加密方式定义了多用户 |
| 其他任何值 | 拒绝 | node requests kernel-unsupported feature: shadowsocks cipher "rc4-md5" |
AEAD 名称匹配时不区分大小写,并接受 aead_aes_128_gcm、aead_aes_256_gcm 和 aead_chacha20_poly1305 作为别名。2022 名称必须与上表完全一致,且为小写。
Shadowsocks 2022 密钥
Section titled “Shadowsocks 2022 密钥”2022 节点始终以多用户模式运行,所有用户共用一个端口。每条客户端连接都带有一个身份头,告诉 katana 它属于哪个用户。这里涉及两个密钥:
- 服务端密钥即面板的
server_key,是 base64 编码的 PSK,2022-blake3-aes-128-gcm为 16 字节,2022-blake3-aes-256-gcm为 32 字节。更长的密钥会被折叠到该长度;更短的会报错shadowsocks-2022: PSK too short (0 < 32),无效的 base64 会报decode PSK:错误。 - 用户密钥是用户 UUID 字符串的前 16 或 32 个字符,按原始字节使用。
Xboard 构建客户端密码时使用的是同样的派生方式:base64(UUID 的前 N 个字符),再用冒号与服务端密钥拼接。以 2022-blake3-aes-128-gcm 节点上的 UUID 11111111-2222-3333-4444-555555555555 为例:
user key bytes: 11111111-2222-33client password: <server_key>:MTExMTExMTEtMjIyMi0zMw==这些都不需要在 katana 中配置,只要与面板保持一致即可,而 katana 与 Xboard 是一致的。
katana 接受的 obfs 值为空、plain 和 none。其他任何值都会在 katana 读取节点信息时被拒绝,早于任何构建步骤:
node 1: node_info failed: newV2board: shadowsocks obfs "http" is not supportedkatana 不读取 plugin 或 plugin_opts。面板中配置的 SIP003 插件不会生效,使用该插件的客户端无法连接。
协议实现见 Shadowsocks。
VMess、VLESS 和 Trojan 节点接受来自 Xray 兼容客户端的 mux.cool 连接。无需任何设置来开启:katana 会在每条连接上识别 mux 命令(VMess 和 VLESS)或 v1.mux.cool 目标地址(Trojan)。
- mux 载体中的每条子连接都是一个独立的流:它会像单独的连接一样,针对已认证的用户进行路由、审计、速率限制和计量。
- 支持 UDP 子连接,包括每个数据包各自携带地址的 XUDP。
- 一个载体同时最多容纳 256 条子连接。客户端再打开一条时,只有这一条子连接被拒绝,载体及其其他子连接继续工作。
- 只实现了 mux.cool。sing-box 多路复用(Xboard 的
multiplex设置)既不读取,也不支持。
katana 采用 fail closed(出错即拒绝):当面板要求它无法提供的功能时,节点不会启动,而不是在缺少客户端所期望功能的情况下启动。下表列出所有拒绝情形以及 katana 记录的消息:
| 功能 | 来源 | 错误 |
|---|---|---|
| REALITY | UniProxy tls = 2,SSPanel enable_reality = true |
node requests kernel-unsupported feature: REALITY |
| XTLS flow | 面板 flow;SSPanel 旧式字符串对应 [node.api].vless_flow |
node requests kernel-unsupported feature: VLESS XTLS flow |
| HTTPUpgrade | network = "httpupgrade" |
node requests kernel-unsupported feature: httpupgrade transport |
| SplitHTTP、XHTTP | network = "splithttp" 或 "xhttp" |
node requests kernel-unsupported feature: splithttp transport |
| 其他传输层 | quic、kcp、h2 等 network 值 |
node requests kernel-unsupported feature: transport "quic" |
| PROXY protocol | 要求接受它的节点;在 katana 3.0.1 中没有面板字段会设置它 | node requests kernel-unsupported feature: PROXY protocol accept |
| ACME 证书 | [node.controller.cert].mode 为 dns、http 或 tls |
node requests kernel-unsupported feature: ACME cert mode "dns" |
| SNI 强制检查 | [node.controller.cert].reject_unknown_sni = true |
node requests kernel-unsupported feature: cert.reject_unknown_sni |
| 未知的 Shadowsocks 加密方式 | 面板 cipher |
node requests kernel-unsupported feature: shadowsocks cipher "rc4-md5" |
| 2022 ChaCha20 多用户 | cipher = "2022-blake3-chacha20-poly1305" |
shadowsocks-2022: multi-user requires an aes-gcm method,没有密钥时为 PSK too short |
| Shadowsocks obfs | 面板 obfs 不是 plain 或 none |
newV2board: shadowsocks obfs "http" is not supported |
| SSPanel 上的 Shadowsocks | node_type = "Shadowsocks" 且 panel_type = "SSPanel" |
sspanel: Shadowsocks node type is not supported |
| 无文件证书的 TLS | TLS 节点的 mode 不是 "file",包括默认值 "none" |
TLS node requires cert.mode = "file" |
| 无路径的 TLS | mode = "file" 但 cert_file 或 key_file 为空 |
TLS node requires cert.cert_file and cert.key_file |
节点被拒绝时
Section titled “节点被拒绝时”这些设置大多来自面板,所以 katana --test 看不到它们:它检查配置文件,构建出站、面板客户端和路由器,并验证 [node.hysteria],但不会联系面板。一个 REALITY 节点的配置能通过 --test,却会在启动时失败。
错误会连同节点 ID 出现在日志中。构建监听器时发现的拒绝如下:
ERROR katana::manager::node: node 1: initial start failed: node requests kernel-unsupported feature: REALITY; retrying in 1s解析面板应答时发现的拒绝(例如 Shadowsocks 的 obfs)在启动时记录为 node 1: node_info failed: 加上错误消息,以及同样的 ; retrying in 提示。如果是在之后的轮询中出现,katana 会记录一条警告(node 1: node_info:),并继续使用已有的设置提供服务。同一文件中的其他节点不受影响。
尚未启动成功的节点会持续重试。第一次尝试失败后 katana 等待 1 秒,此后每失败一次等待时间翻倍,最长 60 秒;如果 update_periodic 更短,则以 update_periodic 为上限。每次尝试都会重新从面板读取节点信息和用户列表,因此在面板中修正节点后,它会在下一次尝试时启动,无需重启 katana。在配置文件中保存对该节点 [[node]] 表的修改,会立即触发下一次尝试。
如果运行中节点的设置在面板中被改成了会被拒绝的内容,该节点会失去监听器,并记录 node 1: rebuild failed: 加上原因。它会在每次轮询时重试,因此面板修正后节点就会恢复。其他启动错误见故障排查。
测试过的客户端
Section titled “测试过的客户端”katana 的集成测试用真实的 katana 二进制对接一个模拟面板,并使用独立的客户端实现进行连接。每个测试都会经节点发送一段数据并校验回显的字节。Xray 测试还会检查面板是否收到了该用户的流量上报。
| 客户端 | 协议 | 传输层 | TLS | Mux |
|---|---|---|---|---|
| Xray-core | VMess | TCP、WebSocket、gRPC | 否 | 仅 TCP |
| Xray-core | VMess | TCP | 是 | 否 |
| Xray-core | VLESS | WebSocket | 是 | 是 |
| Xray-core | VLESS | gRPC | 是 | 否 |
| Xray-core | Trojan | TCP | 是 | 是 |
| Hysteria 2 官方客户端 | Hysteria 2 | QUIC | 是 | 不适用 |
Xray 客户端使用 VMess security auto 和 VLESS encryption none,并通过固定证书哈希来验证 katana 的证书。Xray mux 测试的并发数为 8。Hysteria 2 客户端仅凭用户的 UUID 认证,跳过证书验证,并在一条连接上打开两个 stream;它的节点从 [node.hysteria] 而不是面板获取端口。
katana 中没有任何测试用外部客户端驱动 Shadowsocks 节点。