mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Respect explicit tunnel security off
This commit is contained in:
@@ -7,7 +7,7 @@ AETHER_TUNNEL_MANAGEMENT_TOKEN=ae_xxxxx
|
||||
# Node identification
|
||||
AETHER_TUNNEL_NODE_NAME=jp-proxy-01
|
||||
|
||||
# Secure non-TLS tunnel. http:// plus a key auto-enables non_tls_required.
|
||||
# Secure non-TLS tunnel. Set non_tls_required with a key to enable secure tunnel.
|
||||
AETHER_TUNNEL_SECURITY=off
|
||||
# AETHER_TUNNEL_ENCRYPTION_KEY=base64-32-bytes
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ sudo aether-tunnel uninstall
|
||||
| `--aether-url` | `AETHER_TUNNEL_AETHER_URL` | **必填** | Aether 服务器地址 |
|
||||
| `--management-token` | `AETHER_TUNNEL_MANAGEMENT_TOKEN` | **必填** | 管理员 Token(`ae_xxx` 格式) |
|
||||
| `--node-name` | `AETHER_TUNNEL_NODE_NAME` | **必填** | 节点名称标识 |
|
||||
| `--tunnel-security` | `AETHER_TUNNEL_SECURITY` | `off` | Aether ↔ tunnel 通道安全模式;支持 `off` / `non_tls_required`;`http://` 且提供 key 时会自动按 `non_tls_required` 生效 |
|
||||
| `--tunnel-security` | `AETHER_TUNNEL_SECURITY` | `off` | Aether ↔ tunnel 通道安全模式;支持 `off` / `non_tls_required`;在 `[[servers]]` 中省略该字段且 `http://` 提供 key 时会自动按 `non_tls_required` 生效 |
|
||||
| `--tunnel-encryption-key` | `AETHER_TUNNEL_ENCRYPTION_KEY` | 空 | secure tunnel 使用的长期 PSK(base64 32-byte),每个 `[[servers]]` 节点独立配置 |
|
||||
| `--public-ip` | `AETHER_TUNNEL_PUBLIC_IP` | 自动检测 | 公网 IP |
|
||||
| `--node-region` | `AETHER_TUNNEL_NODE_REGION` | 自动检测 | 地区标识 |
|
||||
@@ -231,7 +231,7 @@ tunnel_encryption_key = "base64-32-bytes"
|
||||
|
||||
`tunnel_security = "non_tls_required"` 是非 TLS secure tunnel 的 MVP 配置面:它要求同时提供当前 `[[servers]]` 条目的 `tunnel_encryption_key`,后续握手使用 `node_name` / `X-Node-Id` 查找对应 PSK,不引入 `tunnel_encryption_key_id`。`wss://` 仍是推荐方案;`ws:// + secure tunnel` 只保护 Aether ↔ tunnel 之间的 token 和 payload,不等价于 HTTPS 伪装,也不覆盖 tunnel ↔ origin/provider 这段链路。
|
||||
|
||||
如果 `aether_url` 使用 `http://` 且当前 `[[servers]]` 条目提供了 `tunnel_encryption_key`,即使省略或保留 `tunnel_security = "off"`,运行时也会自动按 `non_tls_required` 生效。secure tunnel 会在 WebSocket tunnel 上加密所有二进制 tunnel frame;未配置 key 的旧节点仍按原明文协议工作。
|
||||
如果 `aether_url` 使用 `http://` 且当前 `[[servers]]` 条目提供了 `tunnel_encryption_key`,省略 `tunnel_security` 时运行时会自动按 `non_tls_required` 生效;显式配置 `tunnel_security = "off"` 会关闭该自动推断。secure tunnel 会在 WebSocket tunnel 上加密所有二进制 tunnel frame;未配置 key 或显式关闭的旧节点仍按原明文协议工作。
|
||||
|
||||
## 发布新版本
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@ function Add-ServerConfig([string]$AetherUrl, [string]$ManagementToken, [string]
|
||||
$QuotedUrl = ConvertTo-TomlQuotedString $AetherUrl
|
||||
$QuotedToken = ConvertTo-TomlQuotedString $ManagementToken
|
||||
$QuotedName = ConvertTo-TomlQuotedString $NodeName
|
||||
$QuotedTunnelSecurity = ConvertTo-TomlQuotedString $TunnelSecurity
|
||||
$QuotedTunnelEncryptionKey = ConvertTo-TomlQuotedString $TunnelEncryptionKey
|
||||
|
||||
if (Test-ServerExists $script:ConfigPath $QuotedUrl $QuotedName) {
|
||||
@@ -134,9 +133,12 @@ function Add-ServerConfig([string]$AetherUrl, [string]$ManagementToken, [string]
|
||||
'[[servers]]',
|
||||
"aether_url = $QuotedUrl",
|
||||
"management_token = $QuotedToken",
|
||||
"node_name = $QuotedName",
|
||||
"tunnel_security = $QuotedTunnelSecurity"
|
||||
"node_name = $QuotedName"
|
||||
) -join "`n"
|
||||
if ($TunnelSecurity) {
|
||||
$QuotedTunnelSecurity = ConvertTo-TomlQuotedString $TunnelSecurity
|
||||
$Block += "`ntunnel_security = $QuotedTunnelSecurity"
|
||||
}
|
||||
if ($TunnelEncryptionKey) {
|
||||
$Block += "`ntunnel_encryption_key = $QuotedTunnelEncryptionKey"
|
||||
}
|
||||
@@ -149,9 +151,9 @@ function Main {
|
||||
$AetherUrl = Prompt-IfEmpty 'AETHER_TUNNEL_AETHER_URL' $env:AETHER_TUNNEL_AETHER_URL 'Aether URL'
|
||||
$ManagementToken = Prompt-IfEmpty 'AETHER_TUNNEL_MANAGEMENT_TOKEN' $env:AETHER_TUNNEL_MANAGEMENT_TOKEN 'Management token (ae_xxx)'
|
||||
$NodeName = Prompt-IfEmpty 'AETHER_TUNNEL_NODE_NAME' $env:AETHER_TUNNEL_NODE_NAME 'Node name'
|
||||
$TunnelSecurity = if ($env:AETHER_TUNNEL_SECURITY) { $env:AETHER_TUNNEL_SECURITY } else { 'off' }
|
||||
$TunnelSecurity = if ($env:AETHER_TUNNEL_SECURITY) { $env:AETHER_TUNNEL_SECURITY } else { '' }
|
||||
$TunnelEncryptionKey = if ($env:AETHER_TUNNEL_ENCRYPTION_KEY) { $env:AETHER_TUNNEL_ENCRYPTION_KEY } else { '' }
|
||||
if ($TunnelSecurity -notin @('off', 'non_tls_required')) {
|
||||
if ($TunnelSecurity -and ($TunnelSecurity -notin @('off', 'non_tls_required'))) {
|
||||
Fail 'AETHER_TUNNEL_SECURITY must be off or non_tls_required'
|
||||
}
|
||||
if (($TunnelSecurity -eq 'non_tls_required') -and -not $TunnelEncryptionKey) {
|
||||
|
||||
@@ -193,8 +193,10 @@ append_server_config() {
|
||||
quoted_url=$(toml_quote "$aether_url")
|
||||
quoted_token=$(toml_quote "$management_token")
|
||||
quoted_name=$(toml_quote "$node_name")
|
||||
quoted_security=$(toml_quote "$tunnel_security")
|
||||
quoted_encryption_key=$(toml_quote "$tunnel_encryption_key")
|
||||
if [ -n "$tunnel_security" ]; then
|
||||
quoted_security=$(toml_quote "$tunnel_security")
|
||||
fi
|
||||
|
||||
if has_legacy_single_server_keys; then
|
||||
fail "现有配置仍使用旧的顶层 aether_url/management_token,请先运行 aether-tunnel setup 迁移为 [[servers]] 后重试:$CONFIG_PATH"
|
||||
@@ -218,7 +220,9 @@ append_server_config() {
|
||||
printf 'aether_url = %s\n' "$quoted_url"
|
||||
printf 'management_token = %s\n' "$quoted_token"
|
||||
printf 'node_name = %s\n' "$quoted_name"
|
||||
printf 'tunnel_security = %s\n' "$quoted_security"
|
||||
if [ -n "$tunnel_security" ]; then
|
||||
printf 'tunnel_security = %s\n' "$quoted_security"
|
||||
fi
|
||||
if [ -n "$tunnel_encryption_key" ]; then
|
||||
printf 'tunnel_encryption_key = %s\n' "$quoted_encryption_key"
|
||||
fi
|
||||
@@ -235,10 +239,10 @@ main() {
|
||||
aether_url=$(prompt_if_empty AETHER_TUNNEL_AETHER_URL "${AETHER_TUNNEL_AETHER_URL:-}" "Aether URL: ")
|
||||
management_token=$(prompt_if_empty AETHER_TUNNEL_MANAGEMENT_TOKEN "${AETHER_TUNNEL_MANAGEMENT_TOKEN:-}" "Management token (ae_xxx): ")
|
||||
node_name=$(prompt_if_empty AETHER_TUNNEL_NODE_NAME "${AETHER_TUNNEL_NODE_NAME:-}" "Node name: ")
|
||||
tunnel_security="${AETHER_TUNNEL_SECURITY:-off}"
|
||||
tunnel_security="${AETHER_TUNNEL_SECURITY:-}"
|
||||
tunnel_encryption_key="${AETHER_TUNNEL_ENCRYPTION_KEY:-}"
|
||||
case "$tunnel_security" in
|
||||
off|non_tls_required) ;;
|
||||
""|off|non_tls_required) ;;
|
||||
*) fail "AETHER_TUNNEL_SECURITY 必须是 off 或 non_tls_required" ;;
|
||||
esac
|
||||
if [ "$tunnel_security" = "non_tls_required" ] && [ -z "$tunnel_encryption_key" ]; then
|
||||
|
||||
@@ -289,8 +289,10 @@ pub fn effective_tunnel_security(
|
||||
configured: Option<TunnelSecurity>,
|
||||
tunnel_encryption_key: Option<&str>,
|
||||
) -> TunnelSecurity {
|
||||
if configured == Some(TunnelSecurity::NonTlsRequired) {
|
||||
return TunnelSecurity::NonTlsRequired;
|
||||
match configured {
|
||||
Some(TunnelSecurity::NonTlsRequired) => return TunnelSecurity::NonTlsRequired,
|
||||
Some(TunnelSecurity::Off) => return TunnelSecurity::Off,
|
||||
None => {}
|
||||
}
|
||||
if aether_url.trim_start().starts_with("http://")
|
||||
&& tunnel_encryption_key
|
||||
@@ -738,12 +740,7 @@ impl Config {
|
||||
if self.node_name.trim().is_empty() {
|
||||
anyhow::bail!("node_name must not be empty");
|
||||
}
|
||||
let effective_security = effective_tunnel_security(
|
||||
&self.aether_url,
|
||||
Some(self.tunnel_security),
|
||||
self.tunnel_encryption_key.as_deref(),
|
||||
);
|
||||
if effective_security == TunnelSecurity::NonTlsRequired {
|
||||
if self.tunnel_security == TunnelSecurity::NonTlsRequired {
|
||||
let Some(key) = normalized_proxy_url(&self.tunnel_encryption_key) else {
|
||||
anyhow::bail!(
|
||||
"tunnel_encryption_key must be set when tunnel_security=non_tls_required"
|
||||
@@ -1796,14 +1793,22 @@ node_name = "tunnel-test"
|
||||
assert_eq!(
|
||||
effective_tunnel_security(
|
||||
&config.aether_url,
|
||||
Some(config.tunnel_security),
|
||||
None,
|
||||
config.tunnel_encryption_key.as_deref(),
|
||||
),
|
||||
TunnelSecurity::NonTlsRequired
|
||||
);
|
||||
assert_eq!(
|
||||
effective_tunnel_security(
|
||||
&config.aether_url,
|
||||
Some(TunnelSecurity::Off),
|
||||
config.tunnel_encryption_key.as_deref(),
|
||||
),
|
||||
TunnelSecurity::Off
|
||||
);
|
||||
config
|
||||
.validate()
|
||||
.expect("http URL with PSK should infer secure tunnel mode");
|
||||
.expect("http URL with PSK should validate when tunnel_security is off");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1816,6 +1821,8 @@ node_name = "tunnel-test"
|
||||
"ae_test",
|
||||
"--node-name",
|
||||
"tunnel-test",
|
||||
"--tunnel-security",
|
||||
"non_tls_required",
|
||||
"--tunnel-encryption-key",
|
||||
"not-a-valid-32-byte-key",
|
||||
]);
|
||||
|
||||
@@ -96,10 +96,10 @@ impl ServerTab {
|
||||
Field {
|
||||
label: "Tunnel Security",
|
||||
key: "tunnel_security",
|
||||
value: "off".into(),
|
||||
value: String::new(),
|
||||
kind: FieldKind::Text,
|
||||
required: false,
|
||||
help: "off or non_tls_required; http:// plus a key auto-enables secure tunnel",
|
||||
help: "off or non_tls_required; omit to auto-enable for http:// plus a key",
|
||||
},
|
||||
Field {
|
||||
label: "Tunnel Encryption Key",
|
||||
@@ -1180,6 +1180,15 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_config_omits_blank_tunnel_security_for_auto_inference() {
|
||||
let app = sample_app();
|
||||
|
||||
let cfg = app.to_config().expect("config should serialize");
|
||||
assert_eq!(cfg.servers.len(), 1);
|
||||
assert_eq!(cfg.servers[0].tunnel_security, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_config_rejects_non_tls_security_without_key() {
|
||||
let mut app = sample_app();
|
||||
|
||||
Reference in New Issue
Block a user