kindling

package module
v0.0.0-...-df15c15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2026 License: Apache-2.0 Imports: 19 Imported by: 4

README

Kindling

Library using a series of redundant techniques to send and receive small amounts of data through censoring firewalls. This is ideal for accessing things like configuration files during the bootrapping phase as circumvention tools first start. Kindling is intended to be used by any circumvention tool written in Go that need to reliably fetch configuration data on startup. It is also designed to be easy for any developer to add a new technique that other tools may benefit from.

The techniques integrated include:

  1. Domain fronting.
  2. Proxyless dialing from the Outline SDK that generally bypasses DNS-based and SNI-based blocking (i.e. works particularly well for broadly used services with a lot of IPs that are not IP-blocked)
  3. DNS tunneling via DNSTT
  4. AMP caching also via David Fifield with a Lantern implementation.

The idea is to continually add more techniques as they become available such that all tools have access to the most robust library possible for getting on the network quickly and reliably.

Example

k := kindling.NewKindling(
	"myapp",
    kindling.WithDomainFronting("https://raw.githubusercontent.com/getlantern/fronted/refs/heads/main/fronted.yaml.gz"),
    kindling.WithProxyless("raw.githubusercontent.com"),
    kindling.WithDNSTunnel(newDNSTT()),
	kindling.WithAMPCache(ampClient),
)
httpClient := k.NewHTTPClient()

You can also dynamically add transports that provide a simple Transport interface:

// Transport provides the basic interface that any transport must implement to be used by Kindling.
type Transport interface {
	// NewRoundTripper creates a new http.RoundTripper that uses this transport. As much as possible
	// the RoundTripper should be pre-connected when it is returned, as otherwise it can take too
	// much time away from other transports. In other words, Kindling parallelizes the connection
	// of the transports, but the actual sending of the request is done serially to avoid
	// issues with non-idempotent requests.
	NewRoundTripper(ctx context.Context, addr string) (http.RoundTripper, error)

	// MaxLength returns the maximum length of data that can be sent using this transport, if any.
	// A value of 0 means there is no limit.
	MaxLength() int

	// Name returns the name of the transport for logging and debugging purposes.
	Name() string
}

You can then use this as follows:

k := kindling.NewKindling(
	"myapp",
    kindling.WithTransport(myCoolTransport),
	kindling.WithTransport(myCoolerTransport),
)
httpClient := k.NewHTTPClient()

I want to add fuel to the fire (aka a new bootrapping technique!). What do I do?

All you really need to do is to return an http.RoundTripper from whatever library you're adding. Then you simply need to add a method in kindling.go to allow callers to configure the new method. For DNS tunneling, for example, that method is as follows:

func WithDNSTunnel(d dnstt.DNSTT) Option {
	return newOption(func(k *kindling) {
		log.Info("Setting DNS tunnel")
		if d == nil {
			log.Error("DNSTT instance is nil")
			return
		}
		k.roundTripperGenerators = append(k.roundTripperGenerators, namedDialer("dnstt", d.NewRoundTripper))
	})
}

It is also important to document any steps that kindling users must take in order to make the technique operational, if any. Does it require server-side components, for example?

Otherwise, just open a pull request, and we'll take it for a spin and will integrate it as soon as possible.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewSmartHTTPTransport

func NewSmartHTTPTransport(logWriter io.Writer, domains ...string) (*http.Transport, error)

NewSmartHTTPTransport creates a new HTTP transport that uses the Outline smart dialer to dial to the specified domains.

Types

type Kindling

type Kindling interface {
	// NewHTTPClient returns a new HTTP client that is configured to use kindling.
	NewHTTPClient() *http.Client
	// ReplaceTransport replaces an existing transport RoundTripper generator with the provided one.
	ReplaceTransport(name string, rt func(ctx context.Context, addr string) (http.RoundTripper, error)) error
}

Kindling is the interface that wraps the basic Dial and DialContext methods for control plane traffic.

func NewKindling

func NewKindling(name string, options ...Option) Kindling

NewKindling returns a new Kindling with the specified name of your tool and the options to use for accessing control plane data.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option is a functional option type that allows us to configure the Client.

func WithAMPCache

func WithAMPCache(c amp.Client) Option

WithAMPCache uses the AMP cache for making requests. It adds an 'amp' round tripper from the provided amp.Client.

func WithDNSTunnel

func WithDNSTunnel(d dnstt.DNSTT) Option

WithDNSTunnel is a functional option that sets up a DNS tunnel for kindling using the provided dnstt.DNSTT instance

func WithDomainFronting

func WithDomainFronting(f fronted.Fronted) Option

WithDomainFronting is a functional option that sets up domain fronting for kindling using the provided fronted.Fronted instance from https://github.com/getlantern/fronted.

func WithLogWriter

func WithLogWriter(w io.Writer) Option

WithLogWriter is a functional option that sets the log writer for the Kindling. By default, the log writer is set to os.Stdout. This should be the first option to be applied to the Kindling to ensure that all logs are captured.

func WithPanicListener

func WithPanicListener(panicListener func(string)) Option

WithPanicListener is a functional option that sets a panic listener that should be notified whenever any goroutine panics. We set this with a higher priority so that it is set before any other options that may depend on it.

func WithProxyless

func WithProxyless(domains ...string) Option

WithProxyless is a functional option that enables proxyless mode for the Kindling such that it accesses the control plane directly using a variety of proxyless techniques.

func WithTransport

func WithTransport(transport Transport) Option

WithTransport allows users to add any transport matching the minimal Transport interface.

type Transport

type Transport interface {
	// NewRoundTripper creates a new http.RoundTripper that uses this transport. As much as possible
	// the RoundTripper should be pre-connected when it is returned, as otherwise it can take too
	// much time away from other transports. In other words, Kindling parallelizes the connection
	// of the transports, but the actual sending of the request is done serially to avoid
	// issues with non-idempotent requests.
	NewRoundTripper(ctx context.Context, addr string) (http.RoundTripper, error)

	// MaxLength returns the maximum length of data that can be sent using this transport, if any.
	// A value of 0 means there is no limit.
	MaxLength() int

	// IsStreamable returns if the transport support streaming
	IsStreamable() bool

	// Name returns the name of the transport for logging and debugging purposes.
	Name() string
}

Transport provides the basic interface that any transport must implement to be used by Kindling.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL