Documentation
¶
Index ¶
- Constants
- Variables
- func ContextWithDirectTransport(ctx context.Context, rt http.RoundTripper) context.Context
- func ContextWithProbe(ctx context.Context) context.Context
- func ContextWithRoomTicketSource(ctx context.Context, src func() []string) context.Context
- func DirectTransportFromContext(ctx context.Context) http.RoundTripper
- func IsHelperTag(tag string) bool
- func IsProbe(ctx context.Context) bool
- func RedactHelperTags(s string) string
- func RoomTicketSourceFromContext(ctx context.Context) func() []string
- type AutoSelectHistoryStorage
- type ExhaustionSignaler
- type MutableOutboundGroup
- type OutboundChecker
- type TagHistory
- type TaggedConn
- type TaggedPacketConn
- type URLOverrideSetter
- type UserFailure
- type UserFailureKind
Constants ¶
const HelperTagPrefix = "helper-"
HelperTagPrefix starts the tag lantern-cloud gives each of a paired inviter's helper outbounds: "helper-" + 12 hex (see HelperTag and HelperUnboundedTag in lantern-cloud's cmd/api/pairing/peersid.go). The tag is a pseudonym of the pairing, so clients must not export it in logs or telemetry; pass any string that may carry an outbound tag through RedactHelperTags first.
Variables ¶
var ErrGroupClosed = errors.New("group is closed")
ErrGroupClosed is returned by MutableOutboundGroup Add/Remove when the group has already been torn down.
Functions ¶
func ContextWithDirectTransport ¶
ContextWithDirectTransport returns a copy of ctx carrying the given http.RoundTripper as the "direct transport". Outbounds that need to make HTTP requests outside the user-facing VPN tunnel (e.g. unbounded's signaling to freddie) should retrieve this transport via DirectTransportFromContext.
The caller (typically radiance, when starting the libbox service) is responsible for building a RoundTripper that dials via the physical interface rather than re-entering the TUN — usually a kindling-backed RoundTripper whose underlying dialer is sing-box's direct outbound, which applies platform socket protection (VpnService.protect on Android, IP_BOUND_IF on iOS/macOS) automatically.
If no direct transport is set, outbounds should fall back to their own DialerOptions-derived dialer. That path does NOT bypass the tunnel, so it is suitable for tests and stand-alone sing-box use but not for production on-device VPN operation.
func ContextWithProbe ¶
ContextWithProbe marks dials made with ctx as probes: connections that test an outbound rather than carry user traffic.
func ContextWithRoomTicketSource ¶ added in v0.0.173
ContextWithRoomTicketSource returns a copy of ctx carrying src, which returns the helper pairing tickets an Unbounded consumer presents to freddie to join its pairings' rooms (the inviter-role tickets lantern-cloud issues the device). The unbounded outbound calls src each time it subscribes for a volunteer, about every 20 seconds, from broflake's signaling goroutines. So src must be cheap, must not block, must not panic, and must be safe for concurrent calls. Its result may change while the outbound runs: tickets live 15 minutes and the caller (radiance) renews them in the background.
Tickets are credentials: neither src nor anything that reads it may log them. With no source, the outbound joins no rooms and uses the pool as before.
func DirectTransportFromContext ¶
func DirectTransportFromContext(ctx context.Context) http.RoundTripper
DirectTransportFromContext returns the direct http.RoundTripper stored in ctx, or nil if none was registered.
func IsHelperTag ¶ added in v0.0.173
IsHelperTag reports whether tag is, in full, a helper tag: HelperTagPrefix followed by exactly 12 lowercase hex digits.
func IsProbe ¶
IsProbe reports whether ctx was marked by ContextWithProbe.
func RedactHelperTags ¶ added in v0.0.173
RedactHelperTags replaces each helper tag in s with "helper". It is cheap when s has none, so it is safe on hot logging and tracing paths.
func RoomTicketSourceFromContext ¶ added in v0.0.173
RoomTicketSourceFromContext returns the source stored in ctx, or nil.
Types ¶
type AutoSelectHistoryStorage ¶
type AutoSelectHistoryStorage interface {
Load(tag string) *TagHistory
Store(tag string, h *TagHistory)
Delete(tag string)
All() map[string]*TagHistory
SetHook(hook func(tag string))
Close() error
}
AutoSelectHistoryStorage is the store the MutableAutoSelect group writes to whenever a member's history changes.
Implementations must be safe for concurrent use. Store and Delete must be non-blocking and fast: the group calls them while holding internal locks, so blocking work — disk I/O, network calls, slow serialization — must happen out-of-band via the hook, not inline. When a state change actually occurs, the hook fires after the change is visible to subsequent Load callers. A Store of nil is equivalent to Delete. Calls that arrive after Close are dropped without panic.
func NewAutoSelectHistoryStorage ¶
func NewAutoSelectHistoryStorage() AutoSelectHistoryStorage
NewAutoSelectHistoryStorage returns an in-memory AutoSelectHistoryStorage. The returned storage is empty; hosts seed it by calling Store for each entry restored from disk before registering it in the service context.
type ExhaustionSignaler ¶
type ExhaustionSignaler interface {
ExhaustionSignal() <-chan struct{}
}
ExhaustionSignaler exposes a channel the host can select on to learn that a full probe of the group's members found no working candidate. At most one value is sent per probe; the host decides what to do (typically a rate-limited config refetch).
type MutableOutboundGroup ¶
type OutboundChecker ¶
type OutboundChecker interface {
CheckOutbounds()
}
OutboundChecker is implemented by outbound groups that support on-demand URL testing.
type TagHistory ¶
type TagHistory struct {
// LastSuccessDelayMs is the most recent successful probe RTT.
// 0 means "no successful probe yet".
LastSuccessDelayMs uint32 `json:"last_success_delay_ms,omitempty"`
// LastOutcomeAt is the timestamp of the most recent probe outcome.
LastOutcomeAt time.Time `json:"last_outcome_at,omitempty"`
// ConsecutiveFailures counts probe failures since the last probe
// success. Resets to zero on probe success.
ConsecutiveFailures uint32 `json:"consecutive_failures,omitempty"`
// UserFailures is the sliding window of user-traffic failures, each
// tagged with its kind. Probe successes never enter this window; entries
// age out naturally on the next mutation older than the group's
// userFailureWindow.
UserFailures []UserFailure `json:"user_failures,omitempty"`
// HardDemoted reports whether the member has reached the hard-demote
// tier from its own recorded probe and user-traffic failures.
HardDemoted bool `json:"hard_demoted,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
}
TagHistory is a point-in-time snapshot of one member's selection state, mirroring the in-memory history kept by the MutableAutoSelect group. Probe outcomes feed the scalar fields; real user-traffic outcomes (dial errors, data-plane stalls) feed the UserFailures sliding window. The two tracks are kept separate so a censor that lets the probe URL through while dropping user traffic shows up as elevated UserFailures with healthy probe scalars simultaneously.
func (*TagHistory) LatestSuccessDelay ¶
func (h *TagHistory) LatestSuccessDelay() uint32
LatestSuccessDelay returns LastSuccessDelayMs, or 0 when h is nil. Kept as a method for symmetry with LatestSuccessTime and to let callers handle nil snapshots without an extra branch.
func (*TagHistory) LatestSuccessTime ¶
func (h *TagHistory) LatestSuccessTime() time.Time
LatestSuccessTime is best-effort: the spec only persists the most recent outcome timestamp (success or failure), so callers asking "tested N seconds ago" get UpdatedAt as a usable reference even when the most recent outcome was a failure. Returns the zero time when h is nil.
type TaggedConn ¶
TaggedConn is a net.Conn tagged with the outbound tag used to create it.
func NewTaggedConn ¶
func NewTaggedConn(conn net.Conn, outboundTag string) *TaggedConn
func (*TaggedConn) Tag ¶
func (c *TaggedConn) Tag() string
func (*TaggedConn) Upstream ¶
func (c *TaggedConn) Upstream() any
Upstream exposes the wrapped conn to common.Cast, so lookups such as the router's pending-handshake check see through the tag.
type TaggedPacketConn ¶
type TaggedPacketConn struct {
net.PacketConn
// contains filtered or unexported fields
}
TaggedPacketConn is a net.PacketConn tagged with the outbound tag used to create it.
It implements N.NetPacketConn so packets written to a domain-name destination reach the wrapped conn with the domain intact. Written only as a net.PacketConn, sing's bufio adapter would reduce the destination to an IP-only address, which per-packet-addressed outbounds reject.
func NewTaggedPacketConn ¶
func NewTaggedPacketConn(conn net.PacketConn, outboundTag string) *TaggedPacketConn
func (*TaggedPacketConn) ReadPacket ¶
func (*TaggedPacketConn) Tag ¶
func (c *TaggedPacketConn) Tag() string
func (*TaggedPacketConn) Upstream ¶
func (c *TaggedPacketConn) Upstream() any
Upstream exposes the wrapped conn to common.Cast and headroom/MTU lookups. TaggedPacketConn is deliberately not Reader/WriterReplaceable, so copy loops never bypass it or the wrappers beneath it.
func (*TaggedPacketConn) WritePacket ¶
type URLOverrideSetter ¶
URLOverrideSetter is implemented by outbound groups that support per-outbound URL test overrides.
type UserFailure ¶
type UserFailure struct {
At time.Time `json:"at"`
Kind UserFailureKind `json:"kind,omitempty"`
}
UserFailure stores when a user-traffic failure happened and what kind it was.
func (*UserFailure) UnmarshalJSON ¶
func (u *UserFailure) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts both the current object form and the legacy bare timestamp form. Legacy entries are tagged as unknown.
type UserFailureKind ¶
type UserFailureKind string
UserFailureKind distinguishes how a member's user traffic failed.
const ( // UserFailureDial is a failure to establish the connection to the member. UserFailureDial UserFailureKind = "dial" // UserFailureStall is a data-plane stall on an already-dialed connection: // the tunnel carried traffic, then went silent for the idle window. UserFailureStall UserFailureKind = "stall" // UserFailureReset is a non-benign transport error (e.g. RST) on an // already-established connection — the tunnel broke mid-stream rather // than going quiet. UserFailureReset UserFailureKind = "reset" UserFailureUnknown UserFailureKind = "unknown" // UserFailureNoResponse is a dialed connection that sent data but had no // response observed before the first-response timeout. UserFailureNoResponse UserFailureKind = "no_response" )