### Basic DNS Proxy Setup Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/00-START-HERE.md This Go code demonstrates the essential steps to create and start a basic DNS proxy. It involves creating an upstream DNS client, configuring the proxy with upstream servers and listen addresses, and then starting the proxy. Ensure necessary imports are included. ```go u, _ := upstream.AddressToUpstream("8.8.8.8:53", nil) conf := &proxy.Config{ UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{u}, }, UDPListenAddr: []*net.UDPAddr{ {IP: net.ParseIP("0.0.0.0"), Port: 53}, }, } p, _ := proxy.New(conf) ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) p.Start(ctx) // Now proxy is running on port 53! ``` -------------------------------- ### Complete dnsproxy Setup with Fastest IP Selection Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/fastip.md This Go code demonstrates a complete setup for the dnsproxy, configuring it to use the `UpstreamModeFastestAddr` for selecting the fastest upstream IP addresses. It includes creating upstreams, setting a ping timeout, and starting the proxy. Ensure you have the necessary imports for `context`, `log`, `net`, `slog`, `time`, and the dnsproxy packages. ```go package main import ( "context" "log" "net" "net/slog" "time" "github.com/AdguardTeam/dnsproxy/fastip" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" ) func main() { // Create upstreams upstreams := make([]upstream.Upstream, 0) addresses := []string{ "8.8.8.8:53", "1.1.1.1:53", "208.67.222.222:53", } for _, addr := range addresses { u, err := upstream.AddressToUpstream(addr, nil) if err != nil { log.Fatalf("Failed to create upstream: %v", err) } upstreams = append(upstreams, u) } defer func() { for _, u := range upstreams { u.Close() } }() // Configure proxy with fastest address mode conf := &proxy.Config{ Logger: slog.Default(), UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: upstreams, }, UpstreamMode: proxy.UpstreamModeFastestAddr, FastestPingTimeout: 2 * time.Second, UDPListenAddr: []*net.UDPAddr{ {IP: net.ParseIP("127.0.0.1"), Port: 5353}, }, } p, err := proxy.New(conf) if err != nil { log.Fatal(err) } // Start proxy ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := p.Start(ctx); err != nil { log.Fatal(err) } defer p.Shutdown(context.Background()) // Proxy is running and will select fastest IPs select {} } ``` -------------------------------- ### Complete DoH Server Setup Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md This Go program demonstrates a full DoH server setup, including configuring upstreams, loading TLS certificates, and setting various proxy options like timeouts and cache. ```go package main import ( "context" "crypto/tls" "log" "net" "net/netip" "net/slog" "net/url" "time" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" ) func main() { // Create upstreams upstreams := make([]upstream.Upstream, 0) for _, addr := range []string{"8.8.8.8:53", "1.1.1.1:53"} { u, err := upstream.AddressToUpstream(addr, nil) if err != nil { log.Fatal(err) } upstreams = append(upstreams, u) } // Load certificate cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem") if err != nil { log.Fatal(err) } // Create config conf := &proxy.Config{ Logger: slog.Default(), // DoH configuration HTTPConfig: &proxy.HTTPConfig{ ListenAddresses: []netip.AddrPort{ netip.MustParseAddrPort("0.0.0.0:443"), }, HTTP3Enabled: true, Userinfo: url.UserPassword("admin", "secret"), ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, }, // TLS TLSConfig: &tls.Config{ Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS12, }, // Upstreams UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: upstreams, }, // Cache CacheEnabled: true, CacheSizeBytes: 256 * 1024, } // Create proxy p, err := proxy.New(conf) if err != nil { log.Fatal(err) } // Start ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := p.Start(ctx); err != nil { log.Fatal(err) } log.Println("DoH server running on https://0.0.0.0:443") defer p.Shutdown(context.Background()) select {} } ``` -------------------------------- ### Create and Start a Basic DNS Proxy Server Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/README.md This snippet demonstrates how to create a basic DNS proxy server using the dnsproxy library. It configures upstream resolvers and starts the proxy. Ensure necessary imports like 'net', 'context', 'time', and 'log' are available. ```go u, _ := upstream.AddressToUpstream("8.8.8.8:53", nil) conf := &proxy.Config{ UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{u}, }, UDPListenAddr: []*net.UDPAddr{ {IP: net.ParseIP("0.0.0.0"), Port: 53}, }, } p, err := proxy.New(conf) if err != nil { log.Fatal(err) } ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) p.Start(ctx) deffer p.Shutdown(context.Background()) ``` -------------------------------- ### HTTP Basic Authentication Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Example GET request with Host header and HTTP Basic Authentication. ```http GET /dns-query?dns=AAAA== HTTP/1.1 Host: dns.example.com Authorization: Basic YWRtaW46c2VjcmV0 ``` -------------------------------- ### Example: Handling NotBootstrapError Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/errors.md This example demonstrates how to check if an error is a NotBootstrapError when creating an upstream resolver. It shows how to unwrap the underlying error if the upstream cannot be used for bootstrapping. ```go resolver, err := upstream.NewUpstreamResolver("https://dns.google/dns-query", &upstream.Options{ Timeout: 5 * time.Second, }) if err != nil { var bootstrapErr upstream.NotBootstrapError if errors.As(err, &bootstrapErr) { log.Printf("Upstream cannot bootstrap others: %v", err.Unwrap()) } else { log.Printf("Failed to create upstream: %v", err) } } else { // Resolver works fine for normal queries // but cannot be used to bootstrap other upstreams } ``` -------------------------------- ### Start Proxy Server Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/proxy.md Starts the DNS proxy server, binding to configured listeners and initiating request handlers. Requires a context for controlling startup. ```APIDOC ## Start Proxy Server ### Description Starts the proxy server by binding to all configured listeners and starting request handlers. ### Function Signature ```go func (p *Proxy) Start(ctx context.Context) (err error) ``` ### Parameters #### Path Parameters - **ctx** (context.Context) - Required - Context for controlling startup ### Returns Error if binding fails or listeners cannot be established. ### Example ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := p.Start(ctx); err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Example HTTPConfig Initialization Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/configuration.md Demonstrates how to initialize an HTTPConfig struct with custom settings for listen addresses, timeouts, HTTP/3, and user credentials. ```go httpConfig := &proxy.HTTPConfig{ ListenAddresses: []netip.AddrPort{ netip.MustParseAddrPort("0.0.0.0:443"), }, ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, HTTP3Enabled: true, Userinfo: url.UserPassword("admin", "secret"), } conf := &proxy.Config{ HTTPConfig: httpConfig, TLSConfig: tlsConfig, // ... other fields } ``` -------------------------------- ### Full DNSProxy Configuration Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/configuration.md Demonstrates how to create a comprehensive configuration for the DNSProxy, including network, upstream, cache, feature flags, and DoH settings. ```go conf := &proxy.Config{ Logger: slog.Default(), // Network configuration UDPListenAddr: []*net.UDPAddr{ {IP: net.ParseIP("0.0.0.0"), Port: 53}, }, TCPListenAddr: []*net.TCPAddr{ {IP: net.ParseIP("0.0.0.0"), Port: 53}, }, // Upstream configuration UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{upstreamA, upstreamB}, }, Fallbacks: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{fallbackUpstream}, }, // Cache configuration CacheEnabled: true, CacheSizeBytes: 256 * 1024, CacheMinTTL: 60, CacheMaxTTL: 3600, // Feature flags DNSSECEnabled: true, RefuseAny: true, EnableEDNSClientSubnet: true, // DoH configuration HTTPConfig: &proxy.HTTPConfig{ ListenAddresses: []netip.AddrPort{ netip.MustParseAddrPort("0.0.0.0:443"), }, HTTP3Enabled: true, ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, }, TLSConfig: tlsConfig, } proxy, err := proxy.New(conf) ``` -------------------------------- ### QueryStatistics Method Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/dns-context.md Demonstrates how to retrieve and use query statistics after a DNS resolution. ```go dctx := &proxy.DNSContext{ Req: request, Proto: proxy.ProtoUDP, Addr: clientAddr, } err := p.Resolve(ctx, dctx) stats := dctx.QueryStatistics() if stats != nil { fmt.Printf("Query took %v\n", stats.Total()) } ``` -------------------------------- ### Rate Limiting Middleware Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md Example demonstrating how to create and apply a rate-limiting middleware to the request handler. ```APIDOC ## Rate Limiting Middleware ### Description This example shows how to integrate rate limiting into the DNS proxy by wrapping the base handler with a rate-limiting middleware. ### Usage Example ```go func createProxyWithRateLimit() (*proxy.Proxy, error) { // Create base configuration conf := &proxy.Config{ // ... other config } // Create proxy p, err := proxy.New(conf) if err != nil { return nil, err } // Create rate limit middleware rlConfig := &ratelimit.Config{ Logger: slog.Default(), Ratelimit: 100, // 100 requests per second SubnetLenIPv4: 24, SubnetLenIPv6: 56, } rlMiddleware := ratelimit.NewMiddleware(rlConfig) // Wrap handler with middleware baseHandler := p.RequestHandler p.RequestHandler = proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return rlMiddleware.Wrap( proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return px.Resolve(ctx, dctx) }), ).ServeDNS(ctx, px, dctx) }) return p, nil } ``` ``` -------------------------------- ### Example Upstreams Configuration Parsing Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/configuration.md Shows how to parse a list of strings into an UpstreamConfig, including default upstreams, local domain configurations, and subdomain exclusions. ```go lines := []string{ "# Default upstreams", "8.8.8.8:53", "1.1.1.1:53", "", "# Local domain", "[/local.lan/]192.168.1.1:53", "", "# Exclude subdomain", "[/api.example.com/]#", } conf, err := proxy.ParseUpstreamsConfig(lines, nil) if err != nil { log.Fatal(err) } def conf.Close() { conf.Close() } ``` -------------------------------- ### Example Handler Using ErrDrop Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md Demonstrates how to use ErrDrop within a handler to block specific domain queries. ```go handler := proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { // Block ads domain if dctx.Req.Question[0].Name == "ads.example.com." { return proxy.ErrDrop } return p.Resolve(ctx, dctx) }) ``` -------------------------------- ### Go DoH Client Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md A Go function to query a DoH server. It constructs a DNS query, encodes it, sends an HTTP GET request with basic authentication, and parses the DNS response. ```go import ( "context" "crypto/tls" "encoding/base64" "fmt" "io" "net/http" "github.com/miekg/dns" ) func queryDoH(ctx context.Context) (*dns.Msg, error) { // Create query q := &dns.Msg{} q.SetQuestion("example.com.", dns.TypeA) wire, _ := q.Pack() // Prepare request encoded := base64.RawURLEncoding.EncodeToString(wire) req, _ := http.NewRequestWithContext( ctx, http.MethodGet, fmt.Sprintf("https://dns.example.com/dns-query?dns=%s", encoded), nil, ) req.SetBasicAuth("admin", "secret") // Send client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, }, } resp, _ := client.Do(req) defer resp.Body.Close() // Parse response body, _ := io.ReadAll(resp.Body) answer := &dns.Msg{} answer.Unpack(body) return answer, nil } ``` -------------------------------- ### Example: Creating and Using Multiple Upstreams Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/upstream.md Demonstrates how to create multiple upstream DNS servers using different protocols (IP, DoT, DoH), query them in parallel, and handle potential errors. Includes cleanup of upstream resources. ```go opts := &upstream.Options{ Timeout: 5 * time.Second, } upstreams := make([]upstream.Upstream, 0) // Add multiple DNS servers addresses := []string{ "8.8.8.8:53", "tls://dns.google:853", "https://dns.google/dns-query", } for _, addr := range addresses { u, err := upstream.AddressToUpstream(addr, opts) if err != nil { log.Printf("Failed to create upstream for %s: %v", addr, err) continue } upstreams = append(upstreams, u) } // Use upstreams req := &dns.Msg{} req.SetQuestion("example.com.", dns.TypeA) resp, resolved, err := upstream.ExchangeParallel(upstreams, req) if err != nil { log.Fatal(err) } fmt.Printf("Resolved by %s\n", resolved.Address()) // Cleanup for _, u := range upstreams { u.Close() } ``` -------------------------------- ### Example: Handling ErrNoReply Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/errors.md This example demonstrates how to detect and log when all upstreams fail to respond using the ErrNoReply error. ```go results, err := upstream.ExchangeAll(upstreams, request) if err != nil { if errors.Is(err, upstream.ErrNoReply) { log.Println("All upstreams failed to respond") } } ``` -------------------------------- ### cURL DoH GET and POST Requests Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Examples of making DNS queries to a DoH server using cURL. Demonstrates both GET and POST request methods. ```bash # GET request curl "https://dns.example.com/dns-query?dns=AAAA..." \ --cert client.crt --key client.key # POST request dig @dns.example.com +https example.com A ``` -------------------------------- ### Run DNS proxy with Google DNS Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS proxy on 0.0.0.0:53 using Google DNS as the upstream server. ```shell ./dnsproxy -u 8.8.8.8:53 ``` -------------------------------- ### Rate Limiting Middleware Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md Demonstrates creating a proxy with rate limiting middleware. It configures rate limit parameters and wraps the base handler with the rate limiter. ```go package main import ( "context" "log" "net" "net/netip" "net/slog" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/ratelimit" "github.com/AdguardTeam/golibs/netutil" ) func createProxyWithRateLimit() (*proxy.Proxy, error) { // Create base configuration conf := &proxy.Config{ // ... other config } // Create proxy p, err := proxy.New(conf) if err != nil { return nil, err } // Create rate limit middleware rlConfig := &ratelimit.Config{ Logger: slog.Default(), Ratelimit: 100, // 100 requests per second SubnetLenIPv4: 24, SubnetLenIPv6: 56, } rlMiddleware := ratelimit.NewMiddleware(rlConfig) // Wrap handler with middleware baseHandler := p.RequestHandler p.RequestHandler = proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return rlMiddleware.Wrap( proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return px.Resolve(ctx, dctx) }), ).ServeDNS(ctx, px, dctx) }) return p, nil } ``` -------------------------------- ### GET Request Example for DNS Query Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Example of a GET request to the /dns-query endpoint with a Base64-encoded DNS message. ```http GET /dns-query?dns=AAAA...== HTTP/1.1 Host: dns.example.com ``` -------------------------------- ### Run DNS-over-QUIC proxy Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS-over-QUIC proxy on 127.0.0.1:853, requiring TLS certificate and key files. ```shell ./dnsproxy -l 127.0.0.1 --quic-port=853 --tls-crt=example.crt --tls-key=example.key -u 8.8.8.8:53 -p 0 ``` -------------------------------- ### Start the DNS Proxy server Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/proxy.md Initiate the proxy server's operation by binding to configured listeners and activating request handlers. Use a context with a timeout to control startup duration. ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) deffer cancel() if err := p.Start(ctx); err != nil { log.Fatal(err) } ``` -------------------------------- ### QueryStatistics Total Method Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/dns-context.md Demonstrates retrieving the total resolution time for a DNS query using the QueryStatistics method. ```go dctx := &proxy.DNSContext{ Req: request, Proto: proxy.ProtoUDP, Addr: clientAddr, } err := p.Resolve(ctx, dctx) if err == nil { stats := dctx.QueryStatistics() if stats != nil { log.Printf("Query resolved in %v", stats.Total()) } } ``` -------------------------------- ### Run DNS Proxy container with default configuration Source: https://github.com/adguardteam/dnsproxy/blob/master/docker/README.md Starts the container using the default configuration file and exposes standard DNS ports. ```shell docker run --name dnsproxy \ -p 53:53/tcp -p 53:53/udp \ adguard/dnsproxy ``` -------------------------------- ### Run DNS proxy with verbose logging Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS proxy with verbose logging enabled, writing output to log.txt. ```shell ./dnsproxy -u 8.8.8.8:53 -v -o log.txt ``` -------------------------------- ### Example: Handling ErrNoUpstreams Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/errors.md This example shows how to check for and handle the ErrNoUpstreams error when performing parallel upstream exchanges. ```go upstreams := []upstream.Upstream{} resp, resolved, err := upstream.ExchangeParallel(upstreams, request) if err != nil { if errors.Is(err, upstream.ErrNoUpstreams) { log.Println("No upstreams configured") } } ``` -------------------------------- ### Run DNS Proxy container with command-line arguments Source: https://github.com/adguardteam/dnsproxy/blob/master/docker/README.md Starts the container using specific command-line arguments to set the upstream DNS server. ```shell docker run --name dnsproxy_google_dns \ -p 53:53/tcp -p 53:53/udp \ adguard/dnsproxy \ -u 8.8.8.8:53 ``` -------------------------------- ### Using DNS Proxy as an HTTP Handler in Go Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Demonstrates how to use the DNS proxy as an http.Handler with a custom ServeMux and start an HTTPS server. ```go p, _ := proxy.New(conf) mux := http.NewServeMux() mux.Handle("/dns-query", p) http.ListenAndServeTLS(":443", "cert.pem", "key.pem", mux) ``` -------------------------------- ### Custom Logging Middleware Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md An example of a custom logging middleware that logs DNS queries and responses, including request details and processing duration. It wraps a handler and logs before and after the handler processes the request. ```go loggingMiddleware := proxy.MiddlewareFunc(func(h proxy.Handler) proxy.Handler { return proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { start := time.Now() // Log request if dctx.Req != nil && len(dctx.Req.Question) > 0 { q := dctx.Req.Question[0] log.Printf("[%s] %s %s from %s", time.Now().Format("15:04:05"), q.Name, dns.TypeToString[q.Qtype], dctx.Addr, ) } // Process request err := h.ServeDNS(ctx, p, dctx) // Log response duration := time.Since(start) if dctx.Res != nil { log.Printf("Response: %d answers in %v", len(dctx.Res.Answer), duration) } else { log.Printf("No response in %v", duration) } return err }) }) ``` -------------------------------- ### Example: Creating Multiple Upstreams Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/upstream.md Demonstrates how to create and use multiple upstream DNS resolvers, including adding them, performing a parallel exchange, and cleaning up resources. ```APIDOC ## Example: Creating Multiple Upstreams ```go opts := &upstream.Options{ Timeout: 5 * time.Second, } upstreams := make([]upstream.Upstream, 0) // Add multiple DNS servers addresses := []string{ "8.8.8.8:53", "tls://dns.google:853", "https://dns.google/dns-query", } for _, addr := range addresses { u, err := upstream.AddressToUpstream(addr, opts) if err != nil { log.Printf("Failed to create upstream for %s: %v", addr, err) continue } upstreams = append(upstreams, u) } // Use upstreams req := &dns.Msg{} req.SetQuestion("example.com.", dns.TypeA) resp, resolved, err := upstream.ExchangeParallel(upstreams, req) if err != nil { log.Fatal(err) } fmt.Printf("Resolved by %s\n", resolved.Address()) // Cleanup for _, u := range upstreams { u.Close() } ``` ``` -------------------------------- ### Example: Blocking a specific IP with ErrDrop Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/errors.md This example demonstrates how to use ErrDrop within a proxy handler to block requests from a specific IP address. ```go handler := proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { // Block requests from a specific IP if dctx.Addr.Addr().String() == "192.168.1.100" { return proxy.ErrDrop } return p.Resolve(ctx, dctx) }) ``` -------------------------------- ### Run DNS proxy with multiple upstreams Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS proxy on 127.0.0.1:5353 with multiple upstream servers configured. ```shell ./dnsproxy -l 127.0.0.1 -p 5353 -u 8.8.8.8:53 -u 1.1.1.1:53 ``` -------------------------------- ### POST Request Example for DNS Query Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Example of a POST request to the /dns-query endpoint with raw DNS message data in the body. ```http POST /dns-query HTTP/1.1 Host: dns.example.com Content-Type: application/dns-message Content-Length: 29 [binary DNS message data] ``` -------------------------------- ### Run DNS-over-TLS proxy Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS-over-TLS proxy on 127.0.0.1:853, requiring TLS certificate and key files. ```shell ./dnsproxy -l 127.0.0.1 --tls-port=853 --tls-crt=example.crt --tls-key=example.key -u 8.8.8.8:53 -p 0 ``` -------------------------------- ### Run DNS-over-HTTPS proxy with HTTP/3 Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS-over-HTTPS proxy on 127.0.0.1:443 with HTTP/3 support enabled, requiring TLS certificate and key files. ```shell ./dnsproxy -l 127.0.0.1 --https-port=443 --http3 --tls-crt=example.crt --tls-key=example.key -u 8.8.8.8:53 -p 0 ``` -------------------------------- ### Run DNSCrypt proxy Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNSCrypt proxy on 127.0.0.1:443, requiring a DNSCrypt configuration file. ```shell ./dnsproxy -l 127.0.0.1 --dnscrypt-config=./dnscrypt-config.yaml --dnscrypt-port=443 --upstream=8.8.8.8:53 -p 0 ``` -------------------------------- ### Run DNS-over-HTTPS proxy Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS-over-HTTPS proxy on 127.0.0.1:443, requiring TLS certificate and key files. ```shell ./dnsproxy -l 127.0.0.1 --https-port=443 --tls-crt=example.crt --tls-key=example.key -u 8.8.8.8:53 -p 0 ``` -------------------------------- ### CustomUpstreamConfig Usage Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/dns-context.md Illustrates how to use CustomUpstreamConfig to specify a special upstream for a request. ```go dctx := &proxy.DNSContext{ Req: request, Proto: proxy.ProtoUDP, Addr: clientAddr, CustomUpstreamConfig: &proxy.CustomUpstreamConfig{ UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{specialUpstream}, }, }, } err := p.Resolve(ctx, dctx) ``` -------------------------------- ### Integrating Rate Limiter Middleware Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/ratelimit.md This Go code demonstrates how to create and apply the rate limiting middleware to a DNSProxy instance. It shows the setup of upstreams, proxy configuration, rate limiter configuration with an allowlist, and applying the middleware to the request handler. ```go package main import ( "context" "log" "net" "net/netip" "net/slog" "time" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/ratelimit" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/netutil" ) func main() { // Create upstreams u, err := upstream.AddressToUpstream("8.8.8.8:53", nil) if err != nil { log.Fatal(err) } defer u.Close() // Create base proxy config conf := &proxy.Config{ Logger: slog.Default(), UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{u}, }, UDPListenAddr: []*net.UDPAddr{ {IP: net.ParseIP("0.0.0.0"), Port: 53}, }, } p, err := proxy.New(conf) if err != nil { log.Fatal(err) } // Create rate limit middleware allowlist := netutil.SliceSubnetSet{ netip.MustParsePrefix("127.0.0.1/32"), } rlConfig := &ratelimit.Config{ Logger: slog.Default(), Ratelimit: 100, AllowlistAddrs: allowlist, SubnetLenIPv4: 24, SubnetLenIPv6: 56, } middleware := ratelimit.NewMiddleware(rlConfig) // Apply middleware baseHandler := proxy.DefaultHandler{} p.RequestHandler = proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return middleware.Wrap( proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return baseHandler.ServeDNS(ctx, px, dctx) }), ).ServeDNS(ctx, px, dctx) }) // Start proxy ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := p.Start(ctx); err != nil { log.Fatal(err) } defer p.Shutdown(context.Background()) // Rate limiting is now active select {} } ``` -------------------------------- ### Run DNS proxy with rate limit, cache, and refuse ANY Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS proxy with a rate limit of 10 requests per second, enabled DNS cache, and configured to refuse type=ANY requests. ```shell ./dnsproxy -u 8.8.8.8:53 -r 10 --cache --refuse-any ``` -------------------------------- ### CustomUpstreamConfig Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/dns-context.md Illustrates how to use CustomUpstreamConfig to override upstream configurations and query logging for a specific DNS request. ```APIDOC ## CustomUpstreamConfig Example ### Description Allows overriding upstreams and query logging for a specific request using `CustomUpstreamConfig`. ### Example ```go dctx := &proxy.DNSContext{ Req: request, Proto: proxy.ProtoUDP, Addr: clientAddr, CustomUpstreamConfig: &proxy.CustomUpstreamConfig{ UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{specialUpstream}, }, }, } err := p.Resolve(ctx, dctx) ``` ``` -------------------------------- ### Implement Custom DNS Handler Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/README.md Provides an example of creating a custom DNS handler function that can implement custom logic, such as blocking specific requests, before forwarding them. ```go handler := proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { // Custom logic if shouldBlock(dctx) { return proxy.ErrDrop } return p.Resolve(ctx, dctx) }) conf.RequestHandler = handler ``` -------------------------------- ### HandlerFunc for Custom Functions Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md Allows ordinary functions to be used as DNS handlers. This example logs all queries before delegating to the proxy's Resolve method. ```go customHandler := proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { // Log all queries q := dctx.Req.Question[0] log.Printf("Query: %s %s from %s", q.Name, dns.TypeToString[q.Qtype], dctx.Addr) // Delegate to proxy return p.Resolve(ctx, dctx) }) conf := &proxy.Config{ RequestHandler: customHandler, // ... other config } ``` -------------------------------- ### Configure DoH Server Timeouts Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Example of setting read and write timeouts for the DoH server's HTTP configuration in Go. ```go conf.HTTPConfig.ReadTimeout = 5 * time.Second // Read timeout conf.HTTPConfig.WriteTimeout = 10 * time.Second // Write timeout ``` -------------------------------- ### Create Request Filtering Middleware Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md Implement a middleware function to filter DNS requests. This example drops loopback queries and ANY queries. ```go filterMiddleware := proxy.MiddlewareFunc(func(h proxy.Handler) proxy.Handler { return proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { // Drop queries from localhost if dctx.Addr.Addr().IsLoopback() { return proxy.ErrDrop } // Drop ANY queries if dctx.Req != nil && len(dctx.Req.Question) > 0 { if dctx.Req.Question[0].Qtype == dns.TypeANY { return proxy.ErrDrop } } // Process request return h.ServeDNS(ctx, p, dctx) }) }) ``` -------------------------------- ### Compose Handlers for Request Pipelines Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/handler.md Handlers can be chained together to create complex processing pipelines. This example shows logging, filtering, and default processing. ```go // Create a chain of handlers loggingHandler := createLoggingHandler() filterHandler := createFilterHandler() defaultHandler := proxy.DefaultHandler{} // Compose: logging -> filter -> default composed := proxy.HandlerFunc(func( ctx context.Context, p *proxy.Proxy, dctx *proxy.DNSContext, ) error { // Logging log.Printf("Handling request: %s", dctx.Req.Question[0].Name) // Filtering if shouldBlock(dctx) { return proxy.ErrDrop } // Default processing return defaultHandler.ServeDNS(ctx, p, dctx) }) ``` -------------------------------- ### Run DNS proxy with parallel upstream queries Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Starts a DNS proxy on 127.0.0.1:5353 with multiple upstreams and enables parallel queries to all configured upstream servers. ```shell ./dnsproxy -l 127.0.0.1 -p 5353 -u 8.8.8.8:53 -u 1.1.1.1:53 -u tls://dns.adguard.com --upstream-mode parallel ``` -------------------------------- ### Python DoH Client Example Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md A Python script demonstrating how to send a DNS query over DoH using the 'requests' and 'dnspython' libraries. Includes base64 encoding of the DNS query and parsing the response. ```python import base64 import requests import dns.message import dns.rdatatype # Create DNS query qname = dns.name.from_text('example.com.') q = dns.message.make_query(qname, dns.rdatatype.A) wire = q.to_wire() # Send via HTTPS dns_param = base64.urlsafe_b64encode(wire).decode().rstrip('=') resp = requests.get( 'https://dns.example.com/dns-query', params={'dns': dns_param}, auth=('admin', 'secret') ) # Parse response if resp.status_code == 200: answer = dns.message.from_wire(resp.content) print(answer) ``` -------------------------------- ### Get All Listener Addresses Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/proxy.md Retrieves all listener addresses for a specified protocol. Returns nil if the protocol is not configured or the server has not started. ```APIDOC ## Get All Listener Addresses ### Description Returns all listener addresses for the specified protocol. ### Function Signature ```go func (p *Proxy) Addrs(proto Proto) (addrs []net.Addr) ``` ### Parameters #### Path Parameters - **proto** (Proto) - Required - Protocol to get addresses for ### Returns Slice of network addresses, nil if protocol not configured or not started. ### Example ```go httpAddrs := p.Addrs(proxy.ProtoHTTPS) for _, addr := range httpAddrs { fmt.Printf("HTTPS listener: %s\n", addr) } ``` ``` -------------------------------- ### Get Listener Address Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/proxy.md Retrieves the listener address for a specified protocol. Returns nil if the protocol is not configured or the server has not started. ```APIDOC ## Get Listener Address ### Description Returns the listener address for the specified protocol. ### Function Signature ```go func (p *Proxy) Addr(proto Proto) (addr net.Addr) ``` ### Parameters #### Path Parameters - **proto** (Proto) - Required - Protocol to get address for ### Returns Network address or nil if protocol not configured or not started. ### Example ```go addr := p.Addr(proxy.ProtoUDP) if addr != nil { fmt.Printf("Listening on UDP: %s\n", addr) } ``` ``` -------------------------------- ### Get listener address for a specific protocol Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/proxy.md Retrieve the network address of the listener for a given protocol. Returns nil if the protocol is not configured or the listener has not started. ```go addr := p.Addr(proxy.ProtoUDP) if addr != nil { fmt.Printf("Listening on UDP: %s\n", addr) } ``` -------------------------------- ### Create a new DNS Proxy instance Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/proxy.md Instantiate a new Proxy with the required configuration. Ensure logger, UDP listen addresses, and upstream configuration are provided. The proxy should be shut down when no longer needed. ```go conf := &proxy.Config{ Logger: slog.Default(), UDPListenAddr: []*net.UDPAddr{{IP: net.ParseIP("0.0.0.0"), Port: 53}}, UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: []upstream.Upstream{}, }, } p, err := proxy.New(conf) if err != nil { log.Fatal(err) } deffer p.Shutdown(context.Background()) ``` -------------------------------- ### Proxy Startup Binding Failure Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/errors.md Handles errors from proxy.Start() when listeners fail to bind to addresses due to issues like 'Address already in use' or 'Permission denied'. ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) def cancel() if err := p.Start(ctx); err != nil { log.Printf("Failed to start proxy: %v", err) } ``` -------------------------------- ### Create Multiple Upstreams Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/README.md Demonstrates how to create multiple upstream DNS servers from a list of addresses. Handles potential errors during upstream creation. ```go addresses := []string{"8.8.8.8:53", "1.1.1.1:53"} upstreams := make([]upstream.Upstream, 0) for _, addr := range addresses { u, err := upstream.AddressToUpstream(addr, nil) if err != nil { log.Printf("Failed to create upstream: %v", err) continue } upstreams = append(upstreams, u) } ``` -------------------------------- ### DNS Query Endpoint Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Handles DNS queries using either GET or POST requests. The GET method uses a query parameter for the DNS message, while the POST method accepts the message in the request body. ```APIDOC ## GET /dns-query ### Description Recommended endpoint for DNS queries using the GET method. Queries are provided as a Base64-encoded DNS message via the 'dns' query parameter. ### Method GET ### Endpoint /dns-query ### Parameters #### Query Parameters - **dns** (string) - Required - Base64-encoded DNS message (RFC 4648 without padding) ### Request Example ``` GET /dns-query?dns=AAAA...== HTTP/1.1 Host: dns.example.com ``` ### Response #### Success Response (200) - **Body** (application/dns-message) - DNS message in wire format #### Response Example ``` [binary DNS message data] ``` ## POST /dns-query ### Description Recommended endpoint for DNS queries using the POST method. The DNS message is sent as raw bytes in the request body with the 'application/dns-message' Content-Type. ### Method POST ### Endpoint /dns-query ### Parameters #### Request Body - **Body** (application/dns-message) - Raw DNS message bytes ### Request Example ``` POST /dns-query HTTP/1.1 Host: dns.example.com Content-Type: application/dns-message Content-Length: 29 [binary DNS message data] ``` ### Response #### Success Response (200) - **Body** (application/dns-message) - DNS message in wire format #### Response Example ``` [binary DNS message data] ``` ``` -------------------------------- ### Create and Wrap Rate Limit Middleware Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/ratelimit.md Demonstrates how to create a rate limit middleware with custom configuration and wrap it around the DNS proxy's request handler. ```go conf := &proxy.Config{ // ... proxy config } p, err := proxy.New(conf) if err != nil { log.Fatal(err) } // Create rate limit middleware rlConfig := &ratelimit.Config{ Logger: slog.Default(), Ratelimit: 100, // 100 requests/second per client SubnetLenIPv4: 24, // /24 subnets count as one client SubnetLenIPv6: 56, // /56 subnets count as one client } rlMiddleware := ratelimit.NewMiddleware(rlConfig) // Wrap the handler baseHandler := proxy.DefaultHandler{} p.RequestHandler = proxy.HandlerFunc(func( ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext, ) error { return rlMiddleware.Wrap( proxy.HandlerFunc(func(ctx context.Context, px *proxy.Proxy, dctx *proxy.DNSContext) error { return px.Resolve(ctx, dctx) }), ).ServeDNS(ctx, px, dctx) }) ``` -------------------------------- ### HTTP 401 Unauthorized Response Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Example response when Basic Authentication is required but not provided. ```http HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="DNS" ``` -------------------------------- ### HTTP Basic Authentication Header Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Example of the Authorization header for HTTP Basic Authentication. ```http Authorization: Basic base64(username:password) ``` -------------------------------- ### Minimal dnsproxy Configuration Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/configuration.md Sets up a basic dnsproxy instance with a single upstream server and a listener on UDP port 53. Ensure necessary imports for upstream and proxy packages. ```go upstreams := make([]upstream.Upstream, 0) u, err := upstream.AddressToUpstream("8.8.8.8:53", nil) if err != nil { log.Fatal(err) } upsstreams = append(upstreams, u) conf := &proxy.Config{ UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: upstreams, }, UDPListenAddr: []*net.UDPAddr{ {IP: net.ParseIP("0.0.0.0"), Port: 53}, }, } p, err := proxy.New(conf) if err != nil { log.Fatal(err) } deffer p.Shutdown(context.Background()) ``` -------------------------------- ### Load Upstreams from File Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/configuration.md Demonstrates how to load upstream DNS server configurations from a text file. The format supports default upstreams and local domain specific configurations. ```text # Default upstreams 8.8.8.8:53 1.1.1.1:53 # Local domains [/local.lan/]192.168.1.1:53 ``` -------------------------------- ### HTTP Server Configuration with Basic Auth in Go Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/endpoints.md Configures an HTTP server with Basic Authentication enabled. Requires TLS configuration. ```go conf := &proxy.Config{ HTTPConfig: &proxy.HTTPConfig{ Userinfo: url.UserPassword("admin", "secretpassword"), ListenAddresses: []netip.AddrPort{ netip.MustParseAddrPort("0.0.0.0:443"), }, }, TLSConfig: tlsConfig, } ``` -------------------------------- ### Run DNS Proxy container with a configuration file Source: https://github.com/adguardteam/dnsproxy/blob/master/docker/README.md Mounts a local configuration file into the container to define proxy settings. ```shell docker run --name dnsproxy_google_dns \ -p 53:53/tcp -p 53:53/udp \ -v $PWD/config.yaml:/opt/dnsproxy/config.yaml \ adguard/dnsproxy ``` -------------------------------- ### Creating a DNSContext Manually Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/dns-context.md Shows how to manually construct a DNSContext for testing or custom scenarios before initiating resolution. ```go dctx := &proxy.DNSContext{ Req: dnsRequest, Proto: proxy.ProtoUDP, Addr: netip.AddrPortFrom(clientIP, 12345), } if err := p.Resolve(context.Background(), dctx); err != nil { log.Printf("Resolution error: %v", err) } if dctx.Res != nil { // Process response } ``` -------------------------------- ### Build DNS Proxy Source: https://github.com/adguardteam/dnsproxy/blob/master/README.md Build the dnsproxy application. Requires Go 1.26 or later. ```shell make build ``` -------------------------------- ### Enable Basic Caching Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/configuration.md Activate the DNS cache and set its size in bytes. Caching reduces latency by serving subsequent requests from memory. ```go conf := &proxy.Config{ CacheEnabled: true, CacheSizeBytes: 256 * 1024, // 256KB } ``` -------------------------------- ### Creating a DNSContext Source: https://github.com/adguardteam/dnsproxy/blob/master/_autodocs/api-reference/dns-context.md Demonstrates how to manually construct a DNSContext instance, typically used for testing or custom proxy integrations. ```APIDOC ## Creating a DNSContext ### Description Manually construct a `DNSContext` instance for testing or custom usage. ### Example ```go dctx := &proxy.DNSContext{ Req: dnsRequest, Proto: proxy.ProtoUDP, Addr: netip.AddrPortFrom(clientIP, 12345), } if err := p.Resolve(context.Background(), dctx); err != nil { log.Printf("Resolution error: %v", err) } if dctx.Res != nil { // Process response } ``` ```