2020-11-03 12:39:55 +00:00
|
|
|
// Package dnsforward contains a DNS forwarding server.
|
2018-11-28 12:40:56 +00:00
|
|
|
package dnsforward
|
|
|
|
|
|
|
|
import (
|
2021-02-01 14:06:09 +00:00
|
|
|
"errors"
|
2019-10-30 08:52:58 +00:00
|
|
|
"fmt"
|
2018-11-28 12:40:56 +00:00
|
|
|
"net"
|
2019-02-22 12:52:12 +00:00
|
|
|
"net/http"
|
2021-02-01 14:06:09 +00:00
|
|
|
"os"
|
2019-10-21 13:58:14 +01:00
|
|
|
"runtime"
|
2018-11-28 12:40:56 +00:00
|
|
|
"sync"
|
2018-12-05 11:03:41 +00:00
|
|
|
"time"
|
2018-11-28 12:40:56 +00:00
|
|
|
|
2020-10-30 10:32:02 +00:00
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/stats"
|
2018-12-24 13:58:48 +00:00
|
|
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
2019-02-25 13:44:22 +00:00
|
|
|
"github.com/AdguardTeam/golibs/log"
|
2018-11-28 12:40:56 +00:00
|
|
|
"github.com/miekg/dns"
|
2018-12-24 12:19:52 +00:00
|
|
|
)
|
|
|
|
|
2018-12-24 22:59:38 +00:00
|
|
|
// DefaultTimeout is the default upstream timeout
|
|
|
|
const DefaultTimeout = 10 * time.Second
|
|
|
|
|
2018-12-24 12:19:52 +00:00
|
|
|
const (
|
|
|
|
safeBrowsingBlockHost = "standard-block.dns.adguard.com"
|
|
|
|
parentalBlockHost = "family-block.dns.adguard.com"
|
2018-11-28 12:40:56 +00:00
|
|
|
)
|
|
|
|
|
2019-10-31 09:32:14 +00:00
|
|
|
var defaultDNS = []string{
|
2020-03-05 10:12:21 +00:00
|
|
|
"https://dns10.quad9.net/dns-query",
|
2019-10-31 09:32:14 +00:00
|
|
|
}
|
2020-03-05 10:12:21 +00:00
|
|
|
var defaultBootstrap = []string{"9.9.9.10", "149.112.112.10", "2620:fe::10", "2620:fe::fe:10"}
|
2019-10-31 09:32:14 +00:00
|
|
|
|
2020-09-10 10:32:36 +01:00
|
|
|
// Often requested by all kinds of DNS probes
|
|
|
|
var defaultBlockedHosts = []string{"version.bind", "id.server", "hostname.bind"}
|
|
|
|
|
2020-01-16 11:25:40 +00:00
|
|
|
var webRegistered bool
|
|
|
|
|
2018-12-05 09:52:23 +00:00
|
|
|
// Server is the main way to start a DNS server.
|
|
|
|
//
|
2018-11-28 12:40:56 +00:00
|
|
|
// Example:
|
2018-12-05 09:52:23 +00:00
|
|
|
// s := dnsforward.Server{}
|
|
|
|
// err := s.Start(nil) // will start a DNS server listening on default port 53, in a goroutine
|
|
|
|
// err := s.Reconfigure(ServerConfig{UDPListenAddr: &net.UDPAddr{Port: 53535}}) // will reconfigure running DNS server to listen on UDP port 53535
|
|
|
|
// err := s.Stop() // will stop listening on port 53535 and cancel all goroutines
|
|
|
|
// err := s.Start(nil) // will start listening again, on port 53535, in a goroutine
|
2018-11-28 12:40:56 +00:00
|
|
|
//
|
|
|
|
// The zero Server is empty and ready for use.
|
|
|
|
type Server struct {
|
2020-07-03 16:20:01 +01:00
|
|
|
dnsProxy *proxy.Proxy // DNS proxy instance
|
2020-12-17 10:32:46 +00:00
|
|
|
dnsFilter *dnsfilter.DNSFilter // DNS filter instance
|
2020-07-03 16:20:01 +01:00
|
|
|
dhcpServer dhcpd.ServerInterface // DHCP server instance (optional)
|
|
|
|
queryLog querylog.QueryLog // Query log instance
|
2020-06-23 10:13:13 +01:00
|
|
|
stats stats.Stats
|
|
|
|
access *accessCtx
|
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
ipset ipsetCtx
|
|
|
|
|
2020-08-18 10:36:52 +01:00
|
|
|
tableHostToIP map[string]net.IP // "hostname -> IP" table for internal addresses (DHCP)
|
|
|
|
tableHostToIPLock sync.Mutex
|
|
|
|
|
2020-06-23 10:13:13 +01:00
|
|
|
tablePTR map[string]string // "IP -> hostname" table for reverse lookup
|
|
|
|
tablePTRLock sync.Mutex
|
2019-05-24 12:49:26 +01:00
|
|
|
|
2019-12-11 09:38:58 +00:00
|
|
|
// DNS proxy instance for internal usage
|
|
|
|
// We don't Start() it and so no listen port is required.
|
|
|
|
internalProxy *proxy.Proxy
|
|
|
|
|
2020-01-16 11:25:40 +00:00
|
|
|
isRunning bool
|
2019-10-30 08:52:58 +00:00
|
|
|
|
2018-11-28 12:40:56 +00:00
|
|
|
sync.RWMutex
|
2019-05-15 13:08:15 +01:00
|
|
|
conf ServerConfig
|
2018-11-28 12:40:56 +00:00
|
|
|
}
|
|
|
|
|
2020-06-23 10:13:13 +01:00
|
|
|
// DNSCreateParams - parameters for NewServer()
|
|
|
|
type DNSCreateParams struct {
|
2020-12-17 10:32:46 +00:00
|
|
|
DNSFilter *dnsfilter.DNSFilter
|
2020-06-23 10:13:13 +01:00
|
|
|
Stats stats.Stats
|
|
|
|
QueryLog querylog.QueryLog
|
2020-07-03 16:20:01 +01:00
|
|
|
DHCPServer dhcpd.ServerInterface
|
2020-06-23 10:13:13 +01:00
|
|
|
}
|
|
|
|
|
2019-02-10 17:47:43 +00:00
|
|
|
// NewServer creates a new instance of the dnsforward.Server
|
2019-07-10 09:56:54 +01:00
|
|
|
// Note: this function must be called only once
|
2020-06-23 10:13:13 +01:00
|
|
|
func NewServer(p DNSCreateParams) *Server {
|
2021-02-04 17:35:13 +00:00
|
|
|
s := &Server{
|
|
|
|
dnsFilter: p.DNSFilter,
|
|
|
|
stats: p.Stats,
|
|
|
|
queryLog: p.QueryLog,
|
|
|
|
}
|
2020-06-23 10:13:13 +01:00
|
|
|
|
2020-08-24 18:06:53 +01:00
|
|
|
if p.DHCPServer != nil {
|
|
|
|
s.dhcpServer = p.DHCPServer
|
2020-06-23 10:13:13 +01:00
|
|
|
s.dhcpServer.SetOnLeaseChanged(s.onDHCPLeaseChanged)
|
|
|
|
s.onDHCPLeaseChanged(dhcpd.LeaseChangedAdded)
|
|
|
|
}
|
2019-10-31 09:32:14 +00:00
|
|
|
|
|
|
|
if runtime.GOARCH == "mips" || runtime.GOARCH == "mipsle" {
|
|
|
|
// Use plain DNS on MIPS, encryption is too slow
|
2019-10-31 09:43:33 +00:00
|
|
|
defaultDNS = defaultBootstrap
|
2019-10-31 09:32:14 +00:00
|
|
|
}
|
2019-07-10 09:56:54 +01:00
|
|
|
return s
|
2019-02-10 17:47:43 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 17:35:13 +00:00
|
|
|
// NewCustomServer creates a new instance of *Server with custom internal proxy.
|
|
|
|
func NewCustomServer(internalProxy *proxy.Proxy) *Server {
|
|
|
|
s := &Server{}
|
|
|
|
if internalProxy != nil {
|
|
|
|
s.internalProxy = internalProxy
|
|
|
|
}
|
|
|
|
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2019-10-30 08:52:58 +00:00
|
|
|
// Close - close object
|
2019-09-16 13:54:41 +01:00
|
|
|
func (s *Server) Close() {
|
|
|
|
s.Lock()
|
2019-10-09 17:51:26 +01:00
|
|
|
s.dnsFilter = nil
|
2019-09-16 13:54:41 +01:00
|
|
|
s.stats = nil
|
|
|
|
s.queryLog = nil
|
2019-12-11 09:38:58 +00:00
|
|
|
s.dnsProxy = nil
|
2021-01-29 15:53:39 +00:00
|
|
|
|
|
|
|
err := s.ipset.Close()
|
|
|
|
if err != nil {
|
|
|
|
log.Error("closing ipset: %s", err)
|
|
|
|
}
|
|
|
|
|
2019-09-16 13:54:41 +01:00
|
|
|
s.Unlock()
|
|
|
|
}
|
|
|
|
|
2019-10-30 08:52:58 +00:00
|
|
|
// WriteDiskConfig - write configuration
|
|
|
|
func (s *Server) WriteDiskConfig(c *FilteringConfig) {
|
2019-12-17 10:09:03 +00:00
|
|
|
s.RLock()
|
2019-12-12 12:04:29 +00:00
|
|
|
sc := s.conf.FilteringConfig
|
|
|
|
*c = sc
|
|
|
|
c.RatelimitWhitelist = stringArrayDup(sc.RatelimitWhitelist)
|
|
|
|
c.BootstrapDNS = stringArrayDup(sc.BootstrapDNS)
|
|
|
|
c.AllowedClients = stringArrayDup(sc.AllowedClients)
|
|
|
|
c.DisallowedClients = stringArrayDup(sc.DisallowedClients)
|
|
|
|
c.BlockedHosts = stringArrayDup(sc.BlockedHosts)
|
|
|
|
c.UpstreamDNS = stringArrayDup(sc.UpstreamDNS)
|
2019-12-17 10:09:03 +00:00
|
|
|
s.RUnlock()
|
2019-10-30 08:52:58 +00:00
|
|
|
}
|
|
|
|
|
2019-12-11 09:38:58 +00:00
|
|
|
// Resolve - get IP addresses by host name from an upstream server.
|
|
|
|
// No request/response filtering is performed.
|
|
|
|
// Query log and Stats are not updated.
|
|
|
|
// This method may be called before Start().
|
|
|
|
func (s *Server) Resolve(host string) ([]net.IPAddr, error) {
|
|
|
|
s.RLock()
|
|
|
|
defer s.RUnlock()
|
|
|
|
return s.internalProxy.LookupIPAddr(host)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange - send DNS request to an upstream server and receive response
|
|
|
|
// No request/response filtering is performed.
|
|
|
|
// Query log and Stats are not updated.
|
|
|
|
// This method may be called before Start().
|
|
|
|
func (s *Server) Exchange(req *dns.Msg) (*dns.Msg, error) {
|
|
|
|
s.RLock()
|
|
|
|
defer s.RUnlock()
|
|
|
|
|
|
|
|
ctx := &proxy.DNSContext{
|
|
|
|
Proto: "udp",
|
|
|
|
Req: req,
|
|
|
|
StartTime: time.Now(),
|
|
|
|
}
|
|
|
|
err := s.internalProxy.Resolve(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ctx.Res, nil
|
|
|
|
}
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
// Start starts the DNS server.
|
2019-12-11 09:38:58 +00:00
|
|
|
func (s *Server) Start() error {
|
2018-11-28 12:40:56 +00:00
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-02-02 12:13:12 +00:00
|
|
|
return s.startLocked()
|
2018-12-24 12:19:52 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
// startLocked starts the DNS server without locking. For internal use only.
|
|
|
|
func (s *Server) startLocked() error {
|
2019-12-11 09:38:58 +00:00
|
|
|
err := s.dnsProxy.Start()
|
|
|
|
if err == nil {
|
|
|
|
s.isRunning = true
|
2019-11-21 13:13:19 +00:00
|
|
|
}
|
2019-12-11 09:38:58 +00:00
|
|
|
return err
|
2019-11-21 13:13:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare the object
|
2019-12-11 09:38:58 +00:00
|
|
|
func (s *Server) Prepare(config *ServerConfig) error {
|
2020-09-02 12:13:45 +01:00
|
|
|
// Initialize the server configuration
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
2019-10-09 17:51:26 +01:00
|
|
|
if config != nil {
|
|
|
|
s.conf = *config
|
2019-12-16 14:04:30 +00:00
|
|
|
if s.conf.BlockingMode == "custom_ip" {
|
2021-01-13 13:56:05 +00:00
|
|
|
if s.conf.BlockingIPv4 == nil || s.conf.BlockingIPv6 == nil {
|
2020-11-05 12:20:57 +00:00
|
|
|
return fmt.Errorf("dns: invalid custom blocking IP address specified")
|
2019-12-16 14:04:30 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 09:32:14 +00:00
|
|
|
}
|
2019-10-30 08:52:58 +00:00
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Set default values in the case if nothing is configured
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
|
|
|
s.initDefaultSettings()
|
2019-10-31 09:32:14 +00:00
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Initialize IPSET configuration
|
|
|
|
// --
|
2021-01-29 15:53:39 +00:00
|
|
|
err := s.ipset.init(s.conf.IPSETList)
|
|
|
|
if err != nil {
|
2021-02-01 17:44:15 +00:00
|
|
|
if !errors.Is(err, os.ErrInvalid) && !errors.Is(err, os.ErrPermission) {
|
2021-02-01 14:06:09 +00:00
|
|
|
return fmt.Errorf("cannot initialize ipset: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ipset cannot currently be initialized if the server was
|
|
|
|
// installed from Snap or when the user or the binary doesn't
|
2021-02-01 17:44:15 +00:00
|
|
|
// have the required permissions, or when the kernel doesn't
|
|
|
|
// support netfilter.
|
2021-02-01 14:06:09 +00:00
|
|
|
//
|
|
|
|
// Log and go on.
|
2021-02-01 17:44:15 +00:00
|
|
|
//
|
|
|
|
// TODO(a.garipov): The Snap problem can probably be solved if
|
2021-02-02 10:35:23 +00:00
|
|
|
// we add the netlink-connector interface plug.
|
2021-02-01 14:06:09 +00:00
|
|
|
log.Error("cannot initialize ipset: %s", err)
|
2021-01-29 15:53:39 +00:00
|
|
|
}
|
2020-09-02 12:13:45 +01:00
|
|
|
|
|
|
|
// Prepare DNS servers settings
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
2021-01-29 15:53:39 +00:00
|
|
|
err = s.prepareUpstreamSettings()
|
2019-10-31 09:32:14 +00:00
|
|
|
if err != nil {
|
2020-05-08 16:39:37 +01:00
|
|
|
return err
|
2019-10-31 09:32:14 +00:00
|
|
|
}
|
2018-12-05 11:03:41 +00:00
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Create DNS proxy configuration
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
|
|
|
var proxyConfig proxy.Config
|
|
|
|
proxyConfig, err = s.createProxyConfig()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-12-24 12:19:52 +00:00
|
|
|
}
|
2018-11-28 12:40:56 +00:00
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Prepare a DNS proxy instance that we use for internal DNS queries
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
|
|
|
s.prepareIntlProxy()
|
2019-12-11 09:38:58 +00:00
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Initialize DNS access module
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
2019-10-30 12:11:16 +00:00
|
|
|
s.access = &accessCtx{}
|
2019-10-31 09:32:14 +00:00
|
|
|
err = s.access.Init(s.conf.AllowedClients, s.conf.DisallowedClients, s.conf.BlockedHosts)
|
2019-05-24 12:49:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Register web handlers if necessary
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
2020-01-16 11:25:40 +00:00
|
|
|
if !webRegistered && s.conf.HTTPRegister != nil {
|
|
|
|
webRegistered = true
|
2019-10-30 08:52:58 +00:00
|
|
|
s.registerHandlers()
|
|
|
|
}
|
|
|
|
|
2020-09-02 12:13:45 +01:00
|
|
|
// Create the main DNS proxy instance
|
2020-05-08 16:39:37 +01:00
|
|
|
// --
|
2018-12-24 12:19:52 +00:00
|
|
|
s.dnsProxy = &proxy.Proxy{Config: proxyConfig}
|
2019-11-21 13:13:19 +00:00
|
|
|
return nil
|
2018-12-24 12:27:14 +00:00
|
|
|
}
|
2018-12-24 12:19:52 +00:00
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
// Stop stops the DNS server.
|
2018-11-28 12:40:56 +00:00
|
|
|
func (s *Server) Stop() error {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2021-02-02 12:13:12 +00:00
|
|
|
return s.stopLocked()
|
2018-12-24 12:19:52 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
// stopLocked stops the DNS server without locking. For internal use only.
|
|
|
|
func (s *Server) stopLocked() error {
|
2018-12-24 12:19:52 +00:00
|
|
|
if s.dnsProxy != nil {
|
|
|
|
err := s.dnsProxy.Stop()
|
2018-11-28 12:40:56 +00:00
|
|
|
if err != nil {
|
2020-11-05 12:20:57 +00:00
|
|
|
return fmt.Errorf("could not stop the DNS server properly: %w", err)
|
2018-11-28 12:40:56 +00:00
|
|
|
}
|
|
|
|
}
|
2018-12-05 11:21:48 +00:00
|
|
|
|
2019-12-11 09:38:58 +00:00
|
|
|
s.isRunning = false
|
2019-08-26 09:54:38 +01:00
|
|
|
return nil
|
2018-11-28 12:40:56 +00:00
|
|
|
}
|
|
|
|
|
2018-12-24 12:19:52 +00:00
|
|
|
// IsRunning returns true if the DNS server is running
|
2018-11-28 13:43:50 +00:00
|
|
|
func (s *Server) IsRunning() bool {
|
|
|
|
s.RLock()
|
2019-12-11 09:38:58 +00:00
|
|
|
defer s.RUnlock()
|
|
|
|
return s.isRunning
|
2018-11-28 13:43:50 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 09:32:14 +00:00
|
|
|
// Reconfigure applies the new configuration to the DNS server
|
2018-12-24 12:19:52 +00:00
|
|
|
func (s *Server) Reconfigure(config *ServerConfig) error {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
2018-11-28 12:40:56 +00:00
|
|
|
|
2018-12-24 12:19:52 +00:00
|
|
|
log.Print("Start reconfiguring the server")
|
2021-02-02 12:13:12 +00:00
|
|
|
err := s.stopLocked()
|
2018-12-24 12:19:52 +00:00
|
|
|
if err != nil {
|
2020-11-05 12:20:57 +00:00
|
|
|
return fmt.Errorf("could not reconfigure the server: %w", err)
|
2018-11-28 12:40:56 +00:00
|
|
|
}
|
2019-10-21 13:58:14 +01:00
|
|
|
|
2019-12-11 14:54:34 +00:00
|
|
|
// It seems that net.Listener.Close() doesn't close file descriptors right away.
|
|
|
|
// We wait for some time and hope that this fd will be closed.
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
2019-10-21 13:58:14 +01:00
|
|
|
|
2019-12-11 09:38:58 +00:00
|
|
|
err = s.Prepare(config)
|
|
|
|
if err != nil {
|
2020-11-05 12:20:57 +00:00
|
|
|
return fmt.Errorf("could not reconfigure the server: %w", err)
|
2019-12-11 09:38:58 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 12:13:12 +00:00
|
|
|
err = s.startLocked()
|
2018-12-24 12:19:52 +00:00
|
|
|
if err != nil {
|
2020-11-05 12:20:57 +00:00
|
|
|
return fmt.Errorf("could not reconfigure the server: %w", err)
|
2018-11-28 12:40:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-22 12:52:12 +00:00
|
|
|
// ServeHTTP is a HTTP handler method we use to provide DNS-over-HTTPS
|
|
|
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
s.RLock()
|
2019-12-12 12:00:10 +00:00
|
|
|
p := s.dnsProxy
|
2019-02-22 12:52:12 +00:00
|
|
|
s.RUnlock()
|
2019-12-12 12:00:10 +00:00
|
|
|
if p != nil { // an attempt to protect against race in case we're here after Close() was called
|
|
|
|
p.ServeHTTP(w, r)
|
|
|
|
}
|
2019-02-22 12:52:12 +00:00
|
|
|
}
|
2020-07-24 12:30:29 +01:00
|
|
|
|
|
|
|
// IsBlockedIP - return TRUE if this client should be blocked
|
2021-01-20 14:27:53 +00:00
|
|
|
func (s *Server) IsBlockedIP(ip net.IP) (bool, string) {
|
2020-07-24 12:30:29 +01:00
|
|
|
return s.access.IsBlockedIP(ip)
|
|
|
|
}
|