Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ tor:
onionPort: 80
onionKeyPath: "./data/onion_private_key"
streamIsolation: true
seedAddrs: []
requireSeeds: false
useSSL: false
certFile: "cert.pem"
keyFile: "key.pem"
Expand Down
24 changes: 17 additions & 7 deletions internal/covertraffic/covertraffic.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import (
// p2p.CTConfig via CTConfig.resolve(); keep Go field names aligned with the
// CTConfig yaml tags (covered by the YAML tests in p2p_test.go).
type Config struct {
Enabled bool
Rate int // target messages per second
MaxPayloadSize int // max bytes per dummy payload (default 256)
CPUThreshold float64 // system load threshold to throttle (0.0–1.0, default 0.8)
CPUThrottle time.Duration // duration of throttle when CPU overloaded (default 5s)
InternalTag string // action tag for internal cover messages (default "cover")
Enabled bool `yaml:"coverTraffic"`
Rate int `yaml:"coverTrafficRate"` // target messages per second
MaxPayloadSize int `yaml:"coverTrafficPayloadSize"` // max bytes per dummy payload (default 256)
CPUThreshold float64 `yaml:"coverTrafficCPUThreshold"` // system load threshold to throttle (0.0–1.0, default 0.8)
CPUThrottle time.Duration `yaml:"coverTrafficCPUThrottle"` // duration of throttle when CPU overloaded (default 5s)
InternalTag string `yaml:"coverTrafficInternalTag"` // action tag for internal cover messages (default "cover")
}

// DefaultConfig returns sensible defaults.
Expand All @@ -43,6 +43,7 @@ type CoverTraffic struct {
running atomic.Bool
cancel context.CancelFunc
setRateCh chan uint64 // signals the run loop to reset the ticker
done chan struct{}
// Runtime state — use int64 for go1.26 compatibility
msgsPerSec atomic.Int64 // current rate
shouldThrottle atomic.Int64 // set >0 when throttling
Expand All @@ -69,6 +70,7 @@ func New(cfg Config) *CoverTraffic {
ct := &CoverTraffic{
cfg: cfg,
setRateCh: make(chan uint64, 1),
done: make(chan struct{}),
}
ct.msgsPerSec.Store(int64(cfg.Rate))
return ct
Expand Down Expand Up @@ -289,11 +291,19 @@ func (ct *CoverTraffic) generatePayload() model.Message {

return model.Message{
Action: cfg.InternalTag,
From: model.UserInfo{
From: model.UserInfo{
PeerID: "cover-traffic",
},
Content: model.Content{
Message: string(payload[:cfg.MaxPayloadSize/2]), // keep payload readable
},
}
}

// adjustInterval adjusts the ticker interval based on target rate.
func adjustInterval(interval time.Duration, targetRPS int) time.Duration {
if targetRPS <= 0 {
return interval
}
return time.Duration(float64(time.Second) / float64(targetRPS))
}
27 changes: 7 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,26 +178,13 @@ func main() {
log.Fatalf(Red+"Failed to start P2P: %v"+Reset, err)
}

// --- Cover traffic: send dummy messages to obscure real traffic patterns (production only) ---
if !*devMode {
go func() {
ticker := time.NewTicker(2 * time.Minute)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
dummy := model.Message{
Action: "cover",
Content: model.Content{Message: "keepalive"},
}
if err := host.Publish(dummy); err != nil {
log.Printf("[COVER] publish failed: %v", err)
}
}
}
}()
// --- Cover traffic: configurable module that generates dummy GossipSub messages
// to obscure real traffic patterns (production only) ---
host.InitCoverTraffic()
if !*devMode && host.CoverTrafficEnabled() {
if err := host.StartCoverTraffic(ctx); err != nil {
log.Printf("[COVER] cover traffic start failed: %v", err)
}
}

// --- Initialize streaming (E2E encrypted audio/video) ---
Expand Down
Loading