Documentation
¶
Index ¶
- Constants
- func NewSmartHTTPTransport(logWriter io.Writer, domains ...string) (*http.Transport, error)
- func NewSmartHTTPTransportWithConfig(logWriter io.Writer, config []byte, stream transport.StreamDialer, ...) (*http.Transport, error)
- func NewSmartHTTPTransportWithDialer(logWriter io.Writer, stream transport.StreamDialer, ...) (*http.Transport, error)
- type Kindling
- type Option
- func WithAMPCache(c amp.Client) Option
- func WithDNSTunnel(d dnstt.DNSTT) Option
- func WithDomainFronting(c *domainfront.Client) Option
- func WithLogWriter(w io.Writer) Option
- func WithPacketDialer(d transport.PacketDialer) Option
- func WithPanicListener(fn func(string)) Option
- func WithProxyless(domains ...string) Option
- func WithSmartDialerConfig(cfg []byte) Option
- func WithStreamDialer(d transport.StreamDialer) Option
- func WithTransport(t Transport) Option
- type Transport
- type TransportName
Constants ¶
const IdempotentHeader = "X-Kindling-Idempotent"
IdempotentHeader is an opt-in marker callers can set on a request to declare it idempotent regardless of HTTP method. raceTransport will then apply the same retry-across-transports behavior to that request that it normally reserves for GET/HEAD: transport-level errors and 5xx responses fall back to the next connected transport.
Use this for POST endpoints that are semantically read-only or otherwise safe to replay (e.g., a config-fetch endpoint that returns the same payload regardless of how many times it's called). The header is harmless to leak to the origin — kindling doesn't strip it before sending.
Any non-empty value enables the override. Recommended value is "1".
Variables ¶
This section is empty.
Functions ¶
func NewSmartHTTPTransport ¶
NewSmartHTTPTransport creates an http.Transport using the Outline SDK smart dialer for the given domains. This is a standalone utility that does not require a Kindling instance. The smart dialer's connection attempts go via the stdlib net.Dialer; use NewSmartHTTPTransportWithDialer when those attempts need to bypass an active VPN TUN.
func NewSmartHTTPTransportWithConfig ¶
func NewSmartHTTPTransportWithConfig( logWriter io.Writer, config []byte, stream transport.StreamDialer, packet transport.PacketDialer, domains ...string, ) (*http.Transport, error)
NewSmartHTTPTransportWithConfig is NewSmartHTTPTransportWithDialer plus an override for the YAML strategy config. nil reads the embedded default, which lists `system: {}` first under DNS — incompatible with non-default stream dialers, since outline-sdk's smart strategy then requires the base dialer to be *transport.TCPDialer. Pass a config that omits `system: {}` (using DoH/DoT entries) to route every probe through your stream dialer. A non-nil but empty config is rejected, matching WithSmartDialerConfig.
func NewSmartHTTPTransportWithDialer ¶
func NewSmartHTTPTransportWithDialer( logWriter io.Writer, stream transport.StreamDialer, packet transport.PacketDialer, domains ...string, ) (*http.Transport, error)
NewSmartHTTPTransportWithDialer is NewSmartHTTPTransport plus an override for the base stream / packet dialers the smart strategy probes against. nil dialers fall back to the stdlib-backed defaults. The motivating case is radiance's bypass dialer, which routes connection attempts around its own VPN TUN so kindling traffic doesn't loop through the tunnel.
Types ¶
type Kindling ¶
type Kindling interface {
// NewHTTPClient returns an HTTP client whose transport races all configured
// circumvention transports in parallel.
NewHTTPClient() *http.Client
// ReplaceTransport swaps the round-tripper generator for the named transport,
// preserving its MaxLength and IsStreamable properties.
ReplaceTransport(name TransportName, rt func(ctx context.Context, addr string) (http.RoundTripper, error)) error
}
Kindling creates HTTP clients that race requests across multiple censorship circumvention transports, returning the first successful response.
func NewKindling ¶
NewKindling creates a Kindling instance with the given application name and options. Returns an error if any option fails synchronously (e.g. a nil transport argument). Deferred initialization failures (such as a failed smart dialer in WithProxyless) are logged as warnings and are only fatal when they leave Kindling with no usable transports.
type Option ¶
type Option func(*kindling) error
Option configures a Kindling instance. Options are applied in the order provided — specify WithLogWriter first to capture logs from subsequent transport initialization.
func WithAMPCache ¶
WithAMPCache adds AMP caching via the provided amp.Client. AMP has a 6000-byte request body limit and does not support streaming.
func WithDNSTunnel ¶
WithDNSTunnel adds DNS tunneling via the provided dnstt.DNSTT. DNS tunneling is raced only as a last resort: it keeps working under heavy censorship but is slow and low-throughput, so the race transport reaches for it only after every faster transport has failed to produce a usable response.
func WithDomainFronting ¶
func WithDomainFronting(c *domainfront.Client) Option
WithDomainFronting adds domain fronting via the provided domainfront.Client. Each race attempt obtains a pre-connected one-shot RoundTripper via NewConnectedRoundTripper, so the race transport blocks on a real TLS handshake to a working front (not on a cached wrapper that "connects" instantly and always wins the race).
func WithLogWriter ¶
WithLogWriter sets the log output destination. By default, logs go to os.Stdout. Specify this first to capture initialization logs from other options like WithProxyless.
func WithPacketDialer ¶
func WithPacketDialer(d transport.PacketDialer) Option
WithPacketDialer is the UDP counterpart to WithStreamDialer. The smart strategy uses UDP for DNS probes that drive strategy selection.
func WithPanicListener ¶
WithPanicListener sets a callback invoked when a transport goroutine panics.
func WithProxyless ¶
WithProxyless enables direct access using the Outline SDK smart dialer, which bypasses DNS-based and SNI-based blocking. The smart dialer is constructed after every other option has run, so WithStreamDialer / WithPacketDialer take effect regardless of the order callers pass them to NewKindling.
func WithSmartDialerConfig ¶
WithSmartDialerConfig replaces the embedded smart_dialer_config.yml that drives the Outline SDK strategy probe. Callers that pass a custom StreamDialer typically need this too: the default config lists `system: {}` first under DNS, which makes the strategy fall back to the OS resolver — and outline-sdk then requires the base StreamDialer to be exactly *transport.TCPDialer, rejecting any other type. Supplying a config that omits `system: {}` (using DoH/DoT entries instead) routes every probe through the custom dialer.
func WithStreamDialer ¶
func WithStreamDialer(d transport.StreamDialer) Option
WithStreamDialer overrides the TCP dialer used by smart-dialer-based transports (WithProxyless). When unset, the smart dialer uses Outline SDK's default transport.TCPDialer, which dials via the stdlib net.Dialer and so follows the host's routing table — sending packets through any active VPN TUN. Callers that need their connection attempts to bypass a VPN tunnel they themselves serve (radiance is the motivating case) should pass an alternative here.
func WithTransport ¶
WithTransport adds a custom Transport implementation.
type Transport ¶
type Transport interface {
// NewRoundTripper creates a pre-connected http.RoundTripper. Implementations
// should complete the connection before returning so that the race transport
// can try requests serially without paying connection latency.
NewRoundTripper(ctx context.Context, addr string) (http.RoundTripper, error)
// MaxLength returns the maximum request body size this transport supports.
// Zero means no limit.
MaxLength() int
// IsStreamable reports whether this transport supports streaming responses
// (e.g. text/event-stream).
IsStreamable() bool
// Name identifies this transport for logging and debugging.
Name() string
// RequestTimeout returns the maximum time a single request is allowed to
// spend on this transport. Zero means the race transport picks a default
// (80 s for requests without a body, 3 min for requests with a body).
RequestTimeout() time.Duration
}
Transport defines a censorship circumvention transport that can be used by Kindling.
type TransportName ¶
type TransportName string
TransportName identifies a built-in transport. Custom transports added via WithTransport may use any string for their Name(); the constants below cover the names assigned to the transports configured by WithDomainFronting, WithDNSTunnel, WithAMPCache, and WithProxyless.
const ( TransportDomainfront TransportName = "domainfront" TransportDNSTunnel TransportName = "dnstt" TransportAMP TransportName = "amp" TransportSmart TransportName = "smart" )