ctrld

package module
v1.2.1 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2023 License: MIT Imports: 30 Imported by: 0

README

ctrld

Test Go Reference Go Report Card

A highly configurable DNS forwarding proxy with support for:

  • Multiple listeners for incoming queries
  • Multiple upstreams with fallbacks
  • Multiple network policy driven DNS query steering
  • Policy driven domain based "split horizon" DNS with wildcard support

TLDR

Proxy legacy DNS traffic to secure DNS upstreams in highly configurable ways.

All DNS protocols are supported, including:

  • UDP 53
  • DNS-over-HTTPS
  • DNS-over-TLS
  • DNS-over-HTTP/3 (DOH3)
  • DNS-over-QUIC

Use Cases

  1. Use secure DNS protocols on networks and devices that don't natively support them (legacy routers, legacy OSes, TVs, smart toasters).
  2. Create source IP based DNS routing policies with variable secure DNS upstreams. Subnet 1 (admin) uses upstream resolver A, while Subnet 2 (employee) uses upstream resolver B.
  3. Create destination IP based DNS routing policies with variable secure DNS upstreams. Listener 1 uses upstream resolver C, while Listener 2 uses upstream resolver D.
  4. Create domain level "split horizon" DNS routing policies to send internal domains (*.company.int) to a local DNS server, while everything else goes to another upstream.

OS Support

  • Windows (386, amd64, arm)
  • Mac (amd64, arm64)
  • Linux (386, amd64, arm, mips)
  • Common routers (See Router Mode below)

Install

There are several ways to download and install `ctrld.

Quick Install

The simplest way to download and install ctrld is to use the following installer command on any UNIX-like platform:

sh -c 'sh -c "$(curl -sL https://api.controld.com/dl)"'

Windows user and prefer Powershell (who doesn't)? No problem, execute this command instead in administrative cmd:

powershell -Command "(Invoke-WebRequest -Uri 'https://api.controld.com/dl' -UseBasicParsing).Content | Set-Content 'ctrld_install.bat'" && ctrld_install.bat

Download Manually

Alternatively, if you know what you're doing you can download pre-compiled binaries from the Releases section for the appropriate platform.

Build

Lastly, you can build ctrld from source which requires go1.19+:

$ go build ./cmd/ctrld

or

$ go install github.com/Control-D-Inc/ctrld/cmd/ctrld@latest

Usage

The cli is self documenting, so free free to run --help on any sub-command to get specific usages.

Arguments

        __         .__       .___
  _____/  |________|  |    __| _/
_/ ___\   __\_  __ \  |   / __ |
\  \___|  |  |  | \/  |__/ /_/ |
 \___  >__|  |__|  |____/\____ |
     \/ dns forwarding proxy  \/

Usage:
  ctrld [command]

Available Commands:
  run         Run the DNS proxy server
  service     Manage ctrld service
  start       Quick start service and configure DNS on interface
  stop        Quick stop service and remove DNS from interface
  setup       Auto-setup Control D on a router.

Supported platforms:

    ₒ ddwrt
    ₒ merlin
    ₒ openwrt
    ₒ ubios
    ₒ auto - detect the platform you are running on


Flags:
  -h, --help            help for ctrld
  -s, --silent          do not write any log output
  -v, --verbose count   verbose log output, "-v" basic logging, "-vv" debug level logging
      --version         version for ctrld

Use "ctrld [command] --help" for more information about a command.

Basic Run Mode

To start the server with default configuration, simply run: ./ctrld run. This will create a generic ctrld.toml file in the working directory and start the application in foreground.

  1. Start the server
$ sudo ./ctrld run
  1. Run a test query using a DNS client, for example, dig:
$ dig verify.controld.com @127.0.0.1 +short
api.controld.com.
147.185.34.1

If verify.controld.com resolves, you're successfully using the default Control D upstream. From here, you can start editing the config file and go nuts with it. To enforce a new config, restart the server.

Service Mode

To run the application in service mode on any Windows, MacOS or Linux distibution, simply run: ./ctrld start as system/root user. This will create a generic ctrld.toml file in the user home directory (on Windows) or /etc/controld/ (everywhere else), start the system service, and configure the listener on the default network interface. Service will start on OS boot.

In order to stop the service, and restore your DNS to original state, simply run ./ctrld stop. If you wish to uninstall the service permanently, run ./ctrld service uninstall.

For granular control of the service, run the service command. Each sub-command has its own help section so you can see what arguments you can supply.

  Manage ctrld service

  Usage:
    ctrld service [command]

  Available Commands:
    interfaces  Manage network interfaces
    restart     Restart the ctrld service
    start       Start the ctrld service
    status      Show status of the ctrld service
    stop        Stop the ctrld service
    uninstall   Uninstall the ctrld service

  Flags:
    -h, --help   help for service

  Global Flags:
    -v, --verbose count   verbose log output, "-v" basic logging, "-vv" debug level logging

  Use "ctrld service [command] --help" for more information about a command.

Router Mode

You can run ctrld on any supported router, which will function similarly to the Service Mode mentioned above. The list of supported routers and firmware includes:

  • OpenWRT
  • DD-WRT
  • Asus Merlin
  • GL.iNet
  • Ubiquiti

In order to start ctrld as a DNS provider, simply run ./ctrld setup auto command.

In this mode, and when Control D upstreams are used, the router will relay your network topology to Control D (LAN IPs, MAC addresses, and hostnames), and you will be able to see your LAN devices in the web panel, view analytics and apply unique profiles to them.

Control D Auto Configuration

Application can be started with a specific resolver config, instead of the default one. Simply supply your Resolver ID with a --cd flag, when using the run (foreground) or start (service) or setup (router) modes.

The following command will start the application in foreground mode, using the free "p2" resolver, which blocks Ads & Trackers.

./ctrld run --cd p2

Alternatively, you can use your own personal Control D Device resolver, and start the application in service mode. Your resolver ID is displayed on the "Show Resolvers" screen for the relevant Control D Device.

./ctrld start --cd abcd1234

You can do the same while starting in router mode:

./ctrld setup auto --cd abcd1234

Once you run the above commands (in service or router modes only), the following things will happen:

  • You resolver configuration will be fetched from the API, and config file templated with the resolver data
  • Application will start as a service, and keep running (even after reboot) until you run the stop or service uninstall sub-commands
  • Your default network interface will be updated to use the listener started by the service
  • All OS DNS queries will be sent to the listener

Configuration

See Configuration Docs.

Example

  • Start listener.0 on 127.0.0.1:53
  • Accept queries from any source address
  • Send all queries to upstream.0 via DoH protocol
Default Config
[listener]

  [listener.0]
    ip = "127.0.0.1"
    port = 53
    restricted = false

[network]

  [network.0]
    cidrs = ["0.0.0.0/0"]
    name = "Network 0"

[service]
  log_level = "info"
  log_path = ""

[upstream]

  [upstream.0]
    bootstrap_ip = "76.76.2.11"
    endpoint = "https://freedns.controld.com/p1"
    name = "Control D - Anti-Malware"
    timeout = 5000
    type = "doh"

  [upstream.1]
    bootstrap_ip = "76.76.2.11"
    endpoint = "p2.freedns.controld.com"
    name = "Control D - No Ads"
    timeout = 3000
    type = "doq"

Advanced Configuration

The above is the most basic example, which will work out of the box. If you're looking to do advanced configurations using policies, see Configuration Docs for complete documentation of the config file.

You can also supply configuration via launch argeuments, in Ephemeral Mode.

Contributing

See Contribution Guideline

Roadmap

The following functionality is on the roadmap and will be available in future releases.

  • Prometheus metrics exporter
  • DNS intercept mode
  • Support for more routers (let us know which ones)

Documentation

Index

Constants

View Source
const (
	// IpStackBoth indicates that ctrld will use either ipv4 or ipv6 for connecting to upstream,
	// depending on which stack is available when receiving the DNS query.
	IpStackBoth = "both"
	// IpStackV4 indicates that ctrld will use only ipv4 for connecting to upstream.
	IpStackV4 = "v4"
	// IpStackV6 indicates that ctrld will use only ipv6 for connecting to upstream.
	IpStackV6 = "v6"
	// IpStackSplit indicates that ctrld will use either ipv4 or ipv6 for connecting to upstream,
	// depending on the record type of the DNS query.
	IpStackSplit = "split"
)

IpStackBoth ...

View Source
const (
	// ResolverTypeDOH specifies DoH resolver.
	ResolverTypeDOH = "doh"
	// ResolverTypeDOH3 specifies DoH3 resolver.
	ResolverTypeDOH3 = "doh3"
	// ResolverTypeDOT specifies DoT resolver.
	ResolverTypeDOT = "dot"
	// ResolverTypeDOQ specifies DoQ resolver.
	ResolverTypeDOQ = "doq"
	// ResolverTypeOS specifies OS resolver.
	ResolverTypeOS = "os"
	// ResolverTypeLegacy specifies legacy resolver.
	ResolverTypeLegacy = "legacy"
)

Variables

View Source
var ProxyLog = zerolog.New(io.Discard)

ProxyLog emits the log record for proxy operations. The caller should set it only once.

Functions

func InitConfig

func InitConfig(v *viper.Viper, name string)

InitConfig initializes default config values for given *viper.Viper instance.

func Log

func Log(ctx context.Context, e *zerolog.Event, format string, v ...any)

Log emits the logs for a particular zerolog event. The request id associated with the context will be included if presents.

func LookupIP added in v1.2.0

func LookupIP(domain string) []string

LookupIP looks up host using OS resolver. It returns a slice of that host's IPv4 and IPv6 addresses.

func ResolverTypeFromEndpoint added in v1.1.4

func ResolverTypeFromEndpoint(endpoint string) string

ResolverTypeFromEndpoint tries guessing the resolver type with a given endpoint using following rules:

- If endpoint is an IP address -> ResolverTypeLegacy - If endpoint starts with "https://" -> ResolverTypeDOH - If endpoint starts with "quic://" -> ResolverTypeDOQ - For anything else -> ResolverTypeDOT

func SetConfigName added in v1.1.0

func SetConfigName(v *viper.Viper, name string)

SetConfigName set the config name that ctrld will look for. DEPRECATED: use SetConfigNameWithPath instead.

func SetConfigNameWithPath added in v1.2.0

func SetConfigNameWithPath(v *viper.Viper, name, configPath string)

SetConfigNameWithPath set the config path and name that ctrld will look for.

func ValidateConfig

func ValidateConfig(validate *validator.Validate, cfg *Config) error

ValidateConfig validates the given config.

Types

type ClientInfo added in v1.2.0

type ClientInfo struct {
	Mac      string
	IP       string
	Hostname string
}

ClientInfo represents ctrld's clients information.

type ClientInfoCtxKey added in v1.2.0

type ClientInfoCtxKey struct{}

ClientInfoCtxKey is the context key to store client info.

type Config

type Config struct {
	Service  ServiceConfig              `mapstructure:"service" toml:"service,omitempty"`
	Listener map[string]*ListenerConfig `mapstructure:"listener" toml:"listener" validate:"min=1,dive"`
	Network  map[string]*NetworkConfig  `mapstructure:"network" toml:"network" validate:"min=1,dive"`
	Upstream map[string]*UpstreamConfig `mapstructure:"upstream" toml:"upstream" validate:"min=1,dive"`
}

Config represents ctrld supported configuration.

func (*Config) HasUpstreamSendClientInfo added in v1.2.0

func (c *Config) HasUpstreamSendClientInfo() bool

HasUpstreamSendClientInfo reports whether the config has any upstream is configured to send client info to Control D DNS server.

type ListenerConfig

type ListenerConfig struct {
	IP         string                `mapstructure:"ip" toml:"ip,omitempty" validate:"iporempty"`
	Port       int                   `mapstructure:"port" toml:"port,omitempty" validate:"gte=0"`
	Restricted bool                  `mapstructure:"restricted" toml:"restricted,omitempty"`
	Policy     *ListenerPolicyConfig `mapstructure:"policy" toml:"policy,omitempty"`
}

ListenerConfig specifies the networks configuration that ctrld will run on.

func (*ListenerConfig) Init

func (lc *ListenerConfig) Init()

Init initialized necessary values for an ListenerConfig.

type ListenerPolicyConfig

type ListenerPolicyConfig struct {
	Name                 string   `mapstructure:"name" toml:"name,omitempty"`
	Networks             []Rule   `mapstructure:"networks" toml:"networks,omitempty,inline,multiline" validate:"dive,len=1"`
	Rules                []Rule   `mapstructure:"rules" toml:"rules,omitempty,inline,multiline" validate:"dive,len=1"`
	FailoverRcodes       []string `mapstructure:"failover_rcodes" toml:"failover_rcodes,omitempty" validate:"dive,dnsrcode"`
	FailoverRcodeNumbers []int    `mapstructure:"-" toml:"-"`
}

ListenerPolicyConfig specifies the policy rules for ctrld to filter incoming requests.

type NetworkConfig

type NetworkConfig struct {
	Name   string       `mapstructure:"name" toml:"name,omitempty"`
	Cidrs  []string     `mapstructure:"cidrs" toml:"cidrs,omitempty" validate:"dive,cidr"`
	IPNets []*net.IPNet `mapstructure:"-" toml:"-"`
}

NetworkConfig specifies configuration for networks where ctrld will handle requests.

type ReqIdCtxKey

type ReqIdCtxKey struct{}

ReqIdCtxKey is the context.Context key for a request id.

type Resolver

type Resolver interface {
	Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error)
}

Resolver is the interface that wraps the basic DNS operations.

Resolve resolves the DNS query, return the result and the corresponding error.

func NewBootstrapResolver added in v1.2.1

func NewBootstrapResolver(servers ...string) Resolver

NewBootstrapResolver returns an OS resolver, which use following nameservers:

  • ControlD bootstrap DNS server.
  • Gateway IP address (depends on OS).
  • Input servers.

func NewResolver

func NewResolver(uc *UpstreamConfig) (Resolver, error)

NewResolver creates a Resolver based on the given upstream config.

type Rule

type Rule map[string][]string

Rule is a map from source to list of upstreams. ctrld uses rule to perform requests matching and forward the request to corresponding upstreams if it's matched.

type ServiceConfig

type ServiceConfig struct {
	LogLevel         string `mapstructure:"log_level" toml:"log_level,omitempty"`
	LogPath          string `mapstructure:"log_path" toml:"log_path,omitempty"`
	CacheEnable      bool   `mapstructure:"cache_enable" toml:"cache_enable,omitempty"`
	CacheSize        int    `mapstructure:"cache_size" toml:"cache_size,omitempty"`
	CacheTTLOverride int    `mapstructure:"cache_ttl_override" toml:"cache_ttl_override,omitempty"`
	CacheServeStale  bool   `mapstructure:"cache_serve_stale" toml:"cache_serve_stale,omitempty"`
	Daemon           bool   `mapstructure:"-" toml:"-"`
	AllocateIP       bool   `mapstructure:"-" toml:"-"`
}

ServiceConfig specifies the general ctrld config.

type UpstreamConfig

type UpstreamConfig struct {
	Name        string `mapstructure:"name" toml:"name,omitempty"`
	Type        string `mapstructure:"type" toml:"type,omitempty" validate:"oneof=doh doh3 dot doq os legacy"`
	Endpoint    string `mapstructure:"endpoint" toml:"endpoint,omitempty" validate:"required_unless=Type os"`
	BootstrapIP string `mapstructure:"bootstrap_ip" toml:"bootstrap_ip,omitempty"`
	Domain      string `mapstructure:"-" toml:"-"`
	IPStack     string `mapstructure:"ip_stack" toml:"ip_stack,omitempty" validate:"ipstack"`
	Timeout     int    `mapstructure:"timeout" toml:"timeout,omitempty" validate:"gte=0"`
	// The caller should not access this field directly.
	// Use UpstreamSendClientInfo instead.
	SendClientInfo *bool `mapstructure:"send_client_info" toml:"send_client_info,omitempty"`
	// contains filtered or unexported fields
}

UpstreamConfig specifies configuration for upstreams that ctrld will forward requests to.

func (*UpstreamConfig) BootstrapIPs added in v1.2.0

func (uc *UpstreamConfig) BootstrapIPs() []string

BootstrapIPs returns the bootstrap IPs list of upstreams.

func (*UpstreamConfig) Init

func (uc *UpstreamConfig) Init()

Init initialized necessary values for an UpstreamConfig.

func (*UpstreamConfig) ReBootstrap added in v1.1.1

func (uc *UpstreamConfig) ReBootstrap()

ReBootstrap re-setup the bootstrap IP and the transport.

func (*UpstreamConfig) SetCertPool added in v1.2.0

func (uc *UpstreamConfig) SetCertPool(cp *x509.CertPool)

SetCertPool sets the system cert pool used for TLS connections.

func (*UpstreamConfig) SetupBootstrapIP added in v1.1.1

func (uc *UpstreamConfig) SetupBootstrapIP()

SetupBootstrapIP manually find all available IPs of the upstream. The first usable IP will be used as bootstrap IP of the upstream.

func (*UpstreamConfig) SetupTransport added in v1.1.0

func (uc *UpstreamConfig) SetupTransport()

SetupTransport initializes the network transport used to connect to upstream server. For now, only DoH upstream is supported.

func (*UpstreamConfig) UpstreamSendClientInfo added in v1.2.0

func (uc *UpstreamConfig) UpstreamSendClientInfo() bool

UpstreamSendClientInfo reports whether the upstream is configured to send client info to Control D DNS server.

Client info includes:

  • MAC
  • Lan IP
  • Hostname

func (*UpstreamConfig) VerifyDomain added in v1.2.1

func (uc *UpstreamConfig) VerifyDomain() string

VerifyDomain returns the domain name that could be resolved by the upstream endpoint. It returns empty for non-ControlD upstream endpoint.

Directories

Path Synopsis
cmd
internal
dns
dns/resolvconffile
Package resolvconffile parses & serializes /etc/resolv.conf-style files.
Package resolvconffile parses & serializes /etc/resolv.conf-style files.
net

Jump to

Keyboard shortcuts

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