Descriptor-anchored Secured Filesystem Operations

This commit is contained in:
Alexey
2026-09-17 22:45:48 +03:00
parent 9a683d8b3d
commit 02f66c542e
41 changed files with 2997 additions and 1759 deletions
+43 -22
View File
@@ -42,7 +42,7 @@ pub(super) fn ip_prefix_hint_key(peer_ip: IpAddr) -> u64 {
}
}
pub(super) fn sticky_hint_get_by_ip(shared: &ProxySharedState, peer_ip: IpAddr) -> Option<u32> {
pub(super) fn sticky_hint_get_by_ip(shared: &ProxySharedState, peer_ip: IpAddr) -> Option<u64> {
shared
.handshake
.sticky_user_by_ip
@@ -53,7 +53,7 @@ pub(super) fn sticky_hint_get_by_ip(shared: &ProxySharedState, peer_ip: IpAddr)
pub(super) fn sticky_hint_get_by_ip_prefix(
shared: &ProxySharedState,
peer_ip: IpAddr,
) -> Option<u32> {
) -> Option<u64> {
shared
.handshake
.sticky_user_by_ip_prefix
@@ -61,7 +61,7 @@ pub(super) fn sticky_hint_get_by_ip_prefix(
.map(|entry| *entry)
}
pub(super) fn sticky_hint_get_by_sni(shared: &ProxySharedState, sni: &str) -> Option<u32> {
pub(super) fn sticky_hint_get_by_sni(shared: &ProxySharedState, sni: &str) -> Option<u64> {
let key = sni_hint_hash(sni);
shared
.handshake
@@ -73,20 +73,20 @@ pub(super) fn sticky_hint_get_by_sni(shared: &ProxySharedState, sni: &str) -> Op
pub(super) fn sticky_hint_record_success_in(
shared: &ProxySharedState,
peer_ip: IpAddr,
user_id: u32,
hint_key: u64,
sni: Option<&str>,
) {
bounded_sticky_hint_upsert(
&shared.handshake.sticky_user_by_ip,
&shared.handshake.sticky_user_by_ip_slots,
peer_ip,
user_id,
hint_key,
);
bounded_sticky_hint_upsert(
&shared.handshake.sticky_user_by_ip_prefix,
&shared.handshake.sticky_user_by_ip_prefix_slots,
ip_prefix_hint_key(peer_ip),
user_id,
hint_key,
);
if let Some(sni) = sni {
@@ -94,34 +94,55 @@ pub(super) fn sticky_hint_record_success_in(
&shared.handshake.sticky_user_by_sni_hash,
&shared.handshake.sticky_user_by_sni_hash_slots,
sni_hint_hash(sni),
user_id,
hint_key,
);
}
}
fn bounded_sticky_hint_upsert<K>(
entries: &DashMap<K, u32>,
entries: &DashMap<K, u64>,
slots: &crate::slot_budget::SlotBudget,
key: K,
user_id: u32,
hint_key: u64,
) where
K: Eq + Hash,
K: Clone + Eq + Hash,
{
match entries.entry(key) {
Entry::Occupied(mut entry) => {
entry.insert(user_id);
if let Some(mut existing) = entries.get_mut(&key) {
*existing = hint_key;
return;
}
for _ in 0..2 {
if let Some(slot) = slots.try_acquire() {
match entries.entry(key.clone()) {
Entry::Occupied(mut entry) => {
entry.insert(hint_key);
}
Entry::Vacant(entry) => {
entry.insert(hint_key);
slot.commit();
}
}
return;
}
Entry::Vacant(entry) => {
let Some(slot) = slots.try_acquire() else {
return;
};
entry.insert(user_id);
slot.commit();
let Some((victim_key, victim_hint_key)) = entries
.iter()
.next()
.map(|entry| (entry.key().clone(), *entry.value()))
else {
return;
};
if entries
.remove_if(&victim_key, |_, current| *current == victim_hint_key)
.is_some()
{
slots.release();
}
}
}
pub(super) fn record_recent_user_success_in(shared: &ProxySharedState, user_id: u32) {
pub(super) fn record_recent_user_success_in(shared: &ProxySharedState, hint_key: u64) {
let ring = &shared.handshake.recent_user_ring;
if ring.is_empty() {
return;
@@ -131,7 +152,7 @@ pub(super) fn record_recent_user_success_in(shared: &ProxySharedState, user_id:
.recent_user_ring_seq
.fetch_add(1, Ordering::Relaxed);
let idx = (seq as usize) % ring.len();
ring[idx].store(user_id.saturating_add(1), Ordering::Relaxed);
ring[idx].store(hint_key, Ordering::Relaxed);
}
pub(super) fn mark_candidate_if_new(
@@ -387,7 +408,7 @@ mod bounded_registry_tests {
sticky_hint_record_success_in(
shared.as_ref(),
peer_ip,
index as u32,
index as u64 | 1,
Some(&format!("host-{index}.example")),
);
}
+25 -1
View File
@@ -21,8 +21,10 @@ pub(crate) fn auth_probe_fail_streak_for_testing_in_shared(
}
pub(crate) fn clear_auth_probe_state_for_testing_in_shared(shared: &ProxySharedState) {
let removed = shared.handshake.auth_probe.len();
assert_eq!(shared.handshake.auth_probe_slots.used(), removed);
shared.handshake.auth_probe.clear();
shared.handshake.auth_probe_slots.reset_for_testing();
shared.handshake.auth_probe_slots.release_many(removed);
match shared.handshake.auth_probe_saturation.lock() {
Ok(mut saturation) => {
*saturation = None;
@@ -35,6 +37,28 @@ pub(crate) fn clear_auth_probe_state_for_testing_in_shared(shared: &ProxySharedS
}
}
pub(crate) fn insert_auth_probe_state_for_testing_in_shared(
shared: &ProxySharedState,
peer_ip: IpAddr,
state: AuthProbeState,
) {
let peer_ip = normalize_auth_probe_ip(peer_ip);
let slot = shared
.handshake
.auth_probe_slots
.try_acquire()
.expect("test auth-probe registry capacity must be available");
match shared.handshake.auth_probe.entry(peer_ip) {
Entry::Occupied(mut entry) => {
entry.insert(state);
}
Entry::Vacant(entry) => {
entry.insert(state);
slot.commit();
}
}
}
pub(crate) fn auth_probe_state_for_testing_in_shared(
shared: &ProxySharedState,
) -> &DashMap<IpAddr, AuthProbeState> {
+43 -17
View File
@@ -151,10 +151,14 @@ where
if let Some(snapshot) = config.runtime_user_auth() {
let sticky_ip_hint = sticky_hint_get_by_ip(shared, peer.ip());
let sticky_prefix_hint = sticky_hint_get_by_ip_prefix(shared, peer.ip());
let sticky_ip_candidates = sticky_ip_hint
.and_then(|hint_key| snapshot.candidate_ids_by_hint_key(hint_key));
let sticky_prefix_candidates = sticky_prefix_hint
.and_then(|hint_key| snapshot.candidate_ids_by_hint_key(hint_key));
let preferred_user_id = preferred_user.and_then(|user| snapshot.user_id_by_name(user));
let exact_user_id = exact_user.and_then(|user| snapshot.user_id_by_name(user));
let has_hint = sticky_ip_hint.is_some()
|| sticky_prefix_hint.is_some()
let has_hint = sticky_ip_candidates.is_some_and(|ids| !ids.is_empty())
|| sticky_prefix_candidates.is_some_and(|ids| !ids.is_empty())
|| preferred_user_id.is_some()
|| exact_user_id.is_some();
let overload = auth_probe_saturation_is_throttled_in(shared, Instant::now());
@@ -204,9 +208,17 @@ where
let mut matched = exact_user_id.is_some_and(|user_id| try_user_id!(user_id));
if exact_user.is_none()
&& let Some(user_id) = sticky_ip_hint
&& let Some(candidate_ids) = sticky_ip_candidates
{
matched = try_user_id!(user_id);
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break;
}
if budget_exhausted {
break;
}
}
}
if exact_user.is_none()
@@ -218,9 +230,17 @@ where
if exact_user.is_none()
&& !matched
&& let Some(user_id) = sticky_prefix_hint
&& let Some(candidate_ids) = sticky_prefix_candidates
{
matched = try_user_id!(user_id);
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break;
}
if budget_exhausted {
break;
}
}
}
if exact_user.is_none() && !matched && !budget_exhausted {
@@ -231,18 +251,22 @@ where
.recent_user_ring_seq
.load(Ordering::Relaxed);
let scan_limit = ring.len().min(RECENT_USER_RING_SCAN_LIMIT);
for offset in 0..scan_limit {
'recent_hints: for offset in 0..scan_limit {
let idx = (next_seq as usize + ring.len() - 1 - offset) % ring.len();
let encoded_user_id = ring[idx].load(Ordering::Relaxed);
if encoded_user_id == 0 {
let hint_key = ring[idx].load(Ordering::Relaxed);
if hint_key == 0 {
continue;
}
if try_user_id!(encoded_user_id - 1) {
matched = true;
break;
}
if budget_exhausted {
break;
if let Some(candidate_ids) = snapshot.candidate_ids_by_hint_key(hint_key) {
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break 'recent_hints;
}
if budget_exhausted {
break 'recent_hints;
}
}
}
}
}
@@ -357,8 +381,10 @@ where
auth_probe_record_success_in(shared, peer.ip());
if let Some(user_id) = matched_user_id {
sticky_hint_record_success_in(shared, peer.ip(), user_id, None);
record_recent_user_success_in(shared, user_id);
if let Some(entry) = snapshot.entry_by_id(user_id) {
sticky_hint_record_success_in(shared, peer.ip(), entry.hint_key, None);
record_recent_user_success_in(shared, entry.hint_key);
}
}
let max_pending = config.general.crypto_pending_buffer;
+12 -2
View File
@@ -396,8 +396,18 @@ where
auth_probe_record_success_in(shared, peer.ip());
if let Some(user_id) = validated_user_id {
sticky_hint_record_success_in(shared, peer.ip(), user_id, client_sni.as_deref());
record_recent_user_success_in(shared, user_id);
if let Some(entry) = config
.runtime_user_auth()
.and_then(|snapshot| snapshot.entry_by_id(user_id))
{
sticky_hint_record_success_in(
shared,
peer.ip(),
entry.hint_key,
client_sni.as_deref(),
);
record_recent_user_success_in(shared, entry.hint_key);
}
}
HandshakeResult::Success((
+52 -18
View File
@@ -40,11 +40,17 @@ pub(super) async fn validate_tls_client(
};
let sticky_ip_hint = sticky_hint_get_by_ip(shared, peer.ip());
let sticky_ip_candidates = sticky_ip_hint
.and_then(|hint_key| snapshot.candidate_ids_by_hint_key(hint_key));
let preferred_user_id = preferred_user_hint.and_then(|user| snapshot.user_id_by_name(user));
let sticky_sni_hint = client_sni
.as_deref()
.and_then(|sni| sticky_hint_get_by_sni(shared, sni));
let sticky_sni_candidates = sticky_sni_hint
.and_then(|hint_key| snapshot.candidate_ids_by_hint_key(hint_key));
let sticky_prefix_hint = sticky_hint_get_by_ip_prefix(shared, peer.ip());
let sticky_prefix_candidates = sticky_prefix_hint
.and_then(|hint_key| snapshot.candidate_ids_by_hint_key(hint_key));
let sni_candidates = client_sni
.as_deref()
.and_then(|sni| snapshot.sni_candidates(sni));
@@ -52,10 +58,10 @@ pub(super) async fn validate_tls_client(
.as_deref()
.and_then(|sni| snapshot.sni_initial_candidates(sni));
let has_hint = sticky_ip_hint.is_some()
let has_hint = sticky_ip_candidates.is_some_and(|ids| !ids.is_empty())
|| preferred_user_id.is_some()
|| sticky_sni_hint.is_some()
|| sticky_prefix_hint.is_some()
|| sticky_sni_candidates.is_some_and(|ids| !ids.is_empty())
|| sticky_prefix_candidates.is_some_and(|ids| !ids.is_empty())
|| sni_candidates.is_some_and(|ids| !ids.is_empty())
|| sni_initial_candidates.is_some_and(|ids| !ids.is_empty());
let overload = auth_probe_saturation_is_throttled_in(shared, Instant::now());
@@ -95,20 +101,44 @@ pub(super) async fn validate_tls_client(
}
let mut matched = false;
if let Some(user_id) = sticky_ip_hint {
matched = try_user_id!(user_id);
if let Some(candidate_ids) = sticky_ip_candidates {
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break;
}
if budget_exhausted {
break;
}
}
}
if !matched && let Some(user_id) = preferred_user_id {
matched = try_user_id!(user_id);
}
if !matched && let Some(user_id) = sticky_sni_hint {
matched = try_user_id!(user_id);
if !matched && let Some(candidate_ids) = sticky_sni_candidates {
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break;
}
if budget_exhausted {
break;
}
}
}
if !matched && let Some(user_id) = sticky_prefix_hint {
matched = try_user_id!(user_id);
if !matched && let Some(candidate_ids) = sticky_prefix_candidates {
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break;
}
if budget_exhausted {
break;
}
}
}
if !matched
@@ -149,18 +179,22 @@ pub(super) async fn validate_tls_client(
.recent_user_ring_seq
.load(Ordering::Relaxed);
let scan_limit = ring.len().min(RECENT_USER_RING_SCAN_LIMIT);
for offset in 0..scan_limit {
'recent_hints: for offset in 0..scan_limit {
let idx = (next_seq as usize + ring.len() - 1 - offset) % ring.len();
let encoded_user_id = ring[idx].load(Ordering::Relaxed);
if encoded_user_id == 0 {
let hint_key = ring[idx].load(Ordering::Relaxed);
if hint_key == 0 {
continue;
}
if try_user_id!(encoded_user_id - 1) {
matched = true;
break;
}
if budget_exhausted {
break;
if let Some(candidate_ids) = snapshot.candidate_ids_by_hint_key(hint_key) {
for &user_id in candidate_ids {
if try_user_id!(user_id) {
matched = true;
break 'recent_hints;
}
if budget_exhausted {
break 'recent_hints;
}
}
}
}
}