decoy

package
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 26, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

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 Available

func Available() ([]string, error)

Available returns the list of bundled template slugs.

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.

func New

func New(template string, st Stamp) (*Handler, error)

New returns a decoy handler for the given template slug, stamped with this install's entropy (see LoadStamp).

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP answers like a static file server: known paths are served with full validators, unknown ones get the template's not-found behaviour, and methods a file server doesn't implement get a 405.

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

func LoadStamp(dataDir string) Stamp

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL