secureoperator

package module
v4.1.0+incompatible Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2019 License: Apache-2.0 Imports: 15 Imported by: 13

README

secureoperator

Build Status

A DNS-protocol proxy for DNS-over-HTTPS: allows you to run a server on your local network which responds to DNS queries, but requests records across the internet using HTTPS.

It's known to work with the following providers:

  • Google - Well tested and configured by default
  • Cloudflare (Beta) - May be used by passing the --cloudflare flag
  • Quad9 (Beta) - May be used by passing the `--quad9' flag

If you're interested in a more roll-your-own-DNS system, you might look at dnoxy, a sibling project to secureoperator which allows running your own DNS-over-HTTPS servers.

Installation

You may retrieve binaries from the releases page, or install using go get:

go get -u github.com/fardog/secureoperator/cmd/secure-operator

Then either run the binary you downloaded, or the built package:

secure-operator

This will start a DNS server listening on TCP and UDP at :53. For usage information, run secure-operator --help.

Note: Running a service on port 53 requires administrative privileges on most systems.

Docker

There is a Docker image available for secureoperator:

docker pull fardog/secureoperator

The latest tag will always be the build from the master branch. If you wish to use one of the stable releases, use its version tag when pulling, e.g.:

docker pull fardog/secureoperator:4  # latest of major version
docker pull fardog/secureoperator:4.0  # latest of minor version
docker pull fardog/secureoperator:4.0.1  # exact version

Version Compatibility

This package follows semver for its tagged releases. The master branch is always considered stable, but may break API compatibility. If you require API stability, either use the tagged releases or mirror on gopkg.in:

go get -u gopkg.in/fardog/secureoperator.v4

Caching

secureoperator does not perform any caching; each request to it causes a matching request to the upstream DNS-over-HTTPS server to be made. It's recommended that you place secureoperator behind a caching DNS server such as dnsmasq on your local network.

An simple example setup is described on the wiki. Please feel free to contribute additional setups if you are running secureoperator in your environment.

Security

Note that while DNS requests are made over HTTPS, this does not imply "secure"; consider the following:

  • You must trust the upstream provider with your requests; for your chosen provider, see:
  • The lookup for the HTTP endpoint must happen in some regard, although how this is handled is up to you:
    • The system DNS resolver is used to look up the endpoint (default)
    • You provide a list of DNS servers to use for the endpoint lookup
    • You provide the IP address(es) to the endpoint; and no unencrypted DNS lookup will be performed. However if the addresses change while the service is running, you will need to restart the service to provide new addresses.

Information on the usage of these options is available with secure-operator --help.

Help Wanted

secureoperator could be greatly enhanced by community contributions! The following areas could use work:

  • More thorough unit tests
  • Installable packages for your favorite Linux distributions
  • Documentation on deploying secureoperator to a local network
Known Issues

Cloudflare is not fully tested yet; it should work for common cases, however:

  • EDNS is not supported; this is an intentional choice by Cloudflare, which means any EDNS setting you provide when using Cloudflare as a provider will be silently ignored.

For a production environment, the Google provider (default) is your best option today. If you're brave, please test Cloudflare and report any issues!

Acknowledgments

This owes heavily to the following work:

License

   Copyright 2018 Nathan Wittstock

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

Documentation

Index

Constants

View Source
const (
	// DNSNameMaxBytes is the maximum number of bytes a DNS name may contain
	DNSNameMaxBytes = 253
	// GoogleEDNSSentinelValue is the value that when sent to Google as the
	// EDNS value, means "do not use EDNS".
	GoogleEDNSSentinelValue = "0.0.0.0/0"
)

Variables

View Source
var ErrAllServersFailed = errors.New("unable to reach any of the configured servers")

ErrAllServersFailed is returned when we failed to reach all configured DNS servers

View Source
var ErrFailedParsingIP = errors.New("unable to parse IP from string")

ErrFailedParsingIP is returned when the endpoint string looked valid, but the IP portion of the string was unable to be parsed

View Source
var ErrFailedParsingPort = errors.New("unable to parse port from string")

ErrFailedParsingPort is returned when the endpoint string looked valid, but the port portion of the string was unable to be parsed

View Source
var ErrInvalidEndpointString = errors.New("invalid endpoint string")

ErrInvalidEndpointString is returned when an endpoint string is in an unexpected format; the string is expected to be in `ip[:port]` format

Functions

This section is empty.

Types

type DNSClientOptions

type DNSClientOptions struct {
	Timeout time.Duration
}

type DNSQuestion

type DNSQuestion struct {
	Name string `json:"name,omitempty"`
	Type uint16 `json:"type,omitempty"`
}

DNSQuestion represents a DNS question to be resolved by a DNS server

type DNSRR

type DNSRR struct {
	Name string `json:"name,omitempty"`
	Type uint16 `json:"type,omitempty"`
	TTL  uint32 `json:"TTL,omitempty"`
	Data string `json:"data,omitempty"`
}

DNSRR represents a DNS record, part of a response to a DNSQuestion

func (DNSRR) DNSRR

func (r DNSRR) DNSRR() (dns.RR, error)

DNSRR is deprecated as of 3.0.0; use RR instead.

func (DNSRR) RR

func (r DNSRR) RR() (dns.RR, error)

RR transforms a DNSRR to a dns.RR

func (DNSRR) String

func (r DNSRR) String() string

type DNSResponse

type DNSResponse struct {
	Question           []DNSQuestion
	Answer             []DNSRR
	Authority          []DNSRR
	Extra              []DNSRR
	Truncated          bool
	RecursionDesired   bool
	RecursionAvailable bool
	AuthenticatedData  bool
	CheckingDisabled   bool
	ResponseCode       int
}

DNSResponse represents a complete DNS server response, to be served by the DNS server handler.

type Endpoint

type Endpoint struct {
	IP   net.IP
	Port uint16
}

Endpoint represents a host/port combo

func ParseEndpoint

func ParseEndpoint(endpoint string, defaultPort uint16) (ep Endpoint, err error)

ParseEndpoint parses a string into an Endpoint object, where the endpoint string is in the format of "ip:port". If a port is not present in the string, the defaultPort is used.

func (Endpoint) String

func (e Endpoint) String() string

type Endpoints

type Endpoints []Endpoint

Endpoints is a list of Endpoint objects

func (Endpoints) Random

func (e Endpoints) Random() Endpoint

Random retrieves a random Endpoint from a list of Endpoints

type GDNSOptions

type GDNSOptions struct {
	// Pad specifies if a DNS request should be padded to a fixed length
	Pad bool
	// EndpointIPs is a list of IPs to be used as the GDNS endpoint, avoiding
	// DNS lookups in the case where they are provided. One is chosen randomly
	// for each request.
	EndpointIPs []net.IP
	// DNSServers is a list of Endpoints to be used as DNS servers when looking
	// up the endpoint; if not provided, the system DNS resolver is used.
	DNSServers Endpoints
	// UseEDNSSubnetOption is an option which must be specified to enable an
	// EDNS value other than the default of "0.0.0.0/0", which is Google's
	// sentinel value for "do not send EDNS with this request".
	//
	// When this option is false, the value in EDNSSubnet is ignored.
	//
	// This temporary option exists because the API change may have been
	// dangerous to consumers of this library: to send EDNS by default.
	//
	// Deprecated: this option will be removed in v4, and the default behavior
	// will be that Google decides EDNS behavior.
	UseEDNSsubnetOption bool
	// The EDNS subnet to send in the edns0-client-subnet option. If not
	// specified, Google determines this automatically. To specify that the
	// option should not be set, use the value "0.0.0.0/0".
	EDNSSubnet string
	// Additional headers to be sent with requests to the DNS provider
	Headers http.Header
	// Additional query parameters to be sent with requests to the DNS provider
	QueryParameters map[string][]string
}

GDNSOptions is a configuration object for optional GDNSProvider configuration

type GDNSProvider

type GDNSProvider struct {
	// contains filtered or unexported fields
}

GDNSProvider is the Google DNS-over-HTTPS provider; it implements the Provider interface.

func NewGDNSProvider

func NewGDNSProvider(endpoint string, opts *GDNSOptions) (*GDNSProvider, error)

NewGDNSProvider creates a GDNSProvider

func (GDNSProvider) Query

func (g GDNSProvider) Query(q DNSQuestion) (*DNSResponse, error)

Query sends a DNS question to Google, and returns the response

type GDNSQuestion

type GDNSQuestion DNSQuestion

GDNSQuestion represents a question response item from Google's DNS service This is currently the same as DNSQuestion, our internal implementation, but since Google's API is in flux, we keep them separate

func (GDNSQuestion) DNSQuestion

func (r GDNSQuestion) DNSQuestion() DNSQuestion

DNSQuestion transforms a GDNSQuestion to a DNSQuestion and returns it.

type GDNSQuestions

type GDNSQuestions []GDNSQuestion

GDNSQuestions is a array of GDNSQuestion objects

func (GDNSQuestions) DNSQuestions

func (rs GDNSQuestions) DNSQuestions() (rqs []DNSQuestion)

DNSQuestions transforms an array of GDNSQuestion objects to an array of DNSQuestion objects

type GDNSRR

type GDNSRR DNSRR

GDNSRR represents a dns response record item from Google's DNS service. This is currently the same as DNSRR, our internal implementation, but since Google's API is in flux, we keep them separate

func (GDNSRR) DNSRR

func (r GDNSRR) DNSRR() DNSRR

DNSRR transforms a GDNSRR to a DNSRR

type GDNSRRs

type GDNSRRs []GDNSRR

GDNSRRs represents an array of GDNSRR objects

func (GDNSRRs) DNSRRs

func (rs GDNSRRs) DNSRRs() (rrs []DNSRR)

DNSRRs transforms an array of GDNSRR objects to an array of DNSRR objects

type GDNSResponse

type GDNSResponse struct {
	Status           int32         `json:"Status"`
	TC               bool          `json:"TC"`
	RD               bool          `json:"RD"`
	RA               bool          `json:"RA"`
	AD               bool          `json:"AD"`
	CD               bool          `json:"CD"`
	Question         GDNSQuestions `json:"Question,omitempty"`
	Answer           GDNSRRs       `json:"Answer,omitempty"`
	Authority        GDNSRRs       `json:"Authority,omitempty"`
	Additional       GDNSRRs       `json:"Additional,omitempty"`
	EDNSClientSubnet string        `json:"edns_client_subnet,omitempty"`
	Comment          string        `json:"Comment,omitempty"`
}

GDNSResponse represents a response from the Google DNS-over-HTTPS servers

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler represents a DNS handler

func NewHandler

func NewHandler(provider Provider, options *HandlerOptions) *Handler

NewHandler creates a new Handler

func (*Handler) Handle

func (h *Handler) Handle(w dns.ResponseWriter, r *dns.Msg)

Handle handles a DNS request

type HandlerOptions

type HandlerOptions struct{}

HandlerOptions specifies options to be used when instantiating a handler

type Provider

type Provider interface {
	Query(DNSQuestion) (*DNSResponse, error)
}

Provider is an interface representing a servicer of DNS queries.

type SimpleDNSClient

type SimpleDNSClient struct {
	// contains filtered or unexported fields
}

SimpleDNSClient is a DNS client, primarily for internal use in secure operator.

It provides an in-memory cache, but was optimized to look up one address at a time only.

func NewSimpleDNSClient

func NewSimpleDNSClient(servers Endpoints, opts *DNSClientOptions) (*SimpleDNSClient, error)

NewSimpleDNSClient creates a SimpleDNSClient

func (*SimpleDNSClient) LookupIP

func (c *SimpleDNSClient) LookupIP(host string) ([]net.IP, error)

LookupIP does a single lookup against the client's configured DNS servers, returning a value from cache if its still valid. It looks at A records only.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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