Documentation
¶
Overview ¶
Package decoy serves an innocent-looking website ("заглушка") for every request that doesn't carry the secret panel path. The goal: a visitor, DPI, or scanner sees an ordinary site, never a hint that a VPN panel exists.
Looking ordinary is not only about the HTML. A probe compares what the server DOES against what it claims to be, so the handler mimics a static file server down to the mechanics: Content-Length on every response (net/http chunks bodies over its 2 KB sniff buffer, and no static host chunks static files), Last-Modified + ETag + conditional 304s, byte ranges, a 405 for methods a file server does not implement, and a not-found page whose status agrees with its body. See Handler.ServeHTTP.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RandomTemplate ¶ added in v1.5.0
func RandomTemplate() string
RandomTemplate returns a template slug for a fresh install. Choosing at random keeps a fleet from sharing one recognisable front page — the body stamp (see Stamp) separates two installs that land on the same slug, and this separates their look as well.
Types ¶
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler serves a single decoy template.
type Stamp ¶ added in v1.5.0
type Stamp struct {
// contains filtered or unexported fields
}
Stamp is the per-install entropy applied to a decoy template. Every bundled template is byte-identical in every RosPanel binary, so without it the hash of the served index page is a fleet-wide identifier: collect it from one visible install and the rest fall out of a body-hash search on Censys/FOFA/Shodan.
The stamp derives, from one random per-server seed:
- an insignificant HTML comment appended to every page (unique body bytes),
- a distinct plausible modification time per file (Last-Modified),
- the ETag that follows from that time and size.
Two installs therefore share neither a body hash nor a validator, while each one stays perfectly stable across restarts — an ordinary site whose pages keep changing timestamp on every reload would be its own tell.
func LoadStamp ¶ added in v1.5.0
LoadStamp returns the decoy stamp for dataDir, creating the seed on first use. Cached per directory so the repeated calls behind a template switch don't re-read the file.
It never fails: a seed that cannot be persisted falls back to a process-lifetime random one, which still separates this install from every other — it just stops being stable across a restart.