mirror of https://github.com/telemt/telemt.git
Compare commits
20 Commits
8b92b80b4a
...
80cb1bc221
| Author | SHA1 | Date |
|---|---|---|
|
|
80cb1bc221 | |
|
|
8461556b02 | |
|
|
cfd516edf3 | |
|
|
803c2c0492 | |
|
|
b762bd029f | |
|
|
761679d306 | |
|
|
41668b153d | |
|
|
1d2f88ad29 | |
|
|
80917f5abc | |
|
|
dc61d300ab | |
|
|
ae16080de5 | |
|
|
b8ca1fc166 | |
|
|
f9986944df | |
|
|
cb877c2bc3 | |
|
|
4426082c17 | |
|
|
22097f8c7c | |
|
|
1450af60a0 | |
|
|
f1cc8d65f2 | |
|
|
ec7e808daf | |
|
|
e4b7e23e76 |
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
# GNU / glibc
|
||||
# ==========================
|
||||
build-gnu:
|
||||
name: GNU ${{ matrix.target }}
|
||||
name: GNU ${{ matrix.asset }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
|
|
@ -35,8 +35,15 @@ jobs:
|
|||
include:
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
asset: telemt-x86_64-linux-gnu
|
||||
cpu: baseline
|
||||
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
asset: telemt-x86_64-v3-linux-gnu
|
||||
cpu: v3
|
||||
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
asset: telemt-aarch64-linux-gnu
|
||||
cpu: generic
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -72,11 +79,19 @@ jobs:
|
|||
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
|
||||
export CC=aarch64-linux-gnu-gcc
|
||||
export CXX=aarch64-linux-gnu-g++
|
||||
export RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc"
|
||||
export RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C lto=fat -C panic=abort"
|
||||
|
||||
else
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
export RUSTFLAGS="-C linker=clang -C link-arg=-fuse-ld=lld"
|
||||
|
||||
if [ "${{ matrix.cpu }}" = "v3" ]; then
|
||||
CPU_FLAGS="-C target-cpu=x86-64-v3"
|
||||
else
|
||||
CPU_FLAGS="-C target-cpu=x86-64"
|
||||
fi
|
||||
|
||||
export RUSTFLAGS="-C linker=clang -C link-arg=-fuse-ld=lld -C lto=fat -C panic=abort $CPU_FLAGS"
|
||||
fi
|
||||
|
||||
cargo build --release --target ${{ matrix.target }}
|
||||
|
|
@ -102,7 +117,7 @@ jobs:
|
|||
# MUSL
|
||||
# ==========================
|
||||
build-musl:
|
||||
name: MUSL ${{ matrix.target }}
|
||||
name: MUSL ${{ matrix.asset }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
|
|
@ -114,8 +129,15 @@ jobs:
|
|||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
asset: telemt-x86_64-linux-musl
|
||||
cpu: baseline
|
||||
|
||||
- target: x86_64-unknown-linux-musl
|
||||
asset: telemt-x86_64-v3-linux-musl
|
||||
cpu: v3
|
||||
|
||||
- target: aarch64-unknown-linux-musl
|
||||
asset: telemt-aarch64-linux-musl
|
||||
cpu: generic
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -123,7 +145,43 @@ jobs:
|
|||
- name: Install deps
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y musl-tools pkg-config curl
|
||||
apt-get install -y \
|
||||
musl-tools \
|
||||
pkg-config \
|
||||
curl
|
||||
|
||||
- uses: actions/cache@v4
|
||||
if: matrix.target == 'aarch64-unknown-linux-musl'
|
||||
with:
|
||||
path: ~/.musl-aarch64
|
||||
key: musl-toolchain-aarch64-v1
|
||||
|
||||
- name: Install aarch64 musl toolchain
|
||||
if: matrix.target == 'aarch64-unknown-linux-musl'
|
||||
run: |
|
||||
set -e
|
||||
|
||||
TOOLCHAIN_DIR="$HOME/.musl-aarch64"
|
||||
ARCHIVE="aarch64-linux-musl-cross.tgz"
|
||||
URL="https://github.com/telemt/telemt/releases/download/toolchains/$ARCHIVE"
|
||||
|
||||
if [ -x "$TOOLCHAIN_DIR/bin/aarch64-linux-musl-gcc" ]; then
|
||||
echo "✅ MUSL toolchain cached"
|
||||
else
|
||||
echo "⬇️ Downloading MUSL toolchain..."
|
||||
|
||||
curl -fL \
|
||||
--retry 5 \
|
||||
--retry-delay 3 \
|
||||
--connect-timeout 10 \
|
||||
--max-time 120 \
|
||||
-o "$ARCHIVE" "$URL"
|
||||
|
||||
mkdir -p "$TOOLCHAIN_DIR"
|
||||
tar -xzf "$ARCHIVE" --strip-components=1 -C "$TOOLCHAIN_DIR"
|
||||
fi
|
||||
|
||||
echo "$TOOLCHAIN_DIR/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Add rust target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
|
@ -140,10 +198,20 @@ jobs:
|
|||
run: |
|
||||
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then
|
||||
export CC=aarch64-linux-musl-gcc
|
||||
export RUSTFLAGS="-C target-feature=+crt-static -C linker=aarch64-linux-musl-gcc"
|
||||
export CC_aarch64_unknown_linux_musl=aarch64-linux-musl-gcc
|
||||
export RUSTFLAGS="-C target-feature=+crt-static -C linker=aarch64-linux-musl-gcc -C lto=fat -C panic=abort"
|
||||
|
||||
else
|
||||
export CC=musl-gcc
|
||||
export RUSTFLAGS="-C target-feature=+crt-static"
|
||||
export CC_x86_64_unknown_linux_musl=musl-gcc
|
||||
|
||||
if [ "${{ matrix.cpu }}" = "v3" ]; then
|
||||
CPU_FLAGS="-C target-cpu=x86-64-v3"
|
||||
else
|
||||
CPU_FLAGS="-C target-cpu=x86-64"
|
||||
fi
|
||||
|
||||
export RUSTFLAGS="-C target-feature=+crt-static -C lto=fat -C panic=abort $CPU_FLAGS"
|
||||
fi
|
||||
|
||||
cargo build --release --target ${{ matrix.target }}
|
||||
|
|
@ -194,12 +262,12 @@ jobs:
|
|||
prerelease: ${{ contains(github.ref, '-') }}
|
||||
|
||||
# ==========================
|
||||
# Docker (FROM RELEASE)
|
||||
# Docker
|
||||
# ==========================
|
||||
docker:
|
||||
name: Docker (from release)
|
||||
name: Docker
|
||||
runs-on: ubuntu-latest
|
||||
needs: release
|
||||
needs: [build-gnu, build-musl]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -208,26 +276,19 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install gh
|
||||
run: apt-get update && apt-get install -y gh
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist
|
||||
|
||||
- name: Extract version
|
||||
id: vars
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download binary
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract binaries
|
||||
run: |
|
||||
mkdir dist
|
||||
mkdir bin
|
||||
|
||||
gh release download ${{ steps.vars.outputs.VERSION }} \
|
||||
--repo ${{ github.repository }} \
|
||||
--pattern "telemt-x86_64-linux-musl.tar.gz" \
|
||||
--dir dist
|
||||
tar -xzf dist/telemt-x86_64-linux-musl/telemt-x86_64-linux-musl.tar.gz -C bin
|
||||
mv bin/telemt bin/telemt-amd64
|
||||
|
||||
tar -xzf dist/telemt-x86_64-linux-musl.tar.gz -C dist
|
||||
chmod +x dist/telemt
|
||||
tar -xzf dist/telemt-aarch64-linux-musl/telemt-aarch64-linux-musl.tar.gz -C bin
|
||||
mv bin/telemt bin/telemt-arm64
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
|
@ -238,7 +299,11 @@ jobs:
|
|||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build & Push
|
||||
- name: Extract version
|
||||
id: vars
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build & Push (multi-arch)
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
|
|
@ -248,4 +313,5 @@ jobs:
|
|||
ghcr.io/${{ github.repository }}:${{ steps.vars.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository }}:latest
|
||||
build-args: |
|
||||
BINARY=dist/telemt
|
||||
BINARY_AMD64=bin/telemt-amd64
|
||||
BINARY_ARM64=bin/telemt-arm64
|
||||
|
|
|
|||
|
|
@ -54,14 +54,20 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-cargo-nextest-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-nextest-
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
- run: cargo test --verbose
|
||||
- name: Install cargo-nextest
|
||||
run: cargo install --locked cargo-nextest || true
|
||||
|
||||
- name: Run tests with nextest
|
||||
run: cargo nextest run -j "$(nproc)"
|
||||
|
||||
# ==========================
|
||||
# Clippy
|
||||
|
|
@ -88,11 +94,13 @@ jobs:
|
|||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-clippy-
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
- run: cargo clippy -- --cap-lints warn
|
||||
- name: Run clippy
|
||||
run: cargo clippy -j "$(nproc)" -- --cap-lints warn
|
||||
|
||||
# ==========================
|
||||
# Udeps
|
||||
|
|
@ -108,20 +116,24 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rust-src
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-cargo-udeps-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-udeps-
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
- name: Install cargo-udeps
|
||||
run: cargo install cargo-udeps || true
|
||||
run: cargo install --locked cargo-udeps || true
|
||||
|
||||
# тоже не валит билд
|
||||
- run: cargo udeps || true
|
||||
- name: Run udeps
|
||||
run: cargo udeps -j "$(nproc)" || true
|
||||
|
|
|
|||
|
|
@ -2793,7 +2793,7 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
|
|||
|
||||
[[package]]
|
||||
name = "telemt"
|
||||
version = "3.3.30"
|
||||
version = "3.3.31"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"anyhow",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
[package]
|
||||
name = "telemt"
|
||||
version = "3.3.30"
|
||||
version = "3.3.31"
|
||||
edition = "2024"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
[features]
|
||||
redteam_offline_expected_fail = []
|
||||
|
||||
|
|
@ -83,4 +86,6 @@ name = "crypto_bench"
|
|||
harness = false
|
||||
|
||||
[profile.release]
|
||||
lto = "thin"
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
|
||||
|
|
|
|||
83
Dockerfile
83
Dockerfile
|
|
@ -1,47 +1,78 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG BINARY
|
||||
ARG TARGETARCH
|
||||
ARG BINARY_AMD64
|
||||
ARG BINARY_ARM64
|
||||
|
||||
# ==========================
|
||||
# Stage: minimal
|
||||
# Minimal Image
|
||||
# ==========================
|
||||
FROM debian:12-slim AS minimal
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
binutils \
|
||||
curl \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
ARG TARGETARCH
|
||||
ARG BINARY_AMD64
|
||||
ARG BINARY_ARM64
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
binutils \
|
||||
curl \
|
||||
xz-utils \
|
||||
ca-certificates; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# --- Select correct binary ---
|
||||
RUN set -eux; \
|
||||
case "${TARGETARCH}" in \
|
||||
amd64) BIN="${BINARY_AMD64}" ;; \
|
||||
arm64) BIN="${BINARY_ARM64}" ;; \
|
||||
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
|
||||
esac; \
|
||||
echo "Using binary: $BIN"; \
|
||||
test -f "$BIN"; \
|
||||
cp "$BIN" /telemt
|
||||
|
||||
# --- Install UPX (arch-aware) ---
|
||||
RUN set -eux; \
|
||||
case "${TARGETARCH}" in \
|
||||
amd64) UPX_ARCH="amd64" ;; \
|
||||
arm64) UPX_ARCH="arm64" ;; \
|
||||
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
|
||||
esac; \
|
||||
\
|
||||
&& curl -fL \
|
||||
curl -fL \
|
||||
--retry 5 \
|
||||
--retry-delay 3 \
|
||||
--connect-timeout 10 \
|
||||
--max-time 120 \
|
||||
-o /tmp/upx.tar.xz \
|
||||
https://github.com/telemt/telemt/releases/download/toolchains/upx-amd64_linux.tar.xz \
|
||||
&& tar -xf /tmp/upx.tar.xz -C /tmp \
|
||||
&& mv /tmp/upx*/upx /usr/local/bin/upx \
|
||||
&& chmod +x /usr/local/bin/upx \
|
||||
&& rm -rf /tmp/upx*
|
||||
"https://github.com/telemt/telemt/releases/download/toolchains/upx-${UPX_ARCH}_linux.tar.xz"; \
|
||||
\
|
||||
tar -xf /tmp/upx.tar.xz -C /tmp; \
|
||||
install -m 0755 /tmp/upx*/upx /usr/local/bin/upx; \
|
||||
rm -rf /tmp/upx*
|
||||
|
||||
COPY ${BINARY} /telemt
|
||||
|
||||
RUN strip /telemt || true
|
||||
RUN upx --best --lzma /telemt || true
|
||||
# --- Optimize binary ---
|
||||
RUN set -eux; \
|
||||
test -f /telemt; \
|
||||
strip --strip-unneeded /telemt || true; \
|
||||
upx --best --lzma /telemt || true
|
||||
|
||||
# ==========================
|
||||
# Debug image
|
||||
# Debug Image
|
||||
# ==========================
|
||||
FROM debian:12-slim AS debug
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
curl \
|
||||
iproute2 \
|
||||
busybox \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
curl \
|
||||
iproute2 \
|
||||
busybox; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -54,7 +85,7 @@ ENTRYPOINT ["/app/telemt"]
|
|||
CMD ["config.toml"]
|
||||
|
||||
# ==========================
|
||||
# Production (REAL distroless)
|
||||
# Production Distroless on MUSL
|
||||
# ==========================
|
||||
FROM gcr.io/distroless/static-debian12 AS prod
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use std::sync::Arc;
|
|||
use std::sync::{Mutex, OnceLock};
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
|
||||
use tracing::{debug, trace, warn};
|
||||
use tracing::{debug, info, trace, warn};
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
|
||||
use crate::config::{ProxyConfig, UnknownSniAction};
|
||||
|
|
@ -28,6 +28,8 @@ use rand::RngExt;
|
|||
|
||||
const ACCESS_SECRET_BYTES: usize = 16;
|
||||
static INVALID_SECRET_WARNED: OnceLock<Mutex<HashSet<(String, String)>>> = OnceLock::new();
|
||||
const UNKNOWN_SNI_WARN_COOLDOWN_SECS: u64 = 5;
|
||||
static UNKNOWN_SNI_WARN_NEXT_ALLOWED: OnceLock<Mutex<Option<Instant>>> = OnceLock::new();
|
||||
#[cfg(test)]
|
||||
const WARNED_SECRET_MAX_ENTRIES: usize = 64;
|
||||
#[cfg(not(test))]
|
||||
|
|
@ -86,6 +88,24 @@ fn auth_probe_saturation_state_lock()
|
|||
.unwrap_or_else(|poisoned| poisoned.into_inner())
|
||||
}
|
||||
|
||||
fn unknown_sni_warn_state_lock() -> std::sync::MutexGuard<'static, Option<Instant>> {
|
||||
UNKNOWN_SNI_WARN_NEXT_ALLOWED
|
||||
.get_or_init(|| Mutex::new(None))
|
||||
.lock()
|
||||
.unwrap_or_else(|poisoned| poisoned.into_inner())
|
||||
}
|
||||
|
||||
fn should_emit_unknown_sni_warn(now: Instant) -> bool {
|
||||
let mut guard = unknown_sni_warn_state_lock();
|
||||
if let Some(next_allowed) = *guard
|
||||
&& now < next_allowed
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*guard = Some(now + Duration::from_secs(UNKNOWN_SNI_WARN_COOLDOWN_SECS));
|
||||
true
|
||||
}
|
||||
|
||||
fn normalize_auth_probe_ip(peer_ip: IpAddr) -> IpAddr {
|
||||
match peer_ip {
|
||||
IpAddr::V4(ip) => IpAddr::V4(ip),
|
||||
|
|
@ -412,6 +432,25 @@ fn auth_probe_test_lock() -> &'static Mutex<()> {
|
|||
TEST_LOCK.get_or_init(|| Mutex::new(()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn unknown_sni_warn_test_lock() -> &'static Mutex<()> {
|
||||
static TEST_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
|
||||
TEST_LOCK.get_or_init(|| Mutex::new(()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn clear_unknown_sni_warn_state_for_testing() {
|
||||
if UNKNOWN_SNI_WARN_NEXT_ALLOWED.get().is_some() {
|
||||
let mut guard = unknown_sni_warn_state_lock();
|
||||
*guard = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn should_emit_unknown_sni_warn_for_testing(now: Instant) -> bool {
|
||||
should_emit_unknown_sni_warn(now)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn clear_warned_secrets_for_testing() {
|
||||
if let Some(warned) = INVALID_SECRET_WARNED.get()
|
||||
|
|
@ -658,12 +697,25 @@ where
|
|||
if client_sni.is_some() && matched_tls_domain.is_none() && preferred_user_hint.is_none() {
|
||||
auth_probe_record_failure(peer.ip(), Instant::now());
|
||||
maybe_apply_server_hello_delay(config).await;
|
||||
debug!(
|
||||
peer = %peer,
|
||||
sni = ?client_sni,
|
||||
action = ?config.censorship.unknown_sni_action,
|
||||
"TLS handshake rejected by unknown SNI policy"
|
||||
);
|
||||
let sni = client_sni.as_deref().unwrap_or_default();
|
||||
let log_now = Instant::now();
|
||||
if should_emit_unknown_sni_warn(log_now) {
|
||||
warn!(
|
||||
peer = %peer,
|
||||
sni = %sni,
|
||||
unknown_sni = true,
|
||||
unknown_sni_action = ?config.censorship.unknown_sni_action,
|
||||
"TLS handshake rejected by unknown SNI policy"
|
||||
);
|
||||
} else {
|
||||
info!(
|
||||
peer = %peer,
|
||||
sni = %sni,
|
||||
unknown_sni = true,
|
||||
unknown_sni_action = ?config.censorship.unknown_sni_action,
|
||||
"TLS handshake rejected by unknown SNI policy"
|
||||
);
|
||||
}
|
||||
return match config.censorship.unknown_sni_action {
|
||||
UnknownSniAction::Drop => HandshakeResult::Error(ProxyError::UnknownTlsSni),
|
||||
UnknownSniAction::Mask => HandshakeResult::BadClient { reader, writer },
|
||||
|
|
|
|||
|
|
@ -1643,6 +1643,32 @@ fn auth_probe_capacity_fresh_full_map_still_tracks_newcomer_with_bounded_evictio
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_sni_warn_cooldown_first_event_is_warn_and_repeated_events_are_info_until_window_expires()
|
||||
{
|
||||
let _guard = unknown_sni_warn_test_lock()
|
||||
.lock()
|
||||
.unwrap_or_else(|poisoned| poisoned.into_inner());
|
||||
clear_unknown_sni_warn_state_for_testing();
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
assert!(
|
||||
should_emit_unknown_sni_warn_for_testing(now),
|
||||
"first unknown SNI event must be eligible for WARN emission"
|
||||
);
|
||||
assert!(
|
||||
!should_emit_unknown_sni_warn_for_testing(now + Duration::from_secs(1)),
|
||||
"events inside cooldown window must be demoted from WARN to INFO"
|
||||
);
|
||||
assert!(
|
||||
should_emit_unknown_sni_warn_for_testing(
|
||||
now + Duration::from_secs(UNKNOWN_SNI_WARN_COOLDOWN_SECS)
|
||||
),
|
||||
"once cooldown expires, next unknown SNI event must be WARN-eligible again"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_auth_probe_full_map_churn_keeps_bound_and_tracks_newcomers() {
|
||||
let _guard = auth_probe_test_lock()
|
||||
|
|
|
|||
Loading…
Reference in New Issue