Help us shape the future of Go! Take the 2026 Go Developer Survey

control

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package control is a typed client for the hbbs/hbbr loopback admin channels (docs/research/hbbs-integration.md §1).

Protocol: connect to the hbbs admin port (rendezvous port - 1, default 21115) or the hbbr relay port (21117) FROM LOOPBACK, send one plain-text command line in a single write (hbbs/hbbr do exactly one read() of up to 1024 bytes with a 1 s timeout), then read the reply until the server closes the connection. Setters and unknown commands reply with nothing.

Only allow-listed commands with validated arguments are sent (see Commands). Every call is logged and handed to an AuditSink.

Index

Constants

View Source
const (
	DefaultTimeout     = 3 * time.Second
	DefaultMaxResponse = 256 << 10
)

Defaults.

View Source
const MaxRelayServers = 32

MaxRelayServers bounds the relay server list.

View Source
const MaxWeightedRelayServers = MaxRelayServers * 5

MaxWeightedRelayServers bounds a weighted relay list (MaxRelayServers distinct relays, each repeated at most 5 times); the 1000-byte command line limit usually bites first.

Variables

View Source
var (
	// ErrResponseTooLarge is returned when a reply exceeds MaxResponse.
	ErrResponseTooLarge = errors.New("control: response too large")
	// ErrBadResponse is returned when a reply cannot be parsed.
	ErrBadResponse = errors.New("control: unexpected response")
	// ErrNotLoopback is returned by New for non-loopback addresses.
	ErrNotLoopback = errors.New("control: admin address must be loopback (hbbs/hbbr only accept admin commands from 127.0.0.0/8 or ::1)")
)
View Source
var (
	// ErrNotAllowed is returned for commands outside the allow-list.
	ErrNotAllowed = errors.New("control: command not allowed")
	// ErrInvalidArgs is returned when arguments fail validation.
	ErrInvalidArgs = errors.New("control: invalid arguments")
)
View Source
var SystemActor = Actor{Name: "system"}

SystemActor is used when no actor is attached to the context.

Functions

func BatchIPs

func BatchIPs(ips []string, limit int) [][]string

BatchIPs splits ips into groups whose "|"-joined length is <= limit.

func NormalizeIP

func NormalizeIP(s string) (string, error)

NormalizeIP validates a single IP address (no CIDR, no zone) and returns its canonical form with IPv4-mapped IPv6 unmapped, which is how hbbs/hbbr key their tables.

func NormalizeIPs

func NormalizeIPs(in []string) ([]string, error)

NormalizeIPs validates, canonicalises and de-duplicates a list of IPs (order preserved, empty entries skipped).

func NormalizeRelayServers

func NormalizeRelayServers(in []string) ([]string, error)

NormalizeRelayServers validates relay entries ("host", "host:port", "1.2.3.4", "[v6]:port"), trims blanks and de-duplicates. hbbs resolves each entry with DNS and silently drops failures, so only syntax is checked here.

func NormalizeWeightedRelayServers added in v0.3.0

func NormalizeWeightedRelayServers(in []string) ([]string, error)

NormalizeWeightedRelayServers is NormalizeRelayServers without the de-duplication: hbbs picks relays round-robin over the list as given, so repeating an entry gives it more weight (computed relay rotation).

func ValidateID

func ValidateID(id string) error

ValidateID checks a RustDesk id.

func WithActor

func WithActor(ctx context.Context, a Actor) context.Context

WithActor attaches the acting user to ctx.

Types

type Actor

type Actor struct {
	UserID *int64 `json:"user_id,omitempty"`
	Name   string `json:"name"`
	IP     string `json:"ip,omitempty"`
}

Actor identifies who issued a command (for the audit trail).

func ActorFrom

func ActorFrom(ctx context.Context) Actor

ActorFrom returns the actor attached to ctx, or SystemActor.

type AuditSink

type AuditSink interface {
	RecordCommand(ctx context.Context, rec CommandRecord)
}

AuditSink records admin-channel calls. adminapi implements it on top of admin_audit (typically persisting Mutating or Raw records only).

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to the hbbs/hbbr admin channels. Calls to the same target are serialized. It is safe for concurrent use.

func New

func New(cfg Config) (*Client, error)

New validates cfg (loopback-only addresses) and returns a Client.

func (*Client) Addr

func (c *Client) Addr(t Target) string

Addr returns the configured address of t.

func (*Client) AlwaysUseRelay

func (c *Client) AlwaysUseRelay(ctx context.Context) (bool, error)

AlwaysUseRelay reads ALWAYS_USE_RELAY.

func (*Client) ClearPunchRequests

func (c *Client) ClearPunchRequests(ctx context.Context) error

ClearPunchRequests empties hbbs' punch-request log.

func (*Client) DowngradeStartCheck

func (c *Client) DowngradeStartCheck(ctx context.Context) (time.Duration, error)

DowngradeStartCheck reads how long a relay runs before downgrade checks start.

func (*Client) DowngradeThreshold

func (c *Client) DowngradeThreshold(ctx context.Context) (float64, error)

DowngradeThreshold reads the downgrade threshold ratio (hbbr keeps two decimals).

func (*Client) Exec

func (c *Client) Exec(ctx context.Context, t Target, cmd string, args ...string) (string, error)

Exec runs an allow-listed command with validated arguments and returns the raw reply. cmd may be the full name or the alias.

func (*Client) ExecLine

func (c *Client) ExecLine(ctx context.Context, t Target, line string) (string, error)

ExecLine parses and runs one console line ("ml Y", "blacklist 1.2.3.4") for the admin console. Only allow-listed commands are accepted.

func (*Client) GetRate

func (c *Client) GetRate(ctx context.Context, r Rate) (float64, error)

GetRate reads a bandwidth setting in Mb/s.

func (*Client) IPBlocker

func (c *Client) IPBlocker(ctx context.Context, start int) (IPBlockerPage, error)

IPBlocker lists up to 10 entries starting at offset start.

func (*Client) IPBlockerLookup

func (c *Client) IPBlockerLookup(ctx context.Context, ip string, remove bool) (*IPBlockerEntry, error)

IPBlockerLookup returns the entry for ip (nil if absent). With remove the entry is also deleted (unblocking the IP).

func (*Client) IPChanges

func (c *Client) IPChanges(ctx context.Context, start int) (IPChangesPage, error)

IPChanges lists up to 10 entries starting at offset start.

func (*Client) IPChangesLookup

func (c *Client) IPChangesLookup(ctx context.Context, id string, remove bool) (*IPChange, error)

IPChangesLookup returns the entry for id (nil if absent); remove deletes it. Ids that are integers <= 10,000,000 cannot be addressed (hbbs treats them as a page offset) and yield ErrInvalidArgs.

func (*Client) ListAdd

func (c *Client) ListAdd(ctx context.Context, l List, ips []string) error

ListAdd adds IPs to an hbbr list (batched to fit the 1 KiB command limit).

func (*Client) ListClear

func (c *Client) ListClear(ctx context.Context, l List) error

ListClear empties an hbbr list.

func (*Client) ListContains

func (c *Client) ListContains(ctx context.Context, l List, ip string) (bool, error)

ListContains reports whether ip is on an hbbr list.

func (*Client) ListIPs

func (c *Client) ListIPs(ctx context.Context, l List) ([]string, error)

ListIPs returns the entries of an hbbr list.

func (*Client) ListRemove

func (c *Client) ListRemove(ctx context.Context, l List, ips []string) error

ListRemove removes IPs from an hbbr list.

func (*Client) MustLogin

func (c *Client) MustLogin(ctx context.Context) (bool, error)

MustLogin reads MUST_LOGIN.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context, t Target) (time.Duration, error)

Ping checks that the admin channel of t answers (the help command always returns text) and returns the round-trip time.

func (*Client) PunchRequests

func (c *Client) PunchRequests(ctx context.Context, start, pageSize int) ([]PunchRequest, error)

PunchRequests returns up to pageSize recorded connection attempts starting at offset start (oldest first).

func (*Client) RelayServers

func (c *Client) RelayServers(ctx context.Context) ([]string, error)

RelayServers returns the relay servers hbbs currently hands out (after its DNS/connectivity filtering).

func (*Client) ReloadGeo added in v0.5.7

func (c *Client) ReloadGeo(ctx context.Context) (string, error)

ReloadGeo triggers hbbs to reload its relay_map.txt prefix routing table.

func (*Client) SetAlwaysUseRelay

func (c *Client) SetAlwaysUseRelay(ctx context.Context, on bool) error

SetAlwaysUseRelay sets ALWAYS_USE_RELAY. Upstream hbbs (and this fork before the fix) also re-parses the relay list from the literal "Y"/"N", wiping it; callers must re-send the relay list afterwards (the reconciler does).

func (*Client) SetAudit

func (c *Client) SetAudit(a AuditSink)

SetAudit replaces the audit sink (nil restores NopAudit). The admin API installs its admin_audit-backed sink this way after construction.

func (*Client) SetDowngradeStartCheck

func (c *Client) SetDowngradeStartCheck(ctx context.Context, d time.Duration) error

SetDowngradeStartCheck sets the downgrade start delay (whole seconds, > 0).

func (*Client) SetDowngradeThreshold

func (c *Client) SetDowngradeThreshold(ctx context.Context, v float64) error

SetDowngradeThreshold sets the downgrade threshold ratio (> 0).

func (*Client) SetMustLogin

func (c *Client) SetMustLogin(ctx context.Context, on bool) error

SetMustLogin sets MUST_LOGIN.

func (*Client) SetRate

func (c *Client) SetRate(ctx context.Context, r Rate, mbps float64) error

SetRate sets a bandwidth setting in Mb/s (> 0).

func (*Client) SetRelayServers

func (c *Client) SetRelayServers(ctx context.Context, servers []string) error

SetRelayServers replaces the relay list. hbbs applies it asynchronously and silently drops entries that fail DNS resolution. Repeated entries are kept: hbbs round-robins over the list, so duplicates are weights.

func (*Client) SetTCPKeepalive

func (c *Client) SetTCPKeepalive(ctx context.Context, on bool) error

SetTCPKeepalive sets TCP_KEEPALIVE; it takes effect on the next keepalive tick of every open connection.

func (*Client) SetWebRTC added in v0.3.0

func (c *Client) SetWebRTC(ctx context.Context, on bool) error

SetWebRTC sets WEBRTC; it applies to the next punch request.

func (*Client) Stats added in v0.5.7

func (c *Client) Stats(ctx context.Context) (*RelayStats, error)

Stats returns cumulative process-lifetime statistics from hbbr.

func (*Client) TCPKeepalive

func (c *Client) TCPKeepalive(ctx context.Context) (bool, error)

TCPKeepalive reads TCP_KEEPALIVE (bropines/rustdesk-server fork): whether hbbs sends periodic empty frames on registered TCP/WebSocket rendezvous connections so clients in TCP/WebSocket mode stay online.

func (*Client) TestGeo

func (c *Client) TestGeo(ctx context.Context, ip1, ip2 string) (string, error)

TestGeo returns the relay server hbbs would pick for a connection between ip1 and ip2 (ip2 optional). Note: it advances hbbs' round-robin counter.

func (*Client) Usage

func (c *Client) Usage(ctx context.Context) ([]RelayUsage, error)

Usage returns hbbr's active relays, busiest first.

func (*Client) WebRTC added in v0.3.0

func (c *Client) WebRTC(ctx context.Context) (bool, error)

WebRTC reads WEBRTC (bropines/rustdesk-server fork): whether hbbs forwards WebRTC signaling (SDP offer/answer, trickle ICE) between RustDesk 1.5+ clients.

type CommandRecord

type CommandRecord struct {
	Time    time.Time `json:"time"`
	Target  Target    `json:"target"`
	Command string    `json:"command"` // canonical full name
	Args    []string  `json:"args,omitempty"`
	// Mutating is true for calls that change hbbs/hbbr state.
	Mutating bool `json:"mutating"`
	// Raw is true for calls made through the admin console (ExecLine).
	Raw           bool          `json:"raw"`
	Actor         Actor         `json:"actor"`
	Duration      time.Duration `json:"duration_ns"`
	ResponseBytes int           `json:"response_bytes"`
	// ResponseSHA256 is the hex digest of the reply (the reply itself may be large).
	ResponseSHA256 string `json:"response_sha256,omitempty"`
	Err            string `json:"error,omitempty"`
}

CommandRecord describes one admin-channel call.

type CommandSpec

type CommandSpec struct {
	Target Target `json:"target"`
	Name   string `json:"name"`
	Alias  string `json:"alias"`
	// Usage is a human hint for the console ("[Y|N]").
	Usage string `json:"usage"`
	// contains filtered or unexported fields
}

CommandSpec describes one allow-listed admin command.

func Commands

func Commands() []CommandSpec

Commands returns the allow-list (for the admin console UI).

type Config

type Config struct {
	// HBBSAddr is the hbbs admin address (default 127.0.0.1:21115).
	// "unix:/path" dials a unix socket forwarder instead.
	HBBSAddr string
	// HBBRAddr is the hbbr admin address (default 127.0.0.1:21117).
	HBBRAddr    string
	Timeout     time.Duration
	MaxResponse int
	Audit       AuditSink
	Log         *slog.Logger
	// Dial is injectable for tests.
	Dial func(ctx context.Context, network, addr string) (net.Conn, error)
}

Config configures a Client.

type IPBlockerEntry

type IPBlockerEntry struct {
	IP string `json:"ip"`
	// Attempts is the number of RegisterPk calls in the current window and
	// AttemptsAge the age of that window.
	Attempts    int           `json:"attempts"`
	AttemptsAge time.Duration `json:"attempts_age_ns"`
	// DistinctIDs is the number of ids registered from this IP in the daily
	// window, IDsAge the age of that window.
	DistinctIDs int           `json:"distinct_ids"`
	IDsAge      time.Duration `json:"ids_age_ns"`
}

IPBlockerEntry is one row of hbbs' registration rate limiter.

type IPBlockerPage

type IPBlockerPage struct {
	Total   int              `json:"total"`
	Entries []IPBlockerEntry `json:"entries"`
}

IPBlockerPage is a page of the ip-blocker table.

type IPChange

type IPChange struct {
	ID string `json:"id"`
	// Age is the age of the observation window.
	Age time.Duration `json:"age_ns"`
	// IPs maps each source IP to its registration count.
	IPs map[string]int `json:"ips"`
}

IPChange is one row of hbbs' "id seen from several IPs" table.

type IPChangesPage

type IPChangesPage struct {
	Total   int        `json:"total"`
	Entries []IPChange `json:"entries"`
}

IPChangesPage is a page of the ip-changes table.

type List

type List string

List selects one of hbbr's IP lists.

const (
	Blacklist List = "blacklist"
	Blocklist List = "blocklist"
)

hbbr lists: blacklisted IPs are throttled to limit-speed; blocklisted IPs are refused and cut from running relays.

type NopAudit

type NopAudit struct{}

NopAudit discards records.

func (NopAudit) RecordCommand

func (NopAudit) RecordCommand(context.Context, CommandRecord)

RecordCommand implements AuditSink.

type PunchRequest

type PunchRequest struct {
	Time   time.Time `json:"time"`
	FromIP string    `json:"from_ip"`
	ToID   string    `json:"to_id"`
	ToIP   string    `json:"to_ip"`
}

PunchRequest is one connection attempt recorded by hbbs.

type Rate

type Rate string

Rate selects one of hbbr's bandwidth settings (Mb/s, really Mibit/s).

const (
	LimitSpeed      Rate = "limit-speed"
	TotalBandwidth  Rate = "total-bandwidth"
	SingleBandwidth Rate = "single-bandwidth"
)

hbbr rates. limit-speed applies to blacklisted/downgraded relays and single-bandwidth to each relay (both for new relays only); total-bandwidth is global and applies immediately.

type RelayStats added in v0.5.7

type RelayStats struct {
	BytesTotal    uint64 `json:"bytes_total"`
	RelaysTotal   uint64 `json:"relays_total"`
	RelaysActive  int    `json:"relays_active"`
	Waiting       int    `json:"waiting"`
	AuthFailed    uint64 `json:"auth_failed"`
	Blocked       uint64 `json:"blocked"`
	Downgraded    uint64 `json:"downgraded"`
	UptimeSeconds uint64 `json:"uptime_s"`
	Version       string `json:"version"`
}

RelayStats represents cumulative process-lifetime statistics reported by hbbr stats.

type RelayUsage

type RelayUsage struct {
	Addr    string        `json:"addr"`
	Elapsed time.Duration `json:"elapsed_ns"`
	TotalMB float64       `json:"total_mb"`
	// Rates in kb/s as printed by hbbr.
	HighestKbps int64 `json:"highest_kbps"`
	AvgKbps     int64 `json:"avg_kbps"`
	CurrentKbps int64 `json:"current_kbps"`
}

RelayUsage is one active relay reported by hbbr "usage".

type Target

type Target string

Target selects the process an admin command is sent to.

const (
	HBBS Target = "hbbs"
	HBBR Target = "hbbr"
)

Targets.

func (Target) Valid

func (t Target) Valid() bool

Valid reports whether t is a known target.

Jump to

Keyboard shortcuts

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