Compare commits

..

6 Commits

Author SHA1 Message Date
Stanislau Pilipeika
8ceb92d984 Merge b6a30c1b51 into ad2057ad44 2026-04-07 13:52:43 +03:00
miniusercoder
b6a30c1b51 refactor: cargo fmt fixes 2026-04-07 13:52:35 +03:00
Alexey
ad2057ad44 Merge pull request #649 from JetJava/flow
tls_front/emulator: hash compact cert info payload before TLS emulation
2026-04-07 13:26:22 +03:00
Alexey
f8cfd4f0bc Merge pull request #651 from groozchique/flow
[FAQ] More user-friendly output when obtaining proxy links
2026-04-07 13:22:17 +03:00
Nick Parfyonov
f5e63ab145 [FAQ] change output of user's links more to more user-friendly look
Currently output of existing method for obtaining proxy links of users is cluttered and messy, let's change it to a more clean and precise one
2026-04-07 13:12:22 +03:00
Ivan
bc3ad02a20 tls_front/emulator: hash compact cert info payload before TLS emulation 2026-04-07 11:31:12 +04:00
5 changed files with 55 additions and 13 deletions

View File

@@ -150,7 +150,7 @@ systemctl daemon-reload
**7.** To get the link(s), enter:
```bash
curl -s http://127.0.0.1:9091/v1/users | jq
curl -s http://127.0.0.1:9091/v1/users | jq -r '.data[] | "User: \(.username)\n\(.links.tls[0] // empty)"'
```
> Any number of people can use one link.

View File

@@ -150,7 +150,7 @@ systemctl daemon-reload
**7.** Для получения ссылки/ссылок введите
```bash
curl -s http://127.0.0.1:9091/v1/users | jq
curl -s http://127.0.0.1:9091/v1/users | jq -r '.data[] | "User: \(.username)\n\(.links.tls[0] // empty)"'
```
> Одной ссылкой может пользоваться сколько угодно человек.

View File

@@ -1,5 +1,6 @@
#![allow(clippy::too_many_arguments)]
use crc32fast::Hasher;
use crate::crypto::{SecureRandom, sha256_hmac};
use crate::protocol::constants::{
MAX_TLS_CIPHERTEXT_SIZE, TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER,
@@ -98,6 +99,31 @@ fn build_compact_cert_info_payload(cert_info: &ParsedCertificateInfo) -> Option<
Some(payload)
}
fn hash_compact_cert_info_payload(cert_payload: Vec<u8>) -> Option<Vec<u8>> {
if cert_payload.is_empty() {
return None;
}
let mut hashed = Vec::with_capacity(cert_payload.len());
let mut seed_hasher = Hasher::new();
seed_hasher.update(&cert_payload);
let mut state = seed_hasher.finalize();
while hashed.len() < cert_payload.len() {
let mut hasher = Hasher::new();
hasher.update(&state.to_le_bytes());
hasher.update(&cert_payload);
state = hasher.finalize();
let block = state.to_le_bytes();
let remaining = cert_payload.len() - hashed.len();
let copy_len = remaining.min(block.len());
hashed.extend_from_slice(&block[..copy_len]);
}
Some(hashed)
}
/// Build a ServerHello + CCS + ApplicationData sequence using cached TLS metadata.
pub fn build_emulated_server_hello(
secret: &[u8],
@@ -190,7 +216,8 @@ pub fn build_emulated_server_hello(
let compact_payload = cached
.cert_info
.as_ref()
.and_then(build_compact_cert_info_payload);
.and_then(build_compact_cert_info_payload)
.and_then(hash_compact_cert_info_payload);
let selected_payload: Option<&[u8]> = if use_full_cert_payload {
cached
.cert_payload
@@ -221,7 +248,6 @@ pub fn build_emulated_server_hello(
marker.extend_from_slice(proto);
marker
});
let mut payload_offset = 0usize;
for (idx, size) in sizes.into_iter().enumerate() {
let mut rec = Vec::with_capacity(5 + size);
rec.push(TLS_RECORD_APPLICATION);
@@ -231,11 +257,10 @@ pub fn build_emulated_server_hello(
if let Some(payload) = selected_payload {
if size > 17 {
let body_len = size - 17;
let remaining = payload.len().saturating_sub(payload_offset);
let remaining = payload.len();
let copy_len = remaining.min(body_len);
if copy_len > 0 {
rec.extend_from_slice(&payload[payload_offset..payload_offset + copy_len]);
payload_offset += copy_len;
rec.extend_from_slice(&payload[..copy_len]);
}
if body_len > copy_len {
rec.extend_from_slice(&rng.bytes(body_len - copy_len));
@@ -317,7 +342,9 @@ mod tests {
CachedTlsData, ParsedServerHello, TlsBehaviorProfile, TlsCertPayload, TlsProfileSource,
};
use super::build_emulated_server_hello;
use super::{
build_compact_cert_info_payload, build_emulated_server_hello, hash_compact_cert_info_payload,
};
use crate::crypto::SecureRandom;
use crate::protocol::constants::{
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE,
@@ -432,7 +459,21 @@ mod tests {
);
let payload = first_app_data_payload(&response);
assert!(payload.starts_with(b"CN=example.com"));
let expected_hashed_payload = build_compact_cert_info_payload(
cached
.cert_info
.as_ref()
.expect("test fixture must provide certificate info"),
)
.and_then(hash_compact_cert_info_payload)
.expect("compact certificate info payload must be present for this test");
let copied_prefix_len = expected_hashed_payload
.len()
.min(payload.len().saturating_sub(17));
assert_eq!(
&payload[..copied_prefix_len],
&expected_hashed_payload[..copied_prefix_len]
);
}
#[test]

View File

@@ -383,8 +383,7 @@ async fn check_family(
let reconnect_budget = health_reconnect_budget(pool, dc_endpoints.len());
let reconnect_sem = Arc::new(Semaphore::new(reconnect_budget));
if pool.floor_mode() == MeFloorMode::Static {
}
if pool.floor_mode() == MeFloorMode::Static {}
let mut live_addr_counts = HashMap::<(i32, SocketAddr), usize>::new();
let mut live_writer_ids_by_addr = HashMap::<(i32, SocketAddr), Vec<u64>>::new();
@@ -617,7 +616,8 @@ async fn check_family(
continue;
}
let base_req = pool_for_reconnect.required_writers_for_dc_with_floor_mode(endpoints_for_dc.len(), false);
let base_req = pool_for_reconnect
.required_writers_for_dc_with_floor_mode(endpoints_for_dc.len(), false);
if alive + restored >= base_req {
pool_for_reconnect
.stats

View File

@@ -1670,7 +1670,8 @@ impl MePool {
}
if endpoints_len > 0 {
let base_req = self.required_writers_for_dc_with_floor_mode(endpoints_len, false);
let base_req =
self.required_writers_for_dc_with_floor_mode(endpoints_len, false);
let active_for_dc = {
let ws = self.writers.read().await;
ws.iter()