Based on Nekogram. Key additions: - Rebrand to FoxiGram (app name, APK name, applicationId com.foxigram.app) - Embedded Xray (VLESS+Reality) proxy client via JNI libxray.so - Bundled hidden one-tap proxies (LTE + WiFi), read-only in UI - Auto-restore proxy on restart, rebind to active network (LTE/WiFi) - Server credentials externalized to git-ignored XrayServers.java (+ template) - libxray Go source included; compiled .so, keystore, google-services.json ignored
84 lines
2.6 KiB
C++
84 lines
2.6 KiB
C++
/*
|
|
* ChaffScheduler.h — Idle chaff injection for tgnet
|
|
* Ported from telemt/tdlib-obf (MIT License, Copyright 2026 telemt community)
|
|
* Adapted for tgnet: C++17, no tdlib dependencies.
|
|
*
|
|
* After 15s of idle traffic, emits synthetic dummy TLS records on 5s intervals
|
|
* within a 4096 bytes/minute sliding budget.
|
|
* Prevents idle-gap fingerprinting where absence of traffic is itself a signal.
|
|
*
|
|
* Disabled by default; enabled when TLS proxy connection is active.
|
|
*/
|
|
|
|
#ifndef CHAFF_SCHEDULER_H
|
|
#define CHAFF_SCHEDULER_H
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include "IptController.h"
|
|
#include "DrsEngine.h"
|
|
|
|
namespace stealth {
|
|
|
|
struct ChaffPolicy {
|
|
bool enabled{false};
|
|
int32_t idle_threshold_ms{15000}; // wait this long after last activity
|
|
double min_interval_ms{5000.0}; // minimum gap between chaff records
|
|
size_t max_bytes_per_minute{4096};
|
|
int32_t record_size_lo{50}; // chaff record size range
|
|
int32_t record_size_hi{800};
|
|
};
|
|
|
|
ChaffPolicy default_chaff_policy();
|
|
|
|
class ChaffScheduler {
|
|
public:
|
|
ChaffScheduler(const ChaffPolicy &policy, IptController &ipt, double now_sec);
|
|
|
|
// Call whenever real data is sent
|
|
void note_activity(double now_sec);
|
|
|
|
// Call after a chaff record is emitted
|
|
void note_chaff_emitted(double now_sec, size_t bytes);
|
|
|
|
// Returns true if a chaff record should be sent right now
|
|
bool should_emit(double now_sec, bool has_pending_data, bool can_write) const;
|
|
|
|
// Returns the monotonic time (seconds) when next wakeup is needed.
|
|
// Returns 0.0 if not scheduled.
|
|
double get_wakeup(double now_sec, bool has_pending_data, bool can_write) const;
|
|
|
|
// Size in bytes of the next chaff record to emit
|
|
int32_t next_record_size();
|
|
|
|
bool is_enabled() const noexcept { return policy_.enabled; }
|
|
void set_enabled(bool v) noexcept { policy_.enabled = v; }
|
|
|
|
private:
|
|
struct BudgetSample {
|
|
double at{0.0};
|
|
size_t bytes{0};
|
|
};
|
|
|
|
static constexpr double kBudgetWindow = 60.0; // seconds
|
|
|
|
void schedule_after_activity(double now_sec);
|
|
void schedule_after_chaff(double now_sec);
|
|
void disarm();
|
|
void prune_budget(double now_sec);
|
|
double budget_resume_at(double now_sec, size_t target_bytes) const;
|
|
bool budget_allows(double now_sec, size_t target_bytes) const;
|
|
double sample_interval_sec();
|
|
int32_t sample_record_size();
|
|
|
|
ChaffPolicy policy_;
|
|
IptController &ipt_;
|
|
std::deque<BudgetSample> budget_window_;
|
|
double next_send_at_{0.0};
|
|
int32_t pending_size_{0};
|
|
};
|
|
|
|
} // namespace stealth
|
|
|
|
#endif // CHAFF_SCHEDULER_H
|