Documentation
¶
Index ¶
- Variables
- func ContextWithDirectTransport(ctx context.Context, rt http.RoundTripper) context.Context
- func ContextWithProbe(ctx context.Context) context.Context
- func DirectTransportFromContext(ctx context.Context) http.RoundTripper
- func IsProbe(ctx context.Context) bool
- type AutoSelectHistoryStorage
- type ExhaustionSignaler
- type MutableOutboundGroup
- type OutboundChecker
- type TagHistory
- type TaggedConn
- type TaggedPacketConn
- type URLOverrideSetter
- type UserFailure
- type UserFailureKind
Constants ¶
This section is empty.
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 DirectTransportFromContext ¶
func DirectTransportFromContext(ctx context.Context) http.RoundTripper
DirectTransportFromContext returns the direct http.RoundTripper stored in ctx, or nil if none was registered.
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 the group's reconnection ladder finished without finding a working candidate. At most one value is sent per ladder run; 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" )