mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
fix: harden tunnel security and timeout handling
This commit is contained in:
@@ -9,11 +9,12 @@ use uuid::Uuid;
|
||||
use super::types::{
|
||||
bucket_start_unix_secs, build_tunnel_error_event_detail, build_tunnel_metrics_sample,
|
||||
log_reported_tunnel_error_event, normalize_proxy_metadata,
|
||||
reconcile_remote_config_after_heartbeat, ProxyNodeEventQuery, ProxyNodeHeartbeatMutation,
|
||||
ProxyNodeManualCreateMutation, ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary,
|
||||
ProxyNodeMetricsStep, ProxyNodeReadRepository, ProxyNodeRegistrationMutation,
|
||||
ProxyNodeRemoteConfigMutation, ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation,
|
||||
ProxyNodeWriteRepository, StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
preserve_proxy_metadata_tunnel_security, reconcile_remote_config_after_heartbeat,
|
||||
ProxyNodeEventQuery, ProxyNodeHeartbeatMutation, ProxyNodeManualCreateMutation,
|
||||
ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary, ProxyNodeMetricsStep,
|
||||
ProxyNodeReadRepository, ProxyNodeRegistrationMutation, ProxyNodeRemoteConfigMutation,
|
||||
ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation, ProxyNodeWriteRepository,
|
||||
StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
StoredProxyNodeMetricsBucket, TunnelMetricsSample, PROXY_NODE_EVENT_TYPE_TUNNEL_ERROR,
|
||||
};
|
||||
use crate::DataLayerError;
|
||||
@@ -590,6 +591,10 @@ impl ProxyNodeWriteRepository for InMemoryProxyNodeRepository {
|
||||
mutation.proxy_metadata.as_ref(),
|
||||
mutation.proxy_version.as_deref(),
|
||||
);
|
||||
let normalized_proxy_metadata = preserve_proxy_metadata_tunnel_security(
|
||||
previous_proxy_metadata.as_ref(),
|
||||
normalized_proxy_metadata,
|
||||
);
|
||||
if let Some(value) = normalized_proxy_metadata {
|
||||
node.proxy_metadata = Some(value);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ use sqlx::{mysql::MySqlRow, Row};
|
||||
use super::types::{
|
||||
bucket_start_unix_secs, build_tunnel_error_event_detail, build_tunnel_metrics_sample,
|
||||
log_reported_tunnel_error_event, normalize_proxy_metadata,
|
||||
reconcile_remote_config_after_heartbeat, ProxyNodeEventQuery, ProxyNodeHeartbeatMutation,
|
||||
ProxyNodeManualCreateMutation, ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary,
|
||||
ProxyNodeMetricsStep, ProxyNodeReadRepository, ProxyNodeRegistrationMutation,
|
||||
ProxyNodeRemoteConfigMutation, ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation,
|
||||
ProxyNodeWriteRepository, StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
preserve_proxy_metadata_tunnel_security, reconcile_remote_config_after_heartbeat,
|
||||
ProxyNodeEventQuery, ProxyNodeHeartbeatMutation, ProxyNodeManualCreateMutation,
|
||||
ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary, ProxyNodeMetricsStep,
|
||||
ProxyNodeReadRepository, ProxyNodeRegistrationMutation, ProxyNodeRemoteConfigMutation,
|
||||
ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation, ProxyNodeWriteRepository,
|
||||
StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
StoredProxyNodeMetricsBucket, PROXY_NODE_EVENT_TYPE_TUNNEL_ERROR,
|
||||
};
|
||||
use crate::driver::mysql::MysqlPool;
|
||||
@@ -779,10 +780,15 @@ WHERE is_manual = 0
|
||||
if let Some(value) = mutation.avg_latency_ms {
|
||||
node.avg_latency_ms = Some(value);
|
||||
}
|
||||
if let Some(value) = normalize_proxy_metadata(
|
||||
let normalized_proxy_metadata = normalize_proxy_metadata(
|
||||
mutation.proxy_metadata.as_ref(),
|
||||
mutation.proxy_version.as_deref(),
|
||||
) {
|
||||
);
|
||||
let normalized_proxy_metadata = preserve_proxy_metadata_tunnel_security(
|
||||
previous_proxy_metadata.as_ref(),
|
||||
normalized_proxy_metadata,
|
||||
);
|
||||
if let Some(value) = normalized_proxy_metadata {
|
||||
node.proxy_metadata = Some(value);
|
||||
}
|
||||
if let Some(value) = mutation.total_requests_delta.filter(|value| *value > 0) {
|
||||
|
||||
@@ -6,11 +6,12 @@ use sqlx::{postgres::PgRow, PgPool, Postgres, QueryBuilder, Row};
|
||||
use super::types::{
|
||||
bucket_start_unix_secs, build_tunnel_error_event_detail, build_tunnel_metrics_sample,
|
||||
log_reported_tunnel_error_event, normalize_proxy_metadata,
|
||||
reconcile_remote_config_after_heartbeat, ProxyNodeEventQuery, ProxyNodeHeartbeatMutation,
|
||||
ProxyNodeManualCreateMutation, ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary,
|
||||
ProxyNodeMetricsStep, ProxyNodeReadRepository, ProxyNodeRegistrationMutation,
|
||||
ProxyNodeRemoteConfigMutation, ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation,
|
||||
ProxyNodeWriteRepository, StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
preserve_proxy_metadata_tunnel_security, reconcile_remote_config_after_heartbeat,
|
||||
ProxyNodeEventQuery, ProxyNodeHeartbeatMutation, ProxyNodeManualCreateMutation,
|
||||
ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary, ProxyNodeMetricsStep,
|
||||
ProxyNodeReadRepository, ProxyNodeRegistrationMutation, ProxyNodeRemoteConfigMutation,
|
||||
ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation, ProxyNodeWriteRepository,
|
||||
StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
StoredProxyNodeMetricsBucket, TunnelMetricsSample, PROXY_NODE_EVENT_TYPE_TUNNEL_ERROR,
|
||||
};
|
||||
use crate::{
|
||||
@@ -1174,6 +1175,10 @@ impl ProxyNodeWriteRepository for SqlxProxyNodeRepository {
|
||||
mutation.proxy_metadata.as_ref(),
|
||||
mutation.proxy_version.as_deref(),
|
||||
);
|
||||
let normalized_proxy_metadata = preserve_proxy_metadata_tunnel_security(
|
||||
existing.proxy_metadata.as_ref(),
|
||||
normalized_proxy_metadata,
|
||||
);
|
||||
|
||||
sqlx::query(APPLY_HEARTBEAT_SQL)
|
||||
.bind(&mutation.node_id)
|
||||
|
||||
@@ -4,11 +4,12 @@ use sqlx::{sqlite::SqliteRow, QueryBuilder, Row, Sqlite};
|
||||
use super::types::{
|
||||
bucket_start_unix_secs, build_tunnel_error_event_detail, build_tunnel_metrics_sample,
|
||||
log_reported_tunnel_error_event, normalize_proxy_metadata,
|
||||
reconcile_remote_config_after_heartbeat, ProxyNodeEventQuery, ProxyNodeHeartbeatMutation,
|
||||
ProxyNodeManualCreateMutation, ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary,
|
||||
ProxyNodeMetricsStep, ProxyNodeReadRepository, ProxyNodeRegistrationMutation,
|
||||
ProxyNodeRemoteConfigMutation, ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation,
|
||||
ProxyNodeWriteRepository, StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
preserve_proxy_metadata_tunnel_security, reconcile_remote_config_after_heartbeat,
|
||||
ProxyNodeEventQuery, ProxyNodeHeartbeatMutation, ProxyNodeManualCreateMutation,
|
||||
ProxyNodeManualUpdateMutation, ProxyNodeMetricsCleanupSummary, ProxyNodeMetricsStep,
|
||||
ProxyNodeReadRepository, ProxyNodeRegistrationMutation, ProxyNodeRemoteConfigMutation,
|
||||
ProxyNodeTrafficMutation, ProxyNodeTunnelStatusMutation, ProxyNodeWriteRepository,
|
||||
StoredProxyFleetMetricsBucket, StoredProxyNode, StoredProxyNodeEvent,
|
||||
StoredProxyNodeMetricsBucket, PROXY_NODE_EVENT_TYPE_TUNNEL_ERROR,
|
||||
};
|
||||
use crate::driver::sqlite::SqlitePool;
|
||||
@@ -770,10 +771,15 @@ WHERE is_manual = 0
|
||||
if let Some(value) = mutation.avg_latency_ms {
|
||||
node.avg_latency_ms = Some(value);
|
||||
}
|
||||
if let Some(value) = normalize_proxy_metadata(
|
||||
let normalized_proxy_metadata = normalize_proxy_metadata(
|
||||
mutation.proxy_metadata.as_ref(),
|
||||
mutation.proxy_version.as_deref(),
|
||||
) {
|
||||
);
|
||||
let normalized_proxy_metadata = preserve_proxy_metadata_tunnel_security(
|
||||
previous_proxy_metadata.as_ref(),
|
||||
normalized_proxy_metadata,
|
||||
);
|
||||
if let Some(value) = normalized_proxy_metadata {
|
||||
node.proxy_metadata = Some(value);
|
||||
}
|
||||
if let Some(value) = mutation.total_requests_delta.filter(|value| *value > 0) {
|
||||
|
||||
@@ -485,6 +485,34 @@ pub fn normalize_proxy_metadata(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preserve_proxy_metadata_tunnel_security(
|
||||
previous_proxy_metadata: Option<&Value>,
|
||||
next_proxy_metadata: Option<Value>,
|
||||
) -> Option<Value> {
|
||||
let Some(tunnel_security) = previous_proxy_metadata
|
||||
.and_then(|value| value.get("tunnel_security"))
|
||||
.filter(|value| value.is_object())
|
||||
.cloned()
|
||||
else {
|
||||
return next_proxy_metadata;
|
||||
};
|
||||
|
||||
match next_proxy_metadata {
|
||||
Some(Value::Object(mut metadata)) => {
|
||||
metadata
|
||||
.entry("tunnel_security".to_string())
|
||||
.or_insert(tunnel_security);
|
||||
Some(Value::Object(metadata))
|
||||
}
|
||||
Some(value) => Some(value),
|
||||
None => {
|
||||
let mut metadata = serde_json::Map::new();
|
||||
metadata.insert("tunnel_security".to_string(), tunnel_security);
|
||||
Some(Value::Object(metadata))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_tunnel_metrics_counters(
|
||||
proxy_metadata: Option<&Value>,
|
||||
) -> Option<TunnelMetricsCounters> {
|
||||
@@ -772,10 +800,10 @@ mod tests {
|
||||
|
||||
use super::{
|
||||
bucket_start_unix_secs, build_tunnel_error_event_detail, build_tunnel_metrics_sample,
|
||||
normalize_proxy_node_scheduling_state, proxy_node_accepts_new_tunnels,
|
||||
proxy_reported_version, reconcile_remote_config_after_heartbeat,
|
||||
remote_config_scheduling_state, remote_config_upgrade_target, ProxyNodeMetricsStep,
|
||||
StoredProxyNode,
|
||||
normalize_proxy_node_scheduling_state, preserve_proxy_metadata_tunnel_security,
|
||||
proxy_node_accepts_new_tunnels, proxy_reported_version,
|
||||
reconcile_remote_config_after_heartbeat, remote_config_scheduling_state,
|
||||
remote_config_upgrade_target, ProxyNodeMetricsStep, StoredProxyNode,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -934,6 +962,40 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_secure_tunnel_metadata_across_heartbeat_metadata_refresh() {
|
||||
let previous = json!({
|
||||
"version": "1.0.0",
|
||||
"tunnel_security": {
|
||||
"mode": "non_tls_required",
|
||||
"encryption_key": "BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc="
|
||||
}
|
||||
});
|
||||
let next = json!({
|
||||
"version": "1.0.1",
|
||||
"tunnel_metrics": {"connect_successes": 1}
|
||||
});
|
||||
|
||||
let merged = preserve_proxy_metadata_tunnel_security(Some(&previous), Some(next))
|
||||
.expect("metadata should remain present");
|
||||
assert_eq!(
|
||||
merged
|
||||
.pointer("/tunnel_security/mode")
|
||||
.and_then(|v| v.as_str()),
|
||||
Some("non_tls_required")
|
||||
);
|
||||
assert_eq!(
|
||||
merged
|
||||
.pointer("/tunnel_security/encryption_key")
|
||||
.and_then(|v| v.as_str()),
|
||||
Some("BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc=")
|
||||
);
|
||||
assert_eq!(
|
||||
merged.pointer("/tunnel_metrics/connect_successes"),
|
||||
Some(&json!(1))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_timestamps_to_metric_buckets() {
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user