Documentation
¶
Overview ¶
Package dmsgweb pkg/dmsgweb/home.go c4-app-web
Package dmsgweb pkg/dmsgweb/runtime.go c4-app-web `.dmsg` (and other configurable) domain suffixes. It exposes:
- a SOCKS5 proxy that intercepts hosts ending in the configured DomainSuffix and tunnels them directly as DMSG streams
- a raw TCP bridge for fixed (pk, dmsgPort) → localhost mappings
HTTP bridging was removed; raw TCP forwards bytes transparently and works for HTTP, WebSockets, server-sent events, chunked transfers, and any other protocol the dmsg target speaks. The previous HTTP bridge added URL rewriting and per-target connection pooling but no functional behavior that raw TCP doesn't already provide.
The package accepts an externally-created *dmsg.Client so the runtime can be embedded into either the standalone `skywire dmsg web` command or a visor-hosted application (e.g. a resolver inside skysocks-client). Neither mode owns the client; lifecycle belongs to the caller.
Package dmsgweb pkg/dmsgweb/skynet_via.go c1-net-dmsg
Package dmsgweb pkg/dmsgweb/stats.go c4-app-web
Stats collects per-resolver request counters and surfaces them to consumers via Snapshot(). Intentionally lightweight — atomic counters on the hot path, a short mutex-protected last-error window so the hypervisor UI can display recent failures without hitting the visor logs.
Stats is opt-in: when Config.Stats is nil the runtime skips the bookkeeping entirely, so zero overhead for callers that don't care. The visor layer always wires it up so `skywire cli visor proxies --json` can pipe straight to UI widgets.
Index ¶
- Constants
- Variables
- func IsHomeHost(host, suffix string) bool
- func ParseSkynetVia(s string) (cipher.PubKey, string, error)
- func RenderHomePage(aliases map[string]cipher.PubKey, suffix string, localPK cipher.PubKey) []byte
- func Run(ctx context.Context, log *logging.Logger, dmsgC *dmsg.Client, cfg Config) error
- type Config
- type DmsgTarget
- type SkynetVia
- type Stats
- type StatsSnapshot
Constants ¶
const DefaultDomainSuffix = ".dmsg"
DefaultDomainSuffix is the TLD treated as DMSG addresses when Config.DomainSuffix is empty. Kept here rather than in a CLI flag default so the visor app gets the same behavior.
const HomeAlias = "home"
HomeAlias is a reserved resolver label that serves a synthetic directory of every alias this resolver knows — a navigation index for the proxy. It is generated in-process by the resolver and is reachable ONLY through the proxy (e.g. http://home.dmsg/); the visor never serves it on a real port. The label is reserved: it shadows any same-named configured alias.
Variables ¶
SkynetViaTypes are the transport types that can dial a visor at a fixed address. sudph and webrtc need the address resolver or signaling to connect.
Functions ¶
func IsHomeHost ¶
IsHomeHost and RenderHomePage export the home-label check + directory renderer so the wasm-visor's in-tab resolving fetch (browse overlay) serves the same home.dmsg page + alias directory as the socks5 resolving proxy.
func ParseSkynetVia ¶ added in v1.3.100
ParseSkynetVia splits "<pk>@<host:port>".
func RenderHomePage ¶
RenderHomePage exports renderHomePage (the self-contained alias directory).
Types ¶
type Config ¶
type Config struct {
// DomainSuffix is the domain extension that the SOCKS5 resolver
// treats as DMSG (e.g. ".dmsg"). Defaults to DefaultDomainSuffix.
DomainSuffix string
// WebPorts are the localhost TCP listener ports. Used only in mode 2
// (fixed-mapping); ignored in SOCKS5 mode. One entry per ResolveAddr.
WebPorts []uint
// ProxyAddr is the host the SOCKS5 proxy listens on. Empty means
// loopback ("127.0.0.1") — the safe default. Set to "0.0.0.0" or a
// specific LAN IP to serve OTHER devices on the network, e.g. a board
// acting as a `.dmsg` gateway for a home router's LAN. Binding a
// non-loopback address exposes the proxy to the LAN; only do so on a
// trusted network.
ProxyAddr string
// ProxyPort is the SOCKS5 proxy listener port. Zero disables the
// SOCKS5 proxy (useful when the runtime is embedded inside an
// app that already provides its own SOCKS5 front-end).
ProxyPort uint
// ResolveAddr is a parallel slice of (pk, dmsgPort) fixed targets.
// Enables mode 2; must be the same length as WebPorts when set.
ResolveAddr []DmsgTarget
// UpstreamSOCKS, when non-empty, sends non-matching CONNECT
// requests through this upstream SOCKS5 (e.g. "127.0.0.1:1080").
// Matches the existing `--addproxy` CLI flag.
UpstreamSOCKS string
// UpstreamRules send chosen domains to a different upstream, or
// "direct", ahead of UpstreamSOCKS.
UpstreamRules []proxyroute.Rule
// Stats, when non-nil, is updated for every SOCKS5 dial. The visor
// layer allocates one per resolver lifetime so counters persist
// across Start/Stop cycles.
Stats *Stats
// TLSMITM enables on-the-fly TLS termination for browser
// connections to <pk>.dmsg on the TLSPort, using LeafMinter to
// produce per-host leaf certs signed by a locally-installed CA.
// When false the runtime behaves exactly as before — pure SOCKS5
// byte splice. See pkg/skynetca for the trust model.
TLSMITM bool
// TLSPort selects the destination port treated as TLS for MITM.
// Defaults to 443. Ignored when TLSMITM is false.
TLSPort uint16
// TLSUpstreamPort is the destination port a MITM'd TLS connection is
// sent to once decrypted. Defaults to 80, where visors serve HTTP.
TLSUpstreamPort uint16
// LeafMinter mints per-host leaf certs. Required when TLSMITM
// is true; ignored otherwise.
LeafMinter skynetca.LeafMinter
// LocalPK is this visor's public key, used to detect self-lookups for the
// SelfLoopback short-circuit.
LocalPK cipher.PubKey
// SelfLoopback, when true (the default), serves a request whose destination
// is LocalPK from the local service in-process via SelfDial, instead of
// dialing out over dmsg back to self (a wasteful, 202-prone round-trip).
// Set false to force the full transport path — e.g. to test self-transports.
SelfLoopback bool
// SelfDial returns an in-process connection to the local service registered
// on the given dmsg port. Used only when SelfLoopback short-circuits a
// self-destined request. Nil disables the short-circuit.
SelfDial func(port uint16) (net.Conn, error)
// Aliases maps a destination label to a PK (e.g. "skywire" -> LocalPK), so
// "skywire.dmsg" resolves exactly like "<pk>.dmsg".
Aliases map[string]cipher.PubKey
// DirectClient is an optional dmsg client that reaches servers by their
// configured address rather than via discovery. A dest in DirectServerPKs
// is dialed through it by self-rendezvous (EnsureAndObtainSession(dest) +
// DialStream(dest:port)), which makes non-discovery dmsg SERVERS — they
// serve /health etc. over dmsg but never register a client entry, so the
// discovery client cannot resolve them — reachable by name. Nil disables
// this path (dests fall through to the normal discovery dial).
DirectClient *dmsg.Client
// DirectServerPKs is the set of destination PKs to dial via DirectClient.
DirectServerPKs map[cipher.PubKey]struct{}
// SkynetDial, when set, is tried before the dmsg dial for an ordinary
// .dmsg destination: it reaches the peer over the visor's skynet
// transports (direct, else through a peer that has one), and returns an
// error to fall back to dmsg. The visor sets it only when this resolver
// runs under the visor's own key, whose transports those are.
SkynetDial func(ctx context.Context, pk cipher.PubKey, port uint16) (net.Conn, error)
// StatusProvider, when non-nil, enables the reserved in-process status hosts
// served through this proxy — a read-only diagnostic page (logs +
// route/transport events + per-leg mux view) for a surface. Nil disables the
// status hosts (they fall through to a normal resolve / upstream forward).
// See pkg/proxystatus.
StatusProvider proxystatus.Provider
// StatusSurface scopes which reserved status host THIS proxy layer owns and
// answers for (e.g. SurfaceDmsg → only http(s)://status.dmsg/). A status host
// matching a DIFFERENT surface is NOT served here — it falls through so the
// request continues up the proxy chain to the layer that owns it. Empty means
// "serve any matched surface" (the pre-scoping behavior), kept so standalone
// runtimes and tests need no wiring. Ignored when StatusProvider is nil.
StatusSurface proxystatus.Surface
// Publish, when non-nil, is called once with a handler that serves ONE
// already-established connection exactly as the listener would, protocol
// sniff included. The visor registers it as an in-process local service so
// an app on this visor reaches this resolver over the data plane it already
// holds, with no second SOCKS hop on localhost. The handler stays valid
// until Run returns.
Publish func(serve func(net.Conn))
}
Config configures a dmsgweb runtime. Two operating modes:
ResolveAddr empty → SOCKS5 resolver mode. Any hostname ending in DomainSuffix is treated as <pk>.dmsg:<port> and tunneled directly as a DMSG stream. The SOCKS5 proxy on ProxyPort rewrites the dial target to localhost so curl/browsers reach .dmsg sites transparently.
ResolveAddr non-empty → fixed mapping mode. Each entry maps to WebPorts[i] and is served as a raw TCP tunnel to (pk, dmsgPort). The SOCKS5 proxy is disabled — callers point their client directly at 127.0.0.1:WebPorts[i]. Raw TCP transparently carries HTTP, WebSockets, and any other protocol.
type DmsgTarget ¶
DmsgTarget is a (publicKey, dmsgPort) pair used in fixed-mapping mode.
func ParseDmsgTarget ¶
func ParseDmsgTarget(s string) (DmsgTarget, error)
ParseDmsgTarget parses a "<pk>[:<port>]" string. If the port is omitted, it defaults to 80 (matching the existing CLI behavior).
type SkynetVia ¶ added in v1.3.100
type SkynetVia struct {
// contains filtered or unexported fields
}
SkynetVia holds one transport from this proxy's key to a visor and reaches other visors through it as a one-hop relay. The relay forwards a SYN signed by this key, so the destination sees this key and not the visor's.
func StartSkynetVia ¶ added in v1.3.100
func StartSkynetVia(ctx context.Context, log *logging.Logger, mLog *logging.MasterLogger, pk cipher.PubKey, sk cipher.SecKey, visorPK cipher.PubKey, addr string, tpType types.Type) (*SkynetVia, error)
StartSkynetVia opens a transport of type tpType to visorPK at addr, the visor's transport_port (or its stcpr port, or :7777 for stcp), and keeps it open until ctx is done. This side registers nothing anywhere and binds its own listener to loopback only.
func (*SkynetVia) Dial ¶ added in v1.3.100
Dial reaches pk:port over skynet: directly when pk is the visor, else relayed through it. It fails when the visor has no non-dmsg transport to pk.
func (*SkynetVia) DmsgClient ¶ added in v1.3.100
func (s *SkynetVia) DmsgClient(ctx context.Context, log *logging.Logger, pk cipher.PubKey, sk cipher.SecKey) (*dmsg.Client, func(), error)
DmsgClient starts a dmsg client that holds its one session through the visor's dmsg relay, over this transport. It registers nothing, and its streams go out over the visor's dmsg server sessions under this key.
type Stats ¶
type Stats struct {
// contains filtered or unexported fields
}
Stats is the public stats container. Safe for concurrent use.
func NewStats ¶
func NewStats() *Stats
NewStats returns a zero-valued Stats with its "started at" clock set to now. Callers typically allocate one per resolver lifetime and pass it to every Config, so cumulative counters survive Start/Stop cycles.
func (*Stats) RecordRequest ¶
RecordRequest begins tracking a new request. Returns a closure that the caller defers to record completion; pass in the request error (nil on success). Pattern:
done := stats.RecordRequest() // ... do the work ... done(err)
Nil receiver is a no-op, so callers can unconditionally call it without checking for nil Stats.
func (*Stats) Snapshot ¶
func (s *Stats) Snapshot() StatsSnapshot
Snapshot returns a stable point-in-time copy.
type StatsSnapshot ¶
type StatsSnapshot struct {
StartedAt time.Time `json:"started_at,omitempty"`
UptimeSec int64 `json:"uptime_sec,omitempty"`
TotalRequests uint64 `json:"total_requests"`
Successful uint64 `json:"successful"`
Failed uint64 `json:"failed"`
Active int64 `json:"active"`
LastRequestAt *time.Time `json:"last_request_at,omitempty"`
LastSuccessAt *time.Time `json:"last_success_at,omitempty"`
LastFailureAt *time.Time `json:"last_failure_at,omitempty"`
LastError string `json:"last_error,omitempty"`
}
StatsSnapshot is the read-only view exposed to RPC / UI layers. Safe to marshal.