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://AQMAAAAAAAAAETk0LjE0MC4xNC4xNDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20" // Initializing the DNSCrypt client c := dnscrypt.Client{Net: "udp", Timeout: 10 * time.Second} // Fetching and validating the server certificate resolverInfo, err := c.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 ¶
- Constants
- 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) (resp *dns.Msg, err error)
- func (c *Client) ExchangeConn(conn net.Conn, m *dns.Msg, resolverInfo *ResolverInfo) (*dns.Msg, error)
- type CryptoConstruction
- type EncryptedQuery
- type EncryptedResponse
- type Error
- type Handler
- type ResolverConfig
- type ResolverInfo
- type ResponseWriter
- type Server
- type ServerDNSCrypt
- type TCPResponseWriter
- type UDPResponseWriter
Constants ¶
const ( // ErrTooShort means that the DNS query is shorter than possible ErrTooShort = Error("message is too short") // ErrQueryTooLarge means that the DNS query is larger than max allowed size ErrQueryTooLarge = Error("DNSCrypt query is too large") // ErrEsVersion means that the cert contains unsupported es-version ErrEsVersion = Error("unsupported es-version") // ErrInvalidDate means that the cert is not valid for the current time ErrInvalidDate = Error("cert has invalid ts-start or ts-end") // ErrInvalidCertSignature means that the cert has invalid signature ErrInvalidCertSignature = Error("cert has invalid signature") // ErrInvalidQuery means that it failed to decrypt a DNSCrypt query ErrInvalidQuery = Error("DNSCrypt query is invalid and cannot be decrypted") // ErrInvalidClientMagic means that client-magic does not match ErrInvalidClientMagic = Error("DNSCrypt query contains invalid client magic") // ErrInvalidResolverMagic means that server-magic does not match ErrInvalidResolverMagic = Error("DNSCrypt response contains invalid resolver magic") // ErrInvalidResponse means that it failed to decrypt a DNSCrypt response ErrInvalidResponse = Error("DNSCrypt response is invalid and cannot be decrypted") // ErrInvalidPadding means that it failed to unpad a query ErrInvalidPadding = Error("invalid padding") // ErrInvalidDNSStamp means an invalid DNS stamp ErrInvalidDNSStamp = Error("invalid DNS stamp") // ErrFailedToFetchCert means that it failed to fetch DNSCrypt certificate ErrFailedToFetchCert = Error("failed to fetch DNSCrypt certificate") // ErrCertTooShort means that it failed to deserialize cert, too short ErrCertTooShort = Error("cert is too short") // ErrCertMagic means an invalid cert magic ErrCertMagic = Error("invalid cert magic") // ErrServerConfig means that it failed to start the DNSCrypt server - invalid configuration ErrServerConfig = Error("invalid server configuration") // ErrServerNotStarted is returned if there's nothing to shutdown ErrServerNotStarted = Error("server is not started") )
Variables ¶
This section is empty.
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 is 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 is 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 is 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 is 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 is 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 is the date the certificate is valid from, as a big-endian // 4-byte unsigned Unix timestamp. NotBefore uint32 // NotAfter is the date the certificate is valid until (inclusive), as a // big-endian 4-byte unsigned Unix timestamp. NotAfter uint32 }
Cert is a 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) VerifyDate ¶
VerifyDate checks that the 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 // UDPSize is the maximum size of a DNS response (or query) this client can // sent or receive. If not set, we use dns.MinMsgSize by default. UDPSize int }
Client is a 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 is the encryption to use EsVersion CryptoConstruction // ClientMagic is a 8 byte identifier for the resolver certificate // chosen by the client. ClientMagic [clientMagicSize]byte // ClientPk is 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 is 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 is the 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 is a 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 is the 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 is the DNSCrypt resolver public key PublicKey string `yaml:"public_key"` // PrivateKey is the DNSCrypt resolver private key // The main and only purpose of this key is to sign the certificate PrivateKey string `yaml:"private_key"` // ResolverSk is a 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"` // ResolverPk is a hex-encoded short-term public key corresponding to ResolverSk. // This key is used to encrypt/decrypt DNS queries. ResolverPk string `yaml:"resolver_public"` // EsVersion is the crypto to use in this resolver EsVersion CryptoConstruction `yaml:"es_version"` // CertificateTTL is the time-to-live value 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 is the 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 is the interface that needs to be implemented for different protocols
type Server ¶
type Server struct { // ProviderName is a DNSCrypt provider name ProviderName string // ResolverCert contains resolver certificate. ResolverCert *Cert // UDPSize is the default buffer size to use to read incoming UDP messages. // If not set it defaults to defaultUDPSize (1252 B). UDPSize int // Handler to invoke. If nil, uses DefaultHandler. Handler Handler // contains filtered or unexported fields }
Server is a simple DNSCrypt server implementation
func (*Server) ServeTCP ¶
ServeTCP listens to TCP connections, queries are then processed by Server.Handler. It blocks the calling goroutine and to stop it you need to close the listener or call Server.Shutdown.
type ServerDNSCrypt ¶ added in v2.1.2
type ServerDNSCrypt interface { // ServeTCP listens to TCP connections, queries are then processed by Server.Handler. // It blocks the calling goroutine and to stop it you need to close the listener // or call ServerDNSCrypt.Shutdown. ServeTCP(l net.Listener) error // ServeUDP listens to UDP connections, queries are then processed by Server.Handler. // It blocks the calling goroutine and to stop it you need to close the listener // or call ServerDNSCrypt.Shutdown. ServeUDP(l *net.UDPConn) error // Shutdown tries to gracefully shutdown the server. It waits until all // connections are processed and only after that it leaves the method. // If context deadline is specified, it will exit earlier // or call ServerDNSCrypt.Shutdown. Shutdown(ctx context.Context) error }
ServerDNSCrypt is an interface for a DNSCrypt server
type TCPResponseWriter ¶
type TCPResponseWriter struct {
// contains filtered or unexported fields
}
TCPResponseWriter is the ResponseWriter implementation for TCP
func (*TCPResponseWriter) LocalAddr ¶
func (w *TCPResponseWriter) LocalAddr() net.Addr
LocalAddr is the server socket local address
func (*TCPResponseWriter) RemoteAddr ¶
func (w *TCPResponseWriter) RemoteAddr() net.Addr
RemoteAddr is the client's address
type UDPResponseWriter ¶
type UDPResponseWriter struct {
// contains filtered or unexported fields
}
UDPResponseWriter is the ResponseWriter implementation for UDP
func (*UDPResponseWriter) LocalAddr ¶
func (w *UDPResponseWriter) LocalAddr() net.Addr
LocalAddr is the server socket local address
func (*UDPResponseWriter) RemoteAddr ¶
func (w *UDPResponseWriter) RemoteAddr() net.Addr
RemoteAddr is the client's address
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package main is responsible for the command-line interface.
|
Package main is responsible for the command-line interface. |
Package xsecretbox implements encryption/decryption of a message using specified keys
|
Package xsecretbox implements encryption/decryption of a message using specified keys |