Documentation
¶
Overview ¶
Package proxy implements the forward and reverse proxy data plane for Resin.
Index ¶
- Variables
- func NewCountingListener(ln net.Listener, sink MetricsEventSink) net.Listener
- func NormalizeRulePrefix(prefix string) (string, error)
- type AccountMatcher
- type AccountMatcherRuntime
- func (r *AccountMatcherRuntime) Current() *AccountMatcher
- func (r *AccountMatcherRuntime) Match(host, path string) []string
- func (r *AccountMatcherRuntime) MatchWithPrefix(host, path string) (string, []string)
- func (r *AccountMatcherRuntime) ReplaceRules(rules []model.AccountHeaderRule)
- func (r *AccountMatcherRuntime) Swap(next *AccountMatcher)
- type AccountRuleMatcher
- type ConfigAwareEventEmitter
- type ConnectionDirection
- type ConnectionLifecycleEvent
- type ConnectionOp
- type EventEmitter
- type ForwardProxy
- type ForwardProxyConfig
- type HealthRecorder
- type MetricsEventSink
- type NoOpEventEmitter
- type OutboundTransportConfig
- type OutboundTransportPool
- type PlatformLookup
- type ProxyError
- type ProxyType
- type RequestFinishedEvent
- type RequestLogEntry
- type ReverseProxy
- type ReverseProxyConfig
- type Socks5Inbound
- type Socks5InboundConfig
Constants ¶
This section is empty.
Variables ¶
var ( ErrAuthRequired = &ProxyError{ HTTPCode: http.StatusProxyAuthRequired, ResinError: "AUTH_REQUIRED", Message: "Proxy authentication required", } ErrAuthFailed = &ProxyError{ HTTPCode: http.StatusForbidden, ResinError: "AUTH_FAILED", Message: "Proxy authentication failed", } ErrURLParseError = &ProxyError{ HTTPCode: http.StatusBadRequest, ResinError: "URL_PARSE_ERROR", Message: "Failed to parse request URL", } ErrInvalidProtocol = &ProxyError{ HTTPCode: http.StatusBadRequest, ResinError: "INVALID_PROTOCOL", Message: "Protocol must be http or https", } ErrInvalidHost = &ProxyError{ HTTPCode: http.StatusBadRequest, ResinError: "INVALID_HOST", Message: "Invalid or empty host", } ErrPlatformNotFound = &ProxyError{ HTTPCode: http.StatusNotFound, ResinError: "PLATFORM_NOT_FOUND", Message: "Platform not found", } ErrAccountRejected = &ProxyError{ HTTPCode: http.StatusForbidden, ResinError: "ACCOUNT_REJECTED", Message: "Account extraction failed and platform rejects unmatched requests", } ErrNoAvailableNodes = &ProxyError{ HTTPCode: http.StatusServiceUnavailable, ResinError: "NO_AVAILABLE_NODES", Message: "No available nodes for routing", } ErrUpstreamConnectFailed = &ProxyError{ HTTPCode: http.StatusBadGateway, ResinError: "UPSTREAM_CONNECT_FAILED", Message: "Failed to connect to upstream", } ErrUpstreamTimeout = &ProxyError{ HTTPCode: http.StatusGatewayTimeout, ResinError: "UPSTREAM_TIMEOUT", Message: "Upstream connection or response timed out", } ErrUpstreamRequestFailed = &ProxyError{ HTTPCode: http.StatusBadGateway, ResinError: "UPSTREAM_REQUEST_FAILED", Message: "Upstream request failed", } ErrInternalError = &ProxyError{ HTTPCode: http.StatusInternalServerError, ResinError: "INTERNAL_ERROR", Message: "Internal proxy error", } )
Predefined proxy errors aligned with DESIGN.md error specification.
Functions ¶
func NewCountingListener ¶
func NewCountingListener(ln net.Listener, sink MetricsEventSink) net.Listener
NewCountingListener wraps a listener with connection lifecycle tracking.
func NormalizeRulePrefix ¶
NormalizeRulePrefix canonicalizes an account-header rule prefix.
Rules:
- Trim surrounding whitespace.
- Reject empty values and values containing '?'.
- Keep "*" as wildcard.
- Lowercase only the host part before the first '/'.
- Keep path part (if any) as-is.
Types ¶
type AccountMatcher ¶
type AccountMatcher struct {
// contains filtered or unexported fields
}
AccountMatcher performs longest-prefix matching on (host, path) to find the set of header names from which to extract an account identity.
Rules are stored in a segment-based trie keyed by domain (lowercase) then path segments. The wildcard key "*" serves as a catch-all fallback.
func BuildAccountMatcher ¶
func BuildAccountMatcher(rules []model.AccountHeaderRule) *AccountMatcher
BuildAccountMatcher constructs a matcher from persisted rules.
func (*AccountMatcher) Match ¶
func (m *AccountMatcher) Match(host, path string) []string
Match returns the header names for the longest-prefix rule matching the given host and path. Returns nil if no rule matches.
func (*AccountMatcher) MatchWithPrefix ¶
func (m *AccountMatcher) MatchWithPrefix(host, path string) (string, []string)
MatchWithPrefix returns the matched url_prefix and its headers for the longest-prefix rule matching the given host/path. If no rule matches, it returns ("", nil). Wildcard fallback returns ("*", wildcardHeaders).
type AccountMatcherRuntime ¶
type AccountMatcherRuntime struct {
// contains filtered or unexported fields
}
AccountMatcherRuntime stores the current account matcher in an atomic pointer. Readers stay lock-free; updates swap in a fully built immutable matcher.
func NewAccountMatcherRuntime ¶
func NewAccountMatcherRuntime(initial *AccountMatcher) *AccountMatcherRuntime
NewAccountMatcherRuntime creates a runtime matcher store with an initial matcher. If initial is nil, it uses an empty matcher.
func (*AccountMatcherRuntime) Current ¶
func (r *AccountMatcherRuntime) Current() *AccountMatcher
Current returns the currently published matcher pointer.
func (*AccountMatcherRuntime) Match ¶
func (r *AccountMatcherRuntime) Match(host, path string) []string
Match resolves header rules using the current matcher snapshot.
func (*AccountMatcherRuntime) MatchWithPrefix ¶
func (r *AccountMatcherRuntime) MatchWithPrefix(host, path string) (string, []string)
MatchWithPrefix resolves rules using the current matcher snapshot and returns both the matched url_prefix and header list.
func (*AccountMatcherRuntime) ReplaceRules ¶
func (r *AccountMatcherRuntime) ReplaceRules(rules []model.AccountHeaderRule)
ReplaceRules rebuilds a matcher from persisted rules and atomically replaces it.
func (*AccountMatcherRuntime) Swap ¶
func (r *AccountMatcherRuntime) Swap(next *AccountMatcher)
Swap atomically replaces the current matcher. Passing nil resets to an empty matcher.
type AccountRuleMatcher ¶
AccountRuleMatcher provides longest-prefix rule matching for account headers. ReverseProxy depends on this interface to allow runtime matcher swapping.
type ConfigAwareEventEmitter ¶
type ConfigAwareEventEmitter struct {
Base EventEmitter
RequestLogEnabled func() bool
// Reverse proxy request-log detail controls (hot-reload friendly).
ReverseProxyLogDetailEnabled func() bool
ReverseProxyLogReqHeadersMaxBytes func() int
ReverseProxyLogReqBodyMaxBytes func() int
ReverseProxyLogRespHeadersMaxBytes func() int
ReverseProxyLogRespBodyMaxBytes func() int
}
ConfigAwareEventEmitter wraps another EventEmitter and gates request-log emission by a runtime flag provider (hot-reload friendly).
func (ConfigAwareEventEmitter) EmitRequestFinished ¶
func (e ConfigAwareEventEmitter) EmitRequestFinished(ev RequestFinishedEvent)
func (ConfigAwareEventEmitter) EmitRequestLog ¶
func (e ConfigAwareEventEmitter) EmitRequestLog(ev RequestLogEntry)
type ConnectionDirection ¶
type ConnectionDirection int
ConnectionDirection indicates inbound vs outbound connection flow.
const ( ConnectionInbound ConnectionDirection = iota ConnectionOutbound )
type ConnectionLifecycleEvent ¶
type ConnectionLifecycleEvent struct {
Direction ConnectionDirection
Op ConnectionOp
}
ConnectionLifecycleEvent tracks connection open/close.
type ConnectionOp ¶
type ConnectionOp int
ConnectionOp is the operation type for a connection lifecycle event.
const ( ConnectionOpen ConnectionOp = iota ConnectionClose )
type EventEmitter ¶
type EventEmitter interface {
EmitRequestFinished(RequestFinishedEvent)
EmitRequestLog(RequestLogEntry)
}
EventEmitter defines the interface for proxy-layer event emission. Covers both metrics and requestlog event paths (STAGES.md Task 8).
type ForwardProxy ¶
type ForwardProxy struct {
// contains filtered or unexported fields
}
ForwardProxy implements an HTTP forward proxy with Proxy-Authorization authentication, HTTP request forwarding, and CONNECT tunneling.
func NewForwardProxy ¶
func NewForwardProxy(cfg ForwardProxyConfig) *ForwardProxy
NewForwardProxy creates a new forward proxy handler.
func (*ForwardProxy) ServeHTTP ¶
func (p *ForwardProxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
type ForwardProxyConfig ¶
type ForwardProxyConfig struct {
ProxyToken string
AuthVersion string
Router *routing.Router
Pool outbound.PoolAccessor
Health HealthRecorder
Events EventEmitter
MetricsSink MetricsEventSink
OutboundTransport OutboundTransportConfig
TransportPool *OutboundTransportPool
}
ForwardProxyConfig holds dependencies for the forward proxy.
type HealthRecorder ¶
type HealthRecorder interface {
RecordResult(hash node.Hash, success bool)
RecordLatency(hash node.Hash, rawTarget string, latency *time.Duration)
}
HealthRecorder abstracts passive health feedback reporting. topology.GlobalNodePool satisfies this interface.
type MetricsEventSink ¶
type MetricsEventSink interface {
// OnTrafficDelta reports a global traffic byte count delta.
OnTrafficDelta(ingressBytes, egressBytes int64)
// OnConnectionLifecycle reports a connection open/close event.
OnConnectionLifecycle(direction ConnectionDirection, op ConnectionOp)
}
MetricsEventSink receives traffic and connection lifecycle events from the proxy layer. Implemented by metrics.Manager (wired in main.go). This interface is defined here (in the proxy package) to avoid an import cycle between proxy and metrics.
type NoOpEventEmitter ¶
type NoOpEventEmitter struct{}
NoOpEventEmitter is a no-op implementation used until Phase 7/8.
func (NoOpEventEmitter) EmitRequestFinished ¶
func (NoOpEventEmitter) EmitRequestFinished(RequestFinishedEvent)
func (NoOpEventEmitter) EmitRequestLog ¶
func (NoOpEventEmitter) EmitRequestLog(RequestLogEntry)
type OutboundTransportConfig ¶
type OutboundTransportPool ¶
type OutboundTransportPool struct {
// contains filtered or unexported fields
}
OutboundTransportPool manages reusable outbound HTTP transports keyed by node hash. A single instance should be shared by forward/reverse proxies so keep-alive pools are reused and can be evicted on node removal.
func NewOutboundTransportPool ¶
func NewOutboundTransportPool(cfg OutboundTransportConfig) *OutboundTransportPool
NewOutboundTransportPool creates a transport pool with normalized settings.
func (*OutboundTransportPool) CloseAll ¶
func (p *OutboundTransportPool) CloseAll()
CloseAll closes idle connections and clears all pooled transports.
func (*OutboundTransportPool) Evict ¶
func (p *OutboundTransportPool) Evict(hash node.Hash)
Evict closes idle connections for one node transport and removes it from pool.
func (*OutboundTransportPool) Get ¶
func (p *OutboundTransportPool) Get( hash node.Hash, ob adapter.Outbound, sink MetricsEventSink, ) *http.Transport
Get returns a reusable transport for the given node hash.
type PlatformLookup ¶
type PlatformLookup interface {
GetPlatform(id string) (*platform.Platform, bool)
GetPlatformByName(name string) (*platform.Platform, bool)
}
PlatformLookup provides read-only access to platforms.
type ProxyError ¶
type ProxyError struct {
HTTPCode int
ResinError string // X-Resin-Error header value
Message string // plain-text body
}
ProxyError represents a structured proxy error response.
type RequestFinishedEvent ¶
type RequestFinishedEvent struct {
PlatformID string
ProxyType ProxyType // 1=http forward, 2=reverse, 3=socks5 forward
IsConnect bool
NetOK bool
DurationNs int64
}
RequestFinishedEvent is emitted when a proxy request completes. Used by the metrics subsystem (Phase 8).
type RequestLogEntry ¶
type RequestLogEntry struct {
ID string // optional stable ID; repo generates one when empty
StartedAtNs int64 // request start time (Unix nano), used as ts_ns in DB
ProxyType ProxyType // 1=http forward, 2=reverse, 3=socks5 forward
ClientIP string
PlatformID string
PlatformName string
Account string
TargetHost string
TargetURL string
NodeHash string
NodeTag string // display tag: "<Subscription>/<Tag>" (DESIGN.md §601)
EgressIP string
DurationNs int64
NetOK bool
HTTPMethod string
HTTPStatus int
ResinError string // logical proxy error code, e.g. UPSTREAM_TIMEOUT
UpstreamStage string // where upstream/network failure happened
UpstreamErrKind string // normalized error family
UpstreamErrno string // normalized errno, when available
UpstreamErrMsg string // sanitized upstream error message
IngressBytes int64 // bytes from upstream to client (header + body)
EgressBytes int64 // bytes from client to upstream (header + body)
// Optional detail payload (mainly for reverse proxy request logging).
ReqHeaders []byte
ReqHeadersLen int
ReqHeadersTruncated bool
ReqBody []byte
ReqBodyLen int
ReqBodyTruncated bool
RespHeaders []byte
RespHeadersLen int
RespHeadersTruncated bool
RespBody []byte
RespBodyLen int
RespBodyTruncated bool
}
RequestLogEntry captures per-request details for the structured request log. Used by the requestlog subsystem (Phase 8).
type ReverseProxy ¶
type ReverseProxy struct {
// contains filtered or unexported fields
}
ReverseProxy implements an HTTP reverse proxy. Identity segment format depends on auth version: V1: /PROXY_TOKEN/Platform.Account/protocol/host/path?query LEGACY_V0: /PROXY_TOKEN/Platform:Account/protocol/host/path?query
func NewReverseProxy ¶
func NewReverseProxy(cfg ReverseProxyConfig) *ReverseProxy
NewReverseProxy creates a new reverse proxy handler.
func (*ReverseProxy) ServeHTTP ¶
func (p *ReverseProxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
type ReverseProxyConfig ¶
type ReverseProxyConfig struct {
ProxyToken string
AuthVersion string
Router *routing.Router
Pool outbound.PoolAccessor
PlatformLookup PlatformLookup
Health HealthRecorder
Matcher AccountRuleMatcher
Events EventEmitter
MetricsSink MetricsEventSink
OutboundTransport OutboundTransportConfig
TransportPool *OutboundTransportPool
}
ReverseProxyConfig holds dependencies for the reverse proxy.
type Socks5Inbound ¶ added in v1.1.0
type Socks5Inbound struct {
// contains filtered or unexported fields
}
Socks5Inbound implements SOCKS5 CONNECT over a raw TCP connection.
func NewSocks5Inbound ¶ added in v1.1.0
func NewSocks5Inbound(cfg Socks5InboundConfig) *Socks5Inbound
NewSocks5Inbound creates a new SOCKS5 inbound handler.
func (*Socks5Inbound) ServeConn ¶ added in v1.1.0
func (s *Socks5Inbound) ServeConn(conn net.Conn)
ServeConn handles a SOCKS5 session on an already-accepted TCP connection.
func (*Socks5Inbound) ServeConnContext ¶ added in v1.1.0
func (s *Socks5Inbound) ServeConnContext(baseCtx context.Context, conn net.Conn)
ServeConnContext handles a SOCKS5 session with a caller-provided base context.
type Socks5InboundConfig ¶ added in v1.1.0
type Socks5InboundConfig struct {
ProxyToken string
AuthVersion string
Router *routing.Router
Pool outbound.PoolAccessor
Health HealthRecorder
Events EventEmitter
MetricsSink MetricsEventSink
}
Socks5InboundConfig holds dependencies for the SOCKS5 inbound handler.
Source Files
¶
- account_matcher.go
- account_matcher_runtime.go
- counting_conn.go
- error_detail.go
- errors.go
- events.go
- forward.go
- half_close.go
- health.go
- identity_legacy.go
- identity_v1.go
- request_lifecycle.go
- request_log_capture.go
- reverse.go
- reverse_latency.go
- route_outbound.go
- rule_prefix.go
- socks5.go
- tls_latency_conn.go
- transport.go
- tunnel.go
- upstream_request_trace.go