Documentation
¶
Overview ¶
Package dnscrypt includes everything you need to work with DNSCrypt. You can run your own resolver, make DNS lookups to other DNSCrypt resolvers, and you can use it as a library in your own projects.
Here's how to create a simple DNSCrypt client:
// AdGuard DNS stamp
stampStr := "sdns://AQIAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20"
// Initializing the DNSCrypt client
c := dnscrypt.Client{Net: "udp", Timeout: 10 * time.Second}
// Fetching and validating the server certificate
resolverInfo, err := client.Dial(stampStr)
if err != nil {
return err
}
// Create a DNS request
req := dns.Msg{}
req.Id = dns.Id()
req.RecursionDesired = true
req.Question = []dns.Question{
{Name: "google-public-dns-a.google.com.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
}
// Get the DNS response
reply, err := c.Exchange(&req, resolverInfo)
Here's how to run a DNSCrypt resolver:
// Prepare the test DNSCrypt server config
rc, err := dnscrypt.GenerateResolverConfig("example.org", nil)
if err != nil {
return err
}
cert, err := rc.CreateCert()
if err != nil {
return err
}
s := &dnscrypt.Server{
ProviderName: rc.ProviderName,
ResolverCert: cert,
Handler: dnscrypt.DefaultHandler,
}
// Prepare TCP listener
tcpConn, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4zero, Port: 443})
if err != nil {
return err
}
// Prepare UDP listener
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 443})
if err != nil {
return err
}
// Start the server
go s.ServeUDP(udpConn)
go s.ServeTCP(tcpConn)
Index ¶
- Variables
- func HexDecodeKey(str string) ([]byte, error)
- func HexEncodeKey(b []byte) string
- type Cert
- type Client
- func (c *Client) Dial(stampStr string) (*ResolverInfo, error)
- func (c *Client) DialStamp(stamp dnsstamps.ServerStamp) (*ResolverInfo, error)
- func (c *Client) Exchange(m *dns.Msg, resolverInfo *ResolverInfo) (*dns.Msg, error)
- func (c *Client) ExchangeConn(conn net.Conn, m *dns.Msg, resolverInfo *ResolverInfo) (*dns.Msg, error)
- type CryptoConstruction
- type EncryptedQuery
- type EncryptedResponse
- type Handler
- type ResolverConfig
- type ResolverInfo
- type ResponseWriter
- type Server
- type TCPResponseWriter
- type UDPResponseWriter
Constants ¶
This section is empty.
Variables ¶
var ( // ErrTooShort - DNS query is shorter than possible ErrTooShort = errors.New("DNSCrypt message is too short") // ErrQueryTooLarge - DNS query is larger than max allowed size ErrQueryTooLarge = errors.New("DNSCrypt query is too large") // ErrEsVersion - cert contains unsupported es-version ErrEsVersion = errors.New("unsupported es-version") // ErrInvalidDate - cert is not valid for the current time ErrInvalidDate = errors.New("cert has invalid ts-start or ts-end") // ErrInvalidCertSignature - cert has invalid signature ErrInvalidCertSignature = errors.New("cert has invalid signature") // ErrInvalidQuery - failed to decrypt a DNSCrypt query ErrInvalidQuery = errors.New("DNSCrypt query is invalid and cannot be decrypted") // ErrInvalidClientMagic - client-magic does not match ErrInvalidClientMagic = errors.New("DNSCrypt query contains invalid client magic") // ErrInvalidResolverMagic - server-magic does not match ErrInvalidResolverMagic = errors.New("DNSCrypt response contains invalid resolver magic") // ErrInvalidResponse - failed to decrypt a DNSCrypt response ErrInvalidResponse = errors.New("DNSCrypt response is invalid and cannot be decrypted") // ErrInvalidPadding - failed to unpad a query ErrInvalidPadding = errors.New("invalid padding") // ErrInvalidDNSStamp - invalid DNS stamp ErrInvalidDNSStamp = errors.New("invalid DNS stamp") // ErrFailedToFetchCert - failed to fetch DNSCrypt certificate ErrFailedToFetchCert = errors.New("failed to fetch DNSCrypt certificate") // ErrCertTooShort - failed to deserialize cert, too short ErrCertTooShort = errors.New("cert is too short") // ErrCertMagic - invalid cert magic ErrCertMagic = errors.New("invalid cert magic") // ErrServerConfig - failed to start the DNSCrypt server - invalid configuration ErrServerConfig = errors.New("invalid server configuration") )
Functions ¶
func HexDecodeKey ¶
HexDecodeKey - decodes a hex-encoded string with (optional) colons to a byte array.
func HexEncodeKey ¶
HexEncodeKey - encodes a byte slice to a hex-encoded string.
Types ¶
type Cert ¶
type Cert struct {
// Serial - a 4 byte serial number in big-endian format. If more than
// one certificates are valid, the client must prefer the certificate
// with a higher serial number.
Serial uint32
// <es-version> ::= the cryptographic construction to use with this
// certificate.
// For X25519-XSalsa20Poly1305, <es-version> must be 0x00 0x01.
// For X25519-XChacha20Poly1305, <es-version> must be 0x00 0x02.
EsVersion CryptoConstruction
// Signature - a 64-byte signature of (<resolver-pk> <client-magic>
// <serial> <ts-start> <ts-end> <extensions>) using the Ed25519 algorithm and the
// provider secret key. Ed25519 must be used in this version of the
// protocol.
Signature [ed25519.SignatureSize]byte
// ResolverPk - the resolver's short-term public key, which is 32 bytes when using X25519.
// This key is used to encrypt/decrypt DNS queries
ResolverPk [keySize]byte
// ResolverSk - the resolver's short-term private key, which is 32 bytes when using X25519.
// Note that it's only used in the server implementation and never serialized/deserialized.
// This key is used to encrypt/decrypt DNS queries
ResolverSk [keySize]byte
// ClientMagic - the first 8 bytes of a client query that is to be built
// using the information from this certificate. It may be a truncated
// public key. Two valid certificates cannot share the same <client-magic>.
ClientMagic [clientMagicSize]byte
// NotAfter - the date the certificate is valid from, as a big-endian
// 4-byte unsigned Unix timestamp.
NotBefore uint32
// NotAfter - the date the certificate is valid until (inclusive), as a
// big-endian 4-byte unsigned Unix timestamp.
NotAfter uint32
}
Cert - DNSCrypt server certificate See ResolverConfig for more info on how to create one
func (*Cert) Deserialize ¶
Deserialize - deserializes certificate from a byte array <cert> ::= <cert-magic> <es-version> <protocol-minor-version> <signature>
<resolver-pk> <client-magic> <serial> <ts-start> <ts-end> <extensions>
func (*Cert) Serialize ¶
Serialize - serializes the cert to bytes <cert> ::= <cert-magic> <es-version> <protocol-minor-version> <signature>
<resolver-pk> <client-magic> <serial> <ts-start> <ts-end> <extensions>
Certificates made of these information, without extensions, are 116 bytes long. With the addition of the cert-magic, es-version and protocol-minor-version, the record is 124 bytes long.
func (*Cert) Sign ¶
func (c *Cert) Sign(privateKey ed25519.PrivateKey)
Sign - creates cert.Signature
func (*Cert) VerifyDate ¶
VerifyDate - checks that cert is valid at this moment
type Client ¶
type Client struct {
Net string // protocol (can be "udp" or "tcp", by default - "udp")
Timeout time.Duration // read/write timeout
}
Client - DNSCrypt resolver client
func (*Client) Dial ¶
func (c *Client) Dial(stampStr string) (*ResolverInfo, error)
Dial fetches and validates DNSCrypt certificate from the given server Data received during this call is then used for DNS requests encryption/decryption stampStr is an sdns:// address which is parsed using go-dnsstamps package
func (*Client) DialStamp ¶
func (c *Client) DialStamp(stamp dnsstamps.ServerStamp) (*ResolverInfo, error)
DialStamp fetches and validates DNSCrypt certificate from the given server Data received during this call is then used for DNS requests encryption/decryption
func (*Client) Exchange ¶
Exchange performs a synchronous DNS query to the specified DNSCrypt server and returns a DNS response. This method creates a new network connection for every call so avoid using it for TCP. DNSCrypt cert needs to be fetched and validated prior to this call using the c.DialStamp method.
func (*Client) ExchangeConn ¶
func (c *Client) ExchangeConn(conn net.Conn, m *dns.Msg, resolverInfo *ResolverInfo) (*dns.Msg, error)
ExchangeConn performs a synchronous DNS query to the specified DNSCrypt server and returns a DNS response. DNSCrypt server information needs to be fetched and validated prior to this call using the c.DialStamp method
type CryptoConstruction ¶
type CryptoConstruction uint16
CryptoConstruction represents the encryption algorithm (either XSalsa20Poly1305 or XChacha20Poly1305)
const ( // UndefinedConstruction is the default value for empty CertInfo only UndefinedConstruction CryptoConstruction = iota // XSalsa20Poly1305 encryption XSalsa20Poly1305 CryptoConstruction = 0x0001 // XChacha20Poly1305 encryption XChacha20Poly1305 CryptoConstruction = 0x0002 )
func (CryptoConstruction) String ¶
func (c CryptoConstruction) String() string
type EncryptedQuery ¶
type EncryptedQuery struct {
// EsVersion - encryption to use
EsVersion CryptoConstruction
// ClientMagic - a 8 byte identifier for the resolver certificate
// chosen by the client.
ClientMagic [clientMagicSize]byte
// ClientPk - the client's public key
ClientPk [keySize]byte
// With a 24 bytes nonce, a question sent by a DNSCrypt client must be
// encrypted using the shared secret, and a nonce constructed as follows:
// 12 bytes chosen by the client followed by 12 NUL (0) bytes.
//
// The client's half of the nonce can include a timestamp in addition to a
// counter or to random bytes, so that when a response is received, the
// client can use this timestamp to immediately discard responses to
// queries that have been sent too long ago, or dated in the future.
Nonce [nonceSize]byte
}
EncryptedQuery - a structure for encrypting and decrypting client queries
<dnscrypt-query> ::= <client-magic> <client-pk> <client-nonce> <encrypted-query> <encrypted-query> ::= AE(<shared-key> <client-nonce> <client-nonce-pad>, <client-query> <client-query-pad>)
func (*EncryptedQuery) Decrypt ¶
func (q *EncryptedQuery) Decrypt(query []byte, serverSecretKey [keySize]byte) ([]byte, error)
Decrypt - decrypts the client query, returns decrypted DNS packet.
Please note, that before calling this method the following fields must be set: * ClientMagic -- to verify the query * EsVersion -- to decrypt
func (*EncryptedQuery) Encrypt ¶
func (q *EncryptedQuery) Encrypt(packet []byte, sharedKey [sharedKeySize]byte) ([]byte, error)
Encrypt - encrypts the specified DNS query, returns encrypted data ready to be sent.
Note that this method will generate a random nonce automatically.
The following fields must be set before calling this method: * EsVersion -- to encrypt the query * ClientMagic -- to send it with the query * ClientPk -- to send it with the query
type EncryptedResponse ¶
type EncryptedResponse struct {
// EsVersion - encryption to use
EsVersion CryptoConstruction
// Nonce - <nonce> ::= <client-nonce> <resolver-nonce>
// <client-nonce> ::= the nonce sent by the client in the related query.
Nonce [nonceSize]byte
}
EncryptedResponse - structure for encrypting/decrypting server responses
<dnscrypt-response> ::= <resolver-magic> <nonce> <encrypted-response> <encrypted-response> ::= AE(<shared-key>, <nonce>, <resolver-response> <resolver-response-pad>)
func (*EncryptedResponse) Decrypt ¶
func (r *EncryptedResponse) Decrypt(response []byte, sharedKey [sharedKeySize]byte) ([]byte, error)
Decrypt - decrypts the server response
EsVersion must be set.
func (*EncryptedResponse) Encrypt ¶
func (r *EncryptedResponse) Encrypt(packet []byte, sharedKey [sharedKeySize]byte) ([]byte, error)
Encrypt - encrypts the server response
EsVersion must be set. Nonce needs to be set to "client-nonce". This method will generate "resolver-nonce" and set it automatically.
type Handler ¶
type Handler interface {
ServeDNS(rw ResponseWriter, r *dns.Msg) error
}
Handler is implemented by any value that implements ServeDNS.
var DefaultHandler Handler = &defaultHandler{ udpClient: &dns.Client{ Net: "udp", Timeout: defaultTimeout, }, tcpClient: &dns.Client{ Net: "tcp", Timeout: defaultTimeout, }, addr: "94.140.14.140:53", }
DefaultHandler - default Handler implementation that is used by Server if custom handler is not configured
type ResolverConfig ¶
type ResolverConfig struct {
// DNSCrypt provider name
ProviderName string `yaml:"provider_name"`
// PublicKey - DNSCrypt resolver public key
PublicKey string `yaml:"public_key"`
// PrivateKey - DNSCrypt resolver private key
// The main and only purpose of this key is to sign the certificate
PrivateKey string `yaml:"private_key"`
// ResolverSk - hex-encoded short-term private key.
// This key is used to encrypt/decrypt DNS queries.
// If not set, we'll generate a new random ResolverSk and ResolverPk.
ResolverSk string `yaml:"resolver_secret"`
// ResolverSk - hex-encoded short-term public key corresponding to ResolverSk.
// This key is used to encrypt/decrypt DNS queries.
ResolverPk string `yaml:"resolver_public"`
// EsVersion - crypto to use in this resolver
EsVersion CryptoConstruction `yaml:"es_version"`
// CertificateTTL - time-to-live for the certificate that is generated using this ResolverConfig.
// If not set, we'll use 1 year by default.
CertificateTTL time.Duration `yaml:"certificate_ttl"`
}
ResolverConfig - DNSCrypt resolver configuration
func GenerateResolverConfig ¶
func GenerateResolverConfig(providerName string, privateKey ed25519.PrivateKey) (ResolverConfig, error)
GenerateResolverConfig - generates resolver configuration for a given provider name. providerName is mandatory. If needed, "2.dnscrypt-cert." prefix is added to it. privateKey is optional. If not set, it will be generated automatically.
func (*ResolverConfig) CreateCert ¶
func (rc *ResolverConfig) CreateCert() (*Cert, error)
CreateCert - generates a signed Cert to be used by Server
func (*ResolverConfig) CreateStamp ¶
func (rc *ResolverConfig) CreateStamp(addr string) (dnsstamps.ServerStamp, error)
CreateStamp - generates a DNS stamp for this resolver
type ResolverInfo ¶
type ResolverInfo struct {
SecretKey [keySize]byte // Client short-term secret key
PublicKey [keySize]byte // Client short-term public key
ServerPublicKey ed25519.PublicKey // Resolver public key (this key is used to validate cert signature)
ServerAddress string // Server IP address
ProviderName string // Provider name
ResolverCert *Cert // Certificate info (obtained with the first unencrypted DNS request)
}
ResolverInfo contains DNSCrypt resolver information necessary for decryption/encryption
type ResponseWriter ¶
type ResponseWriter interface {
LocalAddr() net.Addr // LocalAddr - local socket address
RemoteAddr() net.Addr // RemoteAddr - remote client socket address
WriteMsg(m *dns.Msg) error // WriteMsg - writes response message to the client
}
ResponseWriter - interface that needs to be implemented for different protocols
type Server ¶
type Server struct {
// ProviderName - DNSCrypt provider name
ProviderName string
// ResolverCert - contains resolver certificate.
ResolverCert *Cert
// Handler to invoke. If nil, uses DefaultHandler.
Handler Handler
}
Server - a simple DNSCrypt server implementation
type TCPResponseWriter ¶
type TCPResponseWriter struct {
// contains filtered or unexported fields
}
TCPResponseWriter - ResponseWriter implementation for TCP
func (*TCPResponseWriter) LocalAddr ¶
func (w *TCPResponseWriter) LocalAddr() net.Addr
LocalAddr - server socket local address
func (*TCPResponseWriter) RemoteAddr ¶
func (w *TCPResponseWriter) RemoteAddr() net.Addr
RemoteAddr - client's address
type UDPResponseWriter ¶
type UDPResponseWriter struct {
// contains filtered or unexported fields
}
UDPResponseWriter - ResponseWriter implementation for UDP
func (*UDPResponseWriter) LocalAddr ¶
func (w *UDPResponseWriter) LocalAddr() net.Addr
LocalAddr - server socket local address
func (*UDPResponseWriter) RemoteAddr ¶
func (w *UDPResponseWriter) RemoteAddr() net.Addr
RemoteAddr - client's address
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package xsecretbox implements encryption/decryption of a message using specified keys
|
Package xsecretbox implements encryption/decryption of a message using specified keys |