Documentation
¶
Overview ¶
Package httpkit carries the HTTP conveniences the hand-rolled provider clients (qwen, minimax, kimi, bytedance) use: a tuned connection-pooling transport, a bounded retry RoundTripper for transient failures, an option-driven client builder that hardens HTTP/1.1, HTTP/2, or HTTP/3, and the host-side sandbox enforcement proxy (netproxy.go) that turns sandbox.NetAllowList / sandbox.NetProxy into a single enforced egress for the bwrap backend.
This file carries the sandbox enforcement proxy (host side) that turns sandbox.NetAllowList / sandbox.NetProxy into a single enforced network path. It runs on the host (outside any sandbox) and is the sandboxed child's only network egress. It supports two listening surfaces:
- unix socket (default): the bwrap backend bind-mounts the socket into the sandbox, because its netns hides the host loopback and a bridge process pipes the netns loopback to the socket;
- TCP loopback (ProxyConfig.TCPLoopback): the seatbelt backend, whose child shares the host network stack and dials 127.0.0.1:<port> directly under an SBPL loopback-only rule.
It is part of httpkit because the proxy is plain HTTP machinery: an http.Handler with allow-list / upstream policy over a listener.
Trust boundary: the proxy is spawned by the host application and is the sandboxed child's only network egress. A compromised child can reach exactly the destinations the proxy's policy permits — that is the configured policy, not a sandbox escape. The proxy must therefore be pinned and audited like any trust anchor. When MITM is enabled, the temporary CA becomes an additional trust anchor and must be treated with the same care.
Index ¶
- Variables
- func NewClient(options ...Option) *http.Client
- func NewRoundTripper(options ...Option) http.RoundTripper
- func RetryCountOf(response *http.Response) int
- type Config
- type Matcher
- type Option
- func WithConnectionPool(maxIdleConns, maxIdleConnsPerHost int, idleConnTimeout time.Duration) Option
- func WithHTTP1() Option
- func WithHTTP2() Option
- func WithHTTP2Timeouts(pingInterval, pingTimeout, writeByteTimeout time.Duration) Option
- func WithHTTP3() Option
- func WithProtocol(protocol Protocol) Option
- func WithQUICTimeouts(handshakeIdleTimeout, maxIdleTimeout, keepAlivePeriod time.Duration) Option
- func WithResponseHeaderTimeout(timeout time.Duration) Option
- func WithRetry(config RetryConfig) Option
- func WithRetryAttempts(maxAttempts int) Option
- func WithTLSClientConfig(config *tls.Config) Option
- func WithTimeout(timeout time.Duration) Option
- func WithoutRetry() Option
- type Protocol
- type Proxy
- type ProxyConfig
- type ProxyDecision
- type RetryConfig
Constants ¶
This section is empty.
Variables ¶
var DefaultRetry = RetryConfig{ MaxAttempts: 3, BaseDelay: 200 * time.Millisecond, MaxDelay: 2 * time.Second, }
DefaultRetry retries transient failures twice after the first attempt with a 200ms-seeded exponential backoff.
Functions ¶
func NewClient ¶
NewClient builds an http.Client over NewRoundTripper with the configured whole-request timeout.
func NewRoundTripper ¶
func NewRoundTripper(options ...Option) http.RoundTripper
NewRoundTripper builds the hardened base transport per Config and wraps it with the retry transport unless disabled.
func RetryCountOf ¶
RetryCountOf reports the wire attempts that produced a response. It returns 0 for responses the retry transport did not stamp.
Types ¶
type Config ¶
type Config struct {
Protocol Protocol
// ClientTimeout bounds the whole request (http.Client.Timeout).
ClientTimeout time.Duration
// TLSClientConfig is used for TLS dialing. Nil uses system roots.
TLSClientConfig *tls.Config
// ResponseHeaderTimeout bounds the wait for HTTP/1.1 response headers.
ResponseHeaderTimeout time.Duration
// HTTP/2 health checks.
PingInterval time.Duration // quiet-connection PING cadence
PingTimeout time.Duration // close if a PING goes unanswered
WriteByteTimeout time.Duration // close if the write path blocks
// HTTP/3 (QUIC) connection timeouts.
QUICHandshakeIdleTimeout time.Duration
QUICMaxIdleTimeout time.Duration
QUICKeepAlivePeriod time.Duration
// Connection pooling (HTTP/1.1).
MaxIdleConns int
MaxIdleConnsPerHost int
IdleConnTimeout time.Duration
// Retry wraps the base transport; disabled with WithoutRetry.
Retry RetryConfig
RetryEnabled bool
}
Config carries every knob for NewRoundTripper / NewClient. Zero values select the defaults below.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the recommended hardened defaults.
type Matcher ¶ added in v0.5.5
type Matcher struct {
// contains filtered or unexported fields
}
Matcher evaluates sandbox.NetPolicy rules against a destination. Rules are compiled once at construction: hostnames are normalized (lowercase, trailing dot removed, IDNA → punycode) and IP/CIDR entries are parsed so Match / MatchIP stay pure and IO-free.
Semantics:
- "example.com": the bare domain and every subdomain (domain-and-descendants, matching the legacy AllowHosts behaviour).
- "*.example.com": subdomains only, any depth; never the bare domain.
- "1.2.3.4" / "10.0.0.0/8": IP / CIDR, evaluated by MatchIP against locally resolved addresses.
- Deny rules are evaluated first across the whole rule set; a single deny match wins over any allow.
- Port 0 matches any port.
AllowHosts is compiled as trailing allow rules, so explicit deny rules always take precedence over the legacy allow-list.
func NewMatcher ¶ added in v0.5.5
NewMatcher compiles policy into a Matcher. The policy should already have passed NetPolicy.Validate; this constructor re-checks the rule forms it needs and returns Validation errors for malformed hosts.
func (*Matcher) HasIPRules ¶ added in v0.5.5
HasIPRules reports whether any rule needs local DNS resolution (exact IP or CIDR entries).
type Option ¶
type Option func(*Config)
Option mutates a Config.
func WithConnectionPool ¶
func WithConnectionPool(maxIdleConns, maxIdleConnsPerHost int, idleConnTimeout time.Duration) Option
WithConnectionPool tunes HTTP/1.1 keep-alive pooling.
func WithHTTP2Timeouts ¶
WithHTTP2Timeouts sets the HTTP/2 health-check knobs.
func WithProtocol ¶
func WithQUICTimeouts ¶
WithQUICTimeouts sets the HTTP/3 connection timeouts: QUIC handshake, connection idle timeout, and keep-alive period for dead-peer detection.
func WithRetry ¶
func WithRetry(config RetryConfig) Option
func WithRetryAttempts ¶
WithRetryAttempts sets the total wire attempts including the first, keeping the default backoff curve. Zero or negative disables transport retries so an outer retry owner (route.Router) controls the full budget.
func WithTLSClientConfig ¶
WithTLSClientConfig supplies the TLS configuration used for dialing (custom CA roots, client certificates, server name overrides).
func WithTimeout ¶
func WithoutRetry ¶
func WithoutRetry() Option
type Protocol ¶
type Protocol int
Protocol selects the transport family built by NewRoundTripper.
const ( // ProtocolHTTP1 is the default: HTTP/1.1 with ResponseHeaderTimeout, // so a stalled connection is bounded and retried on a fresh one. ProtocolHTTP1 Protocol = iota // ProtocolHTTP2 keeps multiplexing and bounds the write path with // periodic PING health checks and WriteByteTimeout. ProtocolHTTP2 // ProtocolHTTP3 runs HTTP over QUIC (UDP). Streams are independent at // the transport level and QUIC idle timeouts detect dead peers. ProtocolHTTP3 )
type Proxy ¶
type Proxy struct {
// contains filtered or unexported fields
}
Proxy is a host-side enforcement proxy listening on a unix socket (default) or TCP loopback (ProxyConfig.TCPLoopback). Create it with Start and stop it with Close.
func Start ¶
func Start(cfg ProxyConfig) (*Proxy, error)
Start serves the enforcement proxy in the background and returns immediately. With ProxyConfig.TCPLoopback it binds an ephemeral loopback TCP port (Addr reports it); otherwise it binds a unix socket in a fresh per-run temp directory (mode 0600) whose path is available via SocketPath for bind-mounting into a sandbox.
func (*Proxy) Addr ¶
Addr returns the bound listener address. For a TCP-loopback proxy this is the 127.0.0.1:<port> the sandboxed child must be allowed to dial; for a unix-socket proxy it is the socket path address.
func (*Proxy) CAPEM ¶ added in v0.5.5
CAPEM returns the temporary MITM root CA in PEM form, for bundle injection into the sandbox. Nil when MITM is disabled.
func (*Proxy) Close ¶
Close stops the server, closes the listener, and removes the temp directory (including the socket file) when one was created.
func (*Proxy) ServeHTTP ¶
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler for both HTTP absolute-form requests and CONNECT tunnels.
func (*Proxy) SocketPath ¶
SocketPath returns the unix socket path to bind into the sandbox. It is empty when the proxy was started with TCPLoopback.
type ProxyConfig ¶
type ProxyConfig struct {
// Mode is sandbox.NetAllowList or sandbox.NetProxy.
Mode sandbox.NetMode
// AllowHosts is the deprecated allow-list: hostname suffixes and
// exact IP literals. Compiled as trailing allow rules (see
// Matcher); explicit Rules deny rules always win.
AllowHosts []string
// Rules are explicit host/port allow or deny rules. In
// NetAllowList mode they define what is reachable; in NetProxy
// mode deny rules override the upstream and everything else is
// delegated to the upstream.
Rules []sandbox.NetRule
// Upstream is the proxy-mode upstream URL: "http://host:port" or
// "socks5://[user:pass@]host:port". Ignored in allow-list mode.
Upstream string
// TCPLoopback binds 127.0.0.1:0 (an ephemeral loopback TCP port)
// instead of a unix socket. The seatbelt backend uses this because
// its child shares the host network stack and reaches the proxy
// through the single SBPL-allowed loopback port. The bwrap backend
// leaves it false and uses the unix socket for its bridge.
TCPLoopback bool
// MITM enables TLS termination for CONNECT tunnels (opt-in).
MITM *sandbox.MITMPolicy
// OnDecision receives one audit record per allow/deny decision.
// It must not block the proxy; keep it fast and non-throwing.
OnDecision func(ProxyDecision)
// Hooks observe/block traffic. OnConnect applies to every CONNECT;
// OnRequest / OnResponse run only on MITM-decrypted traffic.
Hooks mitm.ProxyHooks
// OutboundRoots overrides the roots used to verify the real
// target's TLS certificate during MITM. Nil means system roots.
OutboundRoots *x509.CertPool
}
ProxyConfig configures one enforcement proxy instance. It is named ProxyConfig (not Config) because httpkit already owns Config for the transport builder.
type ProxyDecision ¶ added in v0.5.5
type ProxyDecision struct {
Host string
Port int
Action sandbox.NetAction
Mode sandbox.NetMode
Rule string
}
ProxyDecision is one audit record: which destination was decided, with which action, and which rule ("" = mode default) decided it.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the total number of tries including the first.
MaxAttempts int
// BaseDelay seeds the exponential backoff.
BaseDelay time.Duration
// MaxDelay caps one backoff sleep (a Retry-After hint may exceed it).
MaxDelay time.Duration
}
RetryConfig bounds the retry behaviour.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package mitm implements opt-in TLS termination for the sandbox enforcement proxy: a per-run temporary CA signs leaf certificates for CONNECT hosts, the proxy terminates TLS with the child, applies hooks, and re-establishes TLS to the real target.
|
Package mitm implements opt-in TLS termination for the sandbox enforcement proxy: a per-run temporary CA signs leaf certificates for CONNECT hosts, the proxy terminates TLS with the child, applies hooks, and re-establishes TLS to the real target. |