Documentation
¶
Overview ¶
Package proxy implements the credential-injecting MITM HTTPS proxy used by runclaude. It is intentionally self-contained so external consumers (e.g. a Docker-sidecar binary) can reuse it without pulling in any of the Linux sandbox plumbing.
Index ¶
- Variables
- func BedrockRegion(host string) string
- func HandleDNSQuery(buf []byte, allowed []string, logger *log.Logger) []byte
- func InjectBedrock(host string, r *http.Request, provider aws.CredentialsProvider, ...)
- func IsBedrockHost(host string) bool
- func LoadOrCreateCA(dir string) (*tls.Certificate, error)
- func MatchDomain(host string, patterns []string) bool
- func NewMitmReverseProxy(host string, target *url.URL, inject func(string, *http.Request), ...) *httputil.ReverseProxy
- func OpenLogger(logPath string) (*log.Logger, error)
- func Serve(p *Setup, ln net.Listener, logger *log.Logger)
- func ServeDNSTCP(ln net.Listener, allowed []string, logger *log.Logger)
- func ServeDNSUDP(conn net.PacketConn, allowed []string, logger *log.Logger)
- func StripHopByHopHeaders(h http.Header)
- func WriteBundle(caCertPEM []byte, dst string) error
- type LeafCache
- type Setup
Constants ¶
This section is empty.
Variables ¶
var DefaultAllowedDomains = []string{
"api.anthropic.com",
"github.com", "*.github.com",
"codeload.github.com",
"release-assets.githubusercontent.com",
"registry.npmjs.org",
"pypi.org", "*.pypi.org", "files.pythonhosted.org",
"crates.io", "static.crates.io",
"proxy.golang.org", "sum.golang.org", "go.dev",
"proxy.golang.org", "sum.golang.org", "go.dev", "*.go.dev",
"dl.google.com", "storage.googleapis.com",
"*.bazel.build", "*.azul.com", "*.maven.org",
"bcr.cloudflaremirrors.com",
}
DefaultAllowedDomains is the set of egress endpoints runclaude permits by default when restricting the network. Callers may extend or replace this list.
Functions ¶
func BedrockRegion ¶
BedrockRegion extracts the AWS region from a Bedrock Runtime hostname, or returns "" if host is not a Bedrock host.
func HandleDNSQuery ¶
HandleDNSQuery parses a single DNS request and returns the wire-format response. Hosts outside allowed receive NXDOMAIN; QTYPEs other than A/AAAA receive NOTIMP.
func InjectBedrock ¶
func InjectBedrock(host string, r *http.Request, provider aws.CredentialsProvider, signer *v4.Signer, logger *log.Logger)
InjectBedrock re-signs an in-flight request using AWS credentials retrieved from provider. The client (e.g. claude code's @aws-sdk/client-bedrock-runtime) may have signed with stub credentials; this strips that signature and recomputes SigV4 against the real credentials. Body is unchanged.
func IsBedrockHost ¶
IsBedrockHost reports whether host is a Bedrock Runtime endpoint (bedrock-runtime.<region>.amazonaws.com).
func LoadOrCreateCA ¶
func LoadOrCreateCA(dir string) (*tls.Certificate, error)
LoadOrCreateCA returns a long-lived self-signed CA persisted in dir. If ca.crt/ca.key are already present they are loaded; otherwise a fresh 3072-bit RSA key + 10-year cert is generated and written with 0600/0644 perms.
func MatchDomain ¶
MatchDomain reports whether host matches any of patterns.
- exact "api.anthropic.com" matches only that hostname
- leading "*.github.com" matches "github.com" and any subdomain at any depth (legacy form)
- mid-label "bedrock-runtime.*.amazonaws.com" each "*" label matches exactly one DNS label
func NewMitmReverseProxy ¶
func NewMitmReverseProxy(host string, target *url.URL, inject func(string, *http.Request), transport http.RoundTripper, logger *log.Logger) *httputil.ReverseProxy
NewMitmReverseProxy builds the reverse proxy used by the MITM path. The Director here is the single place where runclaude rewrites outgoing requests; tests exercise it directly to verify no header drift.
func OpenLogger ¶
OpenLogger opens a proxy log file at logPath. If logPath is empty, the returned logger discards everything.
func Serve ¶
Serve runs the proxy on ln until ln is closed. Connections to hosts matching p.Mitm are TLS-intercepted; hosts matching p.Allowed are passed through; everything else returns 403.
func ServeDNSTCP ¶
ServeDNSTCP accepts DNS-over-TCP connections from ln and serves them until ln is closed.
func ServeDNSUDP ¶
func ServeDNSUDP(conn net.PacketConn, allowed []string, logger *log.Logger)
ServeDNSUDP reads queries from conn and writes responses until conn is closed.
func StripHopByHopHeaders ¶
StripHopByHopHeaders removes RFC 7230 §6.1 hop-by-hop headers from h.
func WriteBundle ¶
WriteBundle writes a CA bundle to dst that concatenates the system trust store (first one of the common Linux locations that exists) with the caller-supplied PEM. Useful for handing a single trust file to a sandboxed process whose libraries each expect their own bundle path.
Types ¶
type LeafCache ¶
type LeafCache struct {
// contains filtered or unexported fields
}
LeafCache mints and memoizes per-hostname leaf certificates signed by a long-lived CA. The cache is concurrency-safe.
func NewLeafCache ¶
func NewLeafCache(ca *tls.Certificate) *LeafCache
NewLeafCache returns an empty LeafCache that signs leaves with ca.
type Setup ¶
type Setup struct {
// Allowed lists hostnames that may be reached via CONNECT or plain HTTP
// without TLS interception.
Allowed []string
// Mitm lists hostnames whose TLS connections will be terminated with a
// leaf cert from Leaves and re-issued upstream after Inject runs.
Mitm []string
// Leaves mints the server certificates used for intercepted hosts. Must
// be non-nil whenever Mitm is non-empty.
Leaves *LeafCache
// Inject rewrites the outgoing request — typically swapping stub
// credentials for real ones. Required.
Inject func(host string, r *http.Request)
// Upstream optionally overrides the upstream URL for a MITM host. Empty
// or missing entries fall back to "https://<host>".
Upstream map[string]string
// Transports optionally installs a per-host RoundTripper around the
// upstream call (e.g. to handle 401-driven OAuth refresh).
Transports map[string]http.RoundTripper
}
Setup configures the proxy. Inject is called with the destination hostname and the in-flight request before it is forwarded upstream; this is where credential rewriting happens. Upstream and Transports are optional overrides keyed by hostname.