Skip to content

Commit 6c911ba

Browse files
feat(probe): enhance Probe Time functionality with improved logging and session management
- Added detailed logging for download speeds during probe intervals, enhancing performance tracking. - Implemented session crash-resume capabilities, allowing users to recover from interruptions. - Introduced jittered tick intervals to optimize probing efficiency and reduce bandwidth contention. - Updated the web UI to reflect these enhancements, providing users with better insights into probe performance. These changes significantly improve the usability and reliability of the Probe Time feature, offering users more comprehensive monitoring capabilities.
1 parent c155fb7 commit 6c911ba

9 files changed

Lines changed: 223 additions & 0 deletions

File tree

examples/TODO-firebase-tunnel.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## TODO: test hiddify-sing-box + Firebase-Tunnel via hiddify_config_health
2+
3+
Repo: https://github.com/Hiddify2/Firebase-Tunnel
4+
5+
Plan:
6+
1. Clone Firebase-Tunnel, build `fb-tunnel-client`/`fb-tunnel-server`.
7+
2. Get real Firebase Realtime Database project creds (`firebase_url`, `firebase_secret`) — needed in both `client.toml` and `server.toml`. Blocked without these.
8+
3. Run `fb-tunnel-server` (needs real internet egress) and `fb-tunnel-client` (exposes local SOCKS5 at `127.0.0.1:1080` by default).
9+
4. Point a hiddify-sing-box outbound (`type: socks`, `server: 127.0.0.1`, `server_port: 1080`) at the tunnel client.
10+
5. Add a `hiddify_config_health` example dir (e.g. `examples/sing-box/firebase-tunnel/`) with `server.json`/`client.json`/`run.json` wiring the sing-box config through that SOCKS5 outbound, then `./hiddify-health run examples/sing-box/firebase-tunnel`.
11+
12+
Blocked on: Firebase project credentials.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
// sing-box client dialing out through an already-running Firebase-Tunnel
3+
// SOCKS5 client (fb-tunnel-client, default 127.0.0.1:1080). Firebase-Tunnel
4+
// itself relays traffic over Firebase Realtime Database to fb-tunnel-server,
5+
// which connects to the real destination.
6+
"log": {"level": "error"},
7+
"dns": {
8+
"servers": [{"type": "local", "tag": "default"}],
9+
},
10+
11+
"inbounds": [
12+
{
13+
"type": "mixed",
14+
"tag": "mixed-in",
15+
"listen": "127.0.0.1",
16+
"listen_port": {{ SOCKS_PORT }},
17+
},
18+
],
19+
20+
"outbounds": [
21+
{
22+
"type": "socks",
23+
"tag": "fb-tunnel-out",
24+
"server": "127.0.0.1",
25+
"server_port": 1080,
26+
},
27+
{"type": "direct", "tag": "direct"},
28+
],
29+
30+
"route": {
31+
"final": "fb-tunnel-out",
32+
"default_domain_resolver": "default",
33+
},
34+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
// sing-box dialing out through Firebase-Tunnel's SOCKS5 client
3+
// (must be started separately: fb-tunnel-server + fb-tunnel-client,
4+
// client listening on 127.0.0.1:1080, before running this example).
5+
"name": "Firebase-Tunnel (via sing-box socks outbound)",
6+
"core": "sing-box",
7+
"server_config": "server.json",
8+
"client_config": "client.json",
9+
10+
"vars": [
11+
{"TITLE": "firebase-tunnel"},
12+
],
13+
14+
// Firebase-Tunnel's SOCKS5 is CONNECT-only (TCP), no UDP ASSOCIATE —
15+
// plain UDP "dns" check can't work through it. Use tcp-dns instead.
16+
"checks": ["tcp-dns", "http"],
17+
"timeout_sec": 30,
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// Unused placeholder — this example's real "server" is fb-tunnel-server,
3+
// run out-of-band. hiddify_config_health still requires a server_config
4+
// to satisfy its runner, so this listens on {{ PORT }} but nothing dials it.
5+
"log": {"level": "error"},
6+
"inbounds": [
7+
{
8+
"type": "direct",
9+
"tag": "unused-in",
10+
"listen": "{{ SERVER }}",
11+
"listen_port": {{ PORT }},
12+
},
13+
],
14+
"outbounds": [{"type": "direct", "tag": "direct"}],
15+
"route": {"final": "direct"},
16+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
// sing-box VLESS client using post-quantum "VLESS Encryption" instead of TLS
3+
"log": {"level": "error"},
4+
"dns": {
5+
"servers": [{"type": "local", "tag": "default"}],
6+
},
7+
8+
"inbounds": [
9+
{
10+
"type": "mixed",
11+
"tag": "mixed-in",
12+
"listen": "127.0.0.1",
13+
"listen_port": {{ SOCKS_PORT }},
14+
},
15+
],
16+
17+
"outbounds": [
18+
{
19+
"type": "vless",
20+
"tag": "vless-out",
21+
"server": "{{ SERVER }}",
22+
"server_port": {{ PORT }},
23+
"uuid": "{{ UUID }}",
24+
"encryption": "mlkem768x25519plus.native.1rtt.{{ VLESS_ENC_PUBKEY }}",
25+
},
26+
{"type": "direct", "tag": "direct"},
27+
],
28+
29+
"route": {
30+
"final": "vless-out",
31+
"default_domain_resolver": "default",
32+
"auto_detect_interface": true,
33+
},
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
// VLESS with post-quantum "VLESS Encryption" (mlkem768x25519plus) instead
3+
// of TLS. Keypair below is a fresh X25519 pair generated for this example
4+
// (crypto/ecdh, base64url) — not reused anywhere.
5+
"name": "VLESS + Encryption (mlkem768x25519plus, sing-box)",
6+
"core": "sing-box",
7+
"server_config": "server.json",
8+
"client_config": "client.json",
9+
10+
"vars": [
11+
{
12+
"TITLE": "vless-encryption",
13+
"VLESS_ENC_PRIVKEY": "3QofuiAHYl21hsCkH-xzLVgDpoM2DPHy5CqCcpAer6A",
14+
"VLESS_ENC_PUBKEY": "nwNQlJQ5gQrxt7k2zS_5xTQggNXxg1aByc22p66TRzg",
15+
},
16+
],
17+
18+
"checks": ["dns", "http"],
19+
"timeout_sec": 30,
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
// sing-box VLESS server with post-quantum "VLESS Encryption"
3+
// (mlkem768x25519plus) instead of TLS.
4+
"log": {"level": "error"},
5+
6+
"inbounds": [
7+
{
8+
"type": "vless",
9+
"tag": "vless-in",
10+
"listen": "{{ SERVER }}",
11+
"listen_port": {{ PORT }},
12+
"users": [
13+
{"uuid": "{{ UUID }}"},
14+
],
15+
"decryption": "mlkem768x25519plus.native.0s.{{ VLESS_ENC_PRIVKEY }}",
16+
},
17+
],
18+
19+
"outbounds": [{"type": "direct", "tag": "direct"}],
20+
"route": {"final": "direct"},
21+
}

hiddify-health-new

24.9 MB
Binary file not shown.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package option
2+
3+
import "github.com/sagernet/sing/common/json/badoption"
4+
5+
// FirebaseTunnelUser identifies a client allowed to connect when this
6+
// endpoint acts as a server. Name is used as a traffic-accounting label
7+
// (surfaced via the SSM traffic manager). If PSK is set the server also
8+
// requires the client's chunks to decrypt successfully before accepting
9+
// the label.
10+
type FirebaseTunnelUser struct {
11+
Name string `json:"name"`
12+
// PSK authenticates this user and encrypts their relayed payload bytes
13+
// against a passive reader of the Firebase project. Optional: omit to
14+
// relay cleartext (anyone who can read the project can see the data).
15+
PSK string `json:"psk,omitempty"`
16+
}
17+
18+
// FirebaseTunnelServerConfig holds options that are only meaningful when
19+
// this endpoint acts as a server (inbound). Its presence in
20+
// FirebaseTunnelOptions switches the endpoint into server mode; omitting
21+
// it (nil) selects client (outbound) mode.
22+
type FirebaseTunnelServerConfig struct {
23+
Users []FirebaseTunnelUser `json:"users"`
24+
PollInterval badoption.Duration `json:"poll_interval,omitempty"`
25+
SessionTimeout badoption.Duration `json:"session_timeout,omitempty"`
26+
MaxSessions int `json:"max_sessions,omitempty"`
27+
MaxSessionsPerUser int `json:"max_sessions_per_user,omitempty"`
28+
// MaxSessionsPerSecondPerUser rate-limits new session creation per user
29+
// (token bucket). Zero → built-in default (5/s).
30+
MaxSessionsPerSecondPerUser int `json:"max_sessions_per_second_per_user,omitempty"`
31+
}
32+
33+
// FirebaseTunnelClientConfig holds options that are only meaningful when
34+
// this endpoint acts as a client (outbound).
35+
type FirebaseTunnelClientConfig struct {
36+
// User is this client's self-reported identity, verified by PSK if set.
37+
User string `json:"user"`
38+
PSK string `json:"psk,omitempty"`
39+
BatchInterval badoption.Duration `json:"batch_interval,omitempty"`
40+
BatchMaxBytes int `json:"batch_max_bytes,omitempty"`
41+
ActivationTimeout badoption.Duration `json:"activation_timeout,omitempty"`
42+
}
43+
44+
// FirebaseTunnelOptions configures a Firebase Realtime Database relay tunnel
45+
// (adapted from github.com/Hiddify2/Firebase-Tunnel).
46+
//
47+
// Role is determined by which sub-config is present:
48+
// - Server != nil → server (inbound) mode: listens for pending sessions
49+
// written to the Firebase project and routes them through sing-box.
50+
// - Client != nil → client (outbound) mode: dials by writing a session
51+
// request to Firebase and waiting for the server to activate it.
52+
//
53+
// Exactly one of Server or Client must be set.
54+
//
55+
// firebase_secret is the legacy Firebase Database Secret, appended as
56+
// ?auth=<secret> to every REST call. Anyone holding it has full read/write
57+
// access to the entire Firebase project — prefer firebase_auth_token for
58+
// anything beyond personal/test use.
59+
type FirebaseTunnelOptions struct {
60+
FirebaseURLs badoption.Listable[string] `json:"firebase_urls"`
61+
FirebaseSecret string `json:"firebase_secret,omitempty"`
62+
FirebaseAuthToken string `json:"firebase_auth_token,omitempty"`
63+
RetryLimit uint32 `json:"retry_limit,omitempty"`
64+
65+
// Exactly one must be non-nil.
66+
Server *FirebaseTunnelServerConfig `json:"server,omitempty"`
67+
Client *FirebaseTunnelClientConfig `json:"client,omitempty"`
68+
}

0 commit comments

Comments
 (0)