all: resync with master
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -217,7 +218,8 @@ func TestServer_clientIDFromDNSContext(t *testing.T) {
|
||||
}
|
||||
|
||||
srv := &Server{
|
||||
conf: ServerConfig{TLSConfig: tlsConf},
|
||||
conf: ServerConfig{TLSConfig: tlsConf},
|
||||
baseLogger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
@@ -158,7 +159,7 @@ type Config struct {
|
||||
// IpsetList is the ipset configuration that allows AdGuard Home to add IP
|
||||
// addresses of the specified domain names to an ipset list. Syntax:
|
||||
//
|
||||
// DOMAIN[,DOMAIN].../IPSET_NAME
|
||||
// DOMAIN[,DOMAIN].../IPSET_NAME[,IPSET_NAME]...
|
||||
//
|
||||
// This field is ignored if [IpsetListFileName] is set.
|
||||
IpsetList []string `yaml:"ipset"`
|
||||
@@ -301,6 +302,8 @@ type ServerConfig struct {
|
||||
|
||||
// UpstreamMode is a enumeration of upstream mode representations. See
|
||||
// [proxy.UpstreamModeType].
|
||||
//
|
||||
// TODO(d.kolyshev): Consider using [proxy.UpstreamMode].
|
||||
type UpstreamMode string
|
||||
|
||||
const (
|
||||
@@ -315,6 +318,7 @@ func (s *Server) newProxyConfig() (conf *proxy.Config, err error) {
|
||||
trustedPrefixes := netutil.UnembedPrefixes(srvConf.TrustedProxies)
|
||||
|
||||
conf = &proxy.Config{
|
||||
Logger: s.baseLogger.With(slogutil.KeyPrefix, "dnsproxy"),
|
||||
HTTP3: srvConf.ServeHTTP3,
|
||||
Ratelimit: int(srvConf.Ratelimit),
|
||||
RatelimitSubnetLenIPv4: srvConf.RatelimitSubnetLenIPv4,
|
||||
@@ -420,8 +424,6 @@ func parseBogusNXDOMAIN(confBogusNXDOMAIN []string) (subnets []netip.Prefix, err
|
||||
return subnets, nil
|
||||
}
|
||||
|
||||
const defaultBlockedResponseTTL = 3600
|
||||
|
||||
// initDefaultSettings initializes default settings if nothing
|
||||
// is configured
|
||||
func (s *Server) initDefaultSettings() {
|
||||
@@ -452,24 +454,24 @@ func (s *Server) initDefaultSettings() {
|
||||
|
||||
// prepareIpsetListSettings reads and prepares the ipset configuration either
|
||||
// from a file or from the data in the configuration file.
|
||||
func (s *Server) prepareIpsetListSettings() (err error) {
|
||||
func (s *Server) prepareIpsetListSettings() (ipsets []string, err error) {
|
||||
fn := s.conf.IpsetListFileName
|
||||
if fn == "" {
|
||||
return s.ipset.init(s.conf.IpsetList)
|
||||
return s.conf.IpsetList, nil
|
||||
}
|
||||
|
||||
// #nosec G304 -- Trust the path explicitly given by the user.
|
||||
data, err := os.ReadFile(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ipsets := stringutil.SplitTrimmed(string(data), "\n")
|
||||
ipsets = stringutil.FilterOut(ipsets, IsCommentOrEmpty)
|
||||
ipsets = stringutil.SplitTrimmed(string(data), "\n")
|
||||
ipsets = slices.DeleteFunc(ipsets, IsCommentOrEmpty)
|
||||
|
||||
log.Debug("dns: using %d ipset rules from file %q", len(ipsets), fn)
|
||||
|
||||
return s.ipset.init(ipsets)
|
||||
return ipsets, nil
|
||||
}
|
||||
|
||||
// loadUpstreams parses upstream DNS servers from the configured file or from
|
||||
@@ -690,7 +692,7 @@ func matchesDomainWildcard(host, pat string) (ok bool) {
|
||||
// the DNS names and patterns from certificate. dnsNames must be sorted.
|
||||
func anyNameMatches(dnsNames []string, sni string) (ok bool) {
|
||||
// Check sni is either a valid hostname or a valid IP address.
|
||||
if netutil.ValidateHostname(sni) != nil && net.ParseIP(sni) == nil {
|
||||
if !netutil.IsValidHostname(sni) && !netutil.IsValidIPString(sni) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
|
||||
// DialContext is an [aghnet.DialContextFunc] that uses s to resolve hostnames.
|
||||
@@ -28,7 +29,7 @@ func (s *Server) DialContext(ctx context.Context, network, addr string) (conn ne
|
||||
Timeout: time.Minute * 5,
|
||||
}
|
||||
|
||||
if net.ParseIP(host) != nil {
|
||||
if netutil.IsValidIPString(host) {
|
||||
return dialer.DialContext(ctx, network, addr)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/cache"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/netutil/sysresolv"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
@@ -121,12 +123,17 @@ type Server struct {
|
||||
// access drops disallowed clients.
|
||||
access *accessManager
|
||||
|
||||
// baseLogger is used to create loggers for other entities. It should not
|
||||
// have a prefix and must not be nil.
|
||||
baseLogger *slog.Logger
|
||||
|
||||
// localDomainSuffix is the suffix used to detect internal hosts. It
|
||||
// must be a valid domain name plus dots on each side.
|
||||
localDomainSuffix string
|
||||
|
||||
// ipset processes DNS requests using ipset data.
|
||||
ipset ipsetCtx
|
||||
// ipset processes DNS requests using ipset data. It must not be nil after
|
||||
// initialization. See [newIpsetHandler].
|
||||
ipset *ipsetHandler
|
||||
|
||||
// privateNets is the configured set of IP networks considered private.
|
||||
privateNets netutil.SubnetSet
|
||||
@@ -197,6 +204,10 @@ type DNSCreateParams struct {
|
||||
PrivateNets netutil.SubnetSet
|
||||
Anonymizer *aghnet.IPMut
|
||||
EtcHosts *aghnet.HostsContainer
|
||||
|
||||
// Logger is used as a base logger. It must not be nil.
|
||||
Logger *slog.Logger
|
||||
|
||||
LocalDomain string
|
||||
}
|
||||
|
||||
@@ -233,6 +244,7 @@ func NewServer(p DNSCreateParams) (s *Server, err error) {
|
||||
stats: p.Stats,
|
||||
queryLog: p.QueryLog,
|
||||
privateNets: p.PrivateNets,
|
||||
baseLogger: p.Logger,
|
||||
// TODO(e.burkov): Use some case-insensitive string comparison.
|
||||
localDomainSuffix: strings.ToLower(localDomainSuffix),
|
||||
etcHosts: etcHosts,
|
||||
@@ -596,11 +608,18 @@ func (s *Server) prepareLocalResolvers() (uc *proxy.UpstreamConfig, err error) {
|
||||
// the primary DNS proxy instance. It assumes s.serverLock is locked or the
|
||||
// Server not running.
|
||||
func (s *Server) prepareInternalDNS() (err error) {
|
||||
err = s.prepareIpsetListSettings()
|
||||
ipsetList, err := s.prepareIpsetListSettings()
|
||||
if err != nil {
|
||||
return fmt.Errorf("preparing ipset settings: %w", err)
|
||||
}
|
||||
|
||||
ipsetLogger := s.baseLogger.With(slogutil.KeyPrefix, "ipset")
|
||||
s.ipset, err = newIpsetHandler(context.TODO(), ipsetLogger, ipsetList)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
bootOpts := &upstream.Options{
|
||||
Timeout: DefaultTimeout,
|
||||
HTTPVersions: UpstreamHTTPVersions(s.conf.UseHTTP3Upstreams),
|
||||
@@ -664,6 +683,7 @@ func (s *Server) setupAddrProc() {
|
||||
s.addrProc = client.EmptyAddrProc{}
|
||||
} else {
|
||||
c := s.conf.AddrProcConf
|
||||
c.BaseLogger = s.baseLogger
|
||||
c.DialContext = s.DialContext
|
||||
c.PrivateSubnets = s.privateNets
|
||||
c.UsePrivateRDNS = s.conf.UsePrivateRDNS
|
||||
@@ -707,6 +727,7 @@ func validateBlockingMode(
|
||||
func (s *Server) prepareInternalProxy() (err error) {
|
||||
srvConf := s.conf
|
||||
conf := &proxy.Config{
|
||||
Logger: s.baseLogger.With(slogutil.KeyPrefix, "dnsproxy"),
|
||||
CacheEnabled: true,
|
||||
CacheSizeBytes: 4096,
|
||||
PrivateRDNSUpstreamConfig: srvConf.PrivateRDNSUpstreamConfig,
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/golibs/timeutil"
|
||||
@@ -99,6 +100,7 @@ func createTestServer(
|
||||
DHCPServer: dhcp,
|
||||
DNSFilter: f,
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -339,7 +341,10 @@ func TestServer_timeout(t *testing.T) {
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s, err := NewServer(DNSCreateParams{DNSFilter: createTestDNSFilter(t)})
|
||||
s, err := NewServer(DNSCreateParams{
|
||||
DNSFilter: createTestDNSFilter(t),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Prepare(srvConf)
|
||||
@@ -349,7 +354,10 @@ func TestServer_timeout(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("default", func(t *testing.T) {
|
||||
s, err := NewServer(DNSCreateParams{DNSFilter: createTestDNSFilter(t)})
|
||||
s, err := NewServer(DNSCreateParams{
|
||||
DNSFilter: createTestDNSFilter(t),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
s.conf.Config.UpstreamMode = UpstreamModeLoadBalance
|
||||
@@ -376,7 +384,9 @@ func TestServer_Prepare_fallbacks(t *testing.T) {
|
||||
ServePlainDNS: true,
|
||||
}
|
||||
|
||||
s, err := NewServer(DNSCreateParams{})
|
||||
s, err := NewServer(DNSCreateParams{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Prepare(srvConf)
|
||||
@@ -962,6 +972,7 @@ func TestBlockedCustomIP(t *testing.T) {
|
||||
DHCPServer: dhcp,
|
||||
DNSFilter: f,
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1127,6 +1138,7 @@ func TestRewrite(t *testing.T) {
|
||||
DHCPServer: dhcp,
|
||||
DNSFilter: f,
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1256,6 +1268,7 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
||||
},
|
||||
},
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
LocalDomain: localDomain,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -1341,6 +1354,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||
DHCPServer: dhcp,
|
||||
DNSFilter: flt,
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1392,24 +1406,29 @@ func TestNewServer(t *testing.T) {
|
||||
in DNSCreateParams
|
||||
wantErrMsg string
|
||||
}{{
|
||||
name: "success",
|
||||
in: DNSCreateParams{},
|
||||
name: "success",
|
||||
in: DNSCreateParams{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
},
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
name: "success_local_tld",
|
||||
in: DNSCreateParams{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
LocalDomain: "mynet",
|
||||
},
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
name: "success_local_domain",
|
||||
in: DNSCreateParams{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
LocalDomain: "my.local.net",
|
||||
},
|
||||
wantErrMsg: "",
|
||||
}, {
|
||||
name: "bad_local_domain",
|
||||
in: DNSCreateParams{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
LocalDomain: "!!!",
|
||||
},
|
||||
wantErrMsg: `local domain: bad domain name "!!!": ` +
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -57,6 +58,7 @@ func TestHandleDNSRequest_handleDNSRequest(t *testing.T) {
|
||||
},
|
||||
DNSFilter: f,
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -229,6 +231,7 @@ func TestHandleDNSRequest_filterDNSResponse(t *testing.T) {
|
||||
DHCPServer: &testDHCP{},
|
||||
DNSFilter: f,
|
||||
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
|
||||
}, {
|
||||
name: "upstream_dns_bad",
|
||||
wantSet: `validating dns config: upstream servers: parsing error at index 0: ` +
|
||||
`cannot prepare the upstream: invalid address !!!: bad hostname "!!!": ` +
|
||||
`cannot prepare the upstream: invalid address !!!: bad domain name "!!!": ` +
|
||||
`bad top-level domain name label "!!!": bad top-level domain name label rune '!'`,
|
||||
}, {
|
||||
name: "bootstraps_bad",
|
||||
|
||||
@@ -1,28 +1,43 @@
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/ipset"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ipsetCtx is the ipset context. ipsetMgr can be nil.
|
||||
type ipsetCtx struct {
|
||||
// ipsetHandler is the ipset context. ipsetMgr can be nil.
|
||||
type ipsetHandler struct {
|
||||
ipsetMgr ipset.Manager
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// init initializes the ipset context. It is not safe for concurrent use.
|
||||
//
|
||||
// TODO(a.garipov): Rewrite into a simple constructor?
|
||||
func (c *ipsetCtx) init(ipsetConf []string) (err error) {
|
||||
c.ipsetMgr, err = ipset.NewManager(ipsetConf)
|
||||
if errors.Is(err, os.ErrInvalid) || errors.Is(err, os.ErrPermission) {
|
||||
// newIpsetHandler returns a new initialized [ipsetHandler]. It is not safe for
|
||||
// concurrent use.
|
||||
func newIpsetHandler(
|
||||
ctx context.Context,
|
||||
logger *slog.Logger,
|
||||
ipsetList []string,
|
||||
) (h *ipsetHandler, err error) {
|
||||
h = &ipsetHandler{
|
||||
logger: logger,
|
||||
}
|
||||
conf := &ipset.Config{
|
||||
Logger: logger,
|
||||
Lines: ipsetList,
|
||||
}
|
||||
h.ipsetMgr, err = ipset.NewManager(ctx, conf)
|
||||
if errors.Is(err, os.ErrInvalid) ||
|
||||
errors.Is(err, os.ErrPermission) ||
|
||||
errors.Is(err, errors.ErrUnsupported) {
|
||||
// ipset cannot currently be initialized if the server was installed
|
||||
// from Snap or when the user or the binary doesn't have the required
|
||||
// permissions, or when the kernel doesn't support netfilter.
|
||||
@@ -31,30 +46,28 @@ func (c *ipsetCtx) init(ipsetConf []string) (err error) {
|
||||
//
|
||||
// TODO(a.garipov): The Snap problem can probably be solved if we add
|
||||
// the netlink-connector interface plug.
|
||||
log.Info("ipset: warning: cannot initialize: %s", err)
|
||||
logger.WarnContext(ctx, "cannot initialize", slogutil.KeyError, err)
|
||||
|
||||
return nil
|
||||
} else if errors.Is(err, errors.ErrUnsupported) {
|
||||
log.Info("ipset: warning: %s", err)
|
||||
|
||||
return nil
|
||||
return h, nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("initializing ipset: %w", err)
|
||||
return nil, fmt.Errorf("initializing ipset: %w", err)
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// close closes the Linux Netfilter connections. close can be called on a nil
|
||||
// handler.
|
||||
func (h *ipsetHandler) close() (err error) {
|
||||
if h != nil && h.ipsetMgr != nil {
|
||||
return h.ipsetMgr.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// close closes the Linux Netfilter connections.
|
||||
func (c *ipsetCtx) close() (err error) {
|
||||
if c.ipsetMgr != nil {
|
||||
return c.ipsetMgr.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ipsetCtx) dctxIsfilled(dctx *dnsContext) (ok bool) {
|
||||
// dctxIsFilled returns true if dctx has enough information to process.
|
||||
func dctxIsFilled(dctx *dnsContext) (ok bool) {
|
||||
return dctx != nil &&
|
||||
dctx.responseFromUpstream &&
|
||||
dctx.proxyCtx != nil &&
|
||||
@@ -65,8 +78,8 @@ func (c *ipsetCtx) dctxIsfilled(dctx *dnsContext) (ok bool) {
|
||||
|
||||
// skipIpsetProcessing returns true when the ipset processing can be skipped for
|
||||
// this request.
|
||||
func (c *ipsetCtx) skipIpsetProcessing(dctx *dnsContext) (ok bool) {
|
||||
if c == nil || c.ipsetMgr == nil || !c.dctxIsfilled(dctx) {
|
||||
func (h *ipsetHandler) skipIpsetProcessing(dctx *dnsContext) (ok bool) {
|
||||
if h == nil || h.ipsetMgr == nil || !dctxIsFilled(dctx) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -108,31 +121,31 @@ func ipsFromAnswer(ans []dns.RR) (ip4s, ip6s []net.IP) {
|
||||
}
|
||||
|
||||
// process adds the resolved IP addresses to the domain's ipsets, if any.
|
||||
func (c *ipsetCtx) process(dctx *dnsContext) (rc resultCode) {
|
||||
log.Debug("dnsforward: ipset: started processing")
|
||||
defer log.Debug("dnsforward: ipset: finished processing")
|
||||
func (h *ipsetHandler) process(dctx *dnsContext) (rc resultCode) {
|
||||
// TODO(s.chzhen): Use passed context.
|
||||
ctx := context.TODO()
|
||||
h.logger.DebugContext(ctx, "started processing")
|
||||
defer h.logger.DebugContext(ctx, "finished processing")
|
||||
|
||||
if c.skipIpsetProcessing(dctx) {
|
||||
if h.skipIpsetProcessing(dctx) {
|
||||
return resultCodeSuccess
|
||||
}
|
||||
|
||||
log.Debug("ipset: starting processing")
|
||||
|
||||
req := dctx.proxyCtx.Req
|
||||
host := req.Question[0].Name
|
||||
host = strings.TrimSuffix(host, ".")
|
||||
host = strings.ToLower(host)
|
||||
|
||||
ip4s, ip6s := ipsFromAnswer(dctx.proxyCtx.Res.Answer)
|
||||
n, err := c.ipsetMgr.Add(host, ip4s, ip6s)
|
||||
n, err := h.ipsetMgr.Add(ctx, host, ip4s, ip6s)
|
||||
if err != nil {
|
||||
// Consider ipset errors non-critical to the request.
|
||||
log.Error("dnsforward: ipset: adding host ips: %s", err)
|
||||
h.logger.ErrorContext(ctx, "adding host ips", slogutil.KeyError, err)
|
||||
|
||||
return resultCodeSuccess
|
||||
}
|
||||
|
||||
log.Debug("dnsforward: ipset: added %d new ipset entries", n)
|
||||
h.logger.DebugContext(ctx, "added new ipset entries", "num", n)
|
||||
|
||||
return resultCodeSuccess
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -16,7 +18,7 @@ type fakeIpsetMgr struct {
|
||||
}
|
||||
|
||||
// Add implements the aghnet.IpsetManager interface for *fakeIpsetMgr.
|
||||
func (m *fakeIpsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) {
|
||||
func (m *fakeIpsetMgr) Add(_ context.Context, host string, ip4s, ip6s []net.IP) (n int, err error) {
|
||||
m.ip4s = append(m.ip4s, ip4s...)
|
||||
m.ip6s = append(m.ip6s, ip6s...)
|
||||
|
||||
@@ -58,7 +60,9 @@ func TestIpsetCtx_process(t *testing.T) {
|
||||
responseFromUpstream: true,
|
||||
}
|
||||
|
||||
ictx := &ipsetCtx{}
|
||||
ictx := &ipsetHandler{
|
||||
logger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
rc := ictx.process(dctx)
|
||||
assert.Equal(t, resultCodeSuccess, rc)
|
||||
|
||||
@@ -77,8 +81,9 @@ func TestIpsetCtx_process(t *testing.T) {
|
||||
}
|
||||
|
||||
m := &fakeIpsetMgr{}
|
||||
ictx := &ipsetCtx{
|
||||
ictx := &ipsetHandler{
|
||||
ipsetMgr: m,
|
||||
logger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
|
||||
rc := ictx.process(dctx)
|
||||
@@ -101,8 +106,9 @@ func TestIpsetCtx_process(t *testing.T) {
|
||||
}
|
||||
|
||||
m := &fakeIpsetMgr{}
|
||||
ictx := &ipsetCtx{
|
||||
ictx := &ipsetHandler{
|
||||
ipsetMgr: m,
|
||||
logger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
|
||||
rc := ictx.process(dctx)
|
||||
@@ -124,8 +130,9 @@ func TestIpsetCtx_SkipIpsetProcessing(t *testing.T) {
|
||||
}
|
||||
|
||||
m := &fakeIpsetMgr{}
|
||||
ictx := &ipsetCtx{
|
||||
ictx := &ipsetHandler{
|
||||
ipsetMgr: m,
|
||||
logger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
|
||||
@@ -58,7 +58,7 @@ func (s *Server) genDNSFilterMessage(
|
||||
return s.replyCompressed(req)
|
||||
}
|
||||
|
||||
return s.newMsgNODATA(req)
|
||||
return s.NewMsgNODATA(req)
|
||||
}
|
||||
|
||||
switch res.Reason {
|
||||
@@ -344,51 +344,6 @@ func (s *Server) makeResponseREFUSED(req *dns.Msg) *dns.Msg {
|
||||
return s.reply(req, dns.RcodeRefused)
|
||||
}
|
||||
|
||||
// newMsgNODATA returns a properly initialized NODATA response.
|
||||
//
|
||||
// See https://www.rfc-editor.org/rfc/rfc2308#section-2.2.
|
||||
func (s *Server) newMsgNODATA(req *dns.Msg) (resp *dns.Msg) {
|
||||
resp = s.reply(req, dns.RcodeSuccess)
|
||||
resp.Ns = s.genSOA(req)
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (s *Server) genSOA(request *dns.Msg) []dns.RR {
|
||||
zone := ""
|
||||
if len(request.Question) > 0 {
|
||||
zone = request.Question[0].Name
|
||||
}
|
||||
|
||||
soa := dns.SOA{
|
||||
// values copied from verisign's nonexistent .com domain
|
||||
// their exact values are not important in our use case because they are used for domain transfers between primary/secondary DNS servers
|
||||
Refresh: 1800,
|
||||
Retry: 900,
|
||||
Expire: 604800,
|
||||
Minttl: 86400,
|
||||
// copied from AdGuard DNS
|
||||
Ns: "fake-for-negative-caching.adguard.com.",
|
||||
Serial: 100500,
|
||||
// rest is request-specific
|
||||
Hdr: dns.RR_Header{
|
||||
Name: zone,
|
||||
Rrtype: dns.TypeSOA,
|
||||
Ttl: s.dnsFilter.BlockedResponseTTL(),
|
||||
Class: dns.ClassINET,
|
||||
},
|
||||
Mbox: "hostmaster.", // zone will be appended later if it's not empty or "."
|
||||
}
|
||||
if soa.Hdr.Ttl == 0 {
|
||||
soa.Hdr.Ttl = defaultBlockedResponseTTL
|
||||
}
|
||||
if len(zone) > 0 && zone[0] != '.' {
|
||||
soa.Mbox += zone
|
||||
}
|
||||
|
||||
return []dns.RR{&soa}
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ proxy.MessageConstructor = (*Server)(nil)
|
||||
|
||||
@@ -425,3 +380,52 @@ func (s *Server) NewMsgNOTIMPLEMENTED(req *dns.Msg) (resp *dns.Msg) {
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
// NewMsgNODATA implements the [proxy.MessageConstructor] interface for *Server.
|
||||
func (s *Server) NewMsgNODATA(req *dns.Msg) (resp *dns.Msg) {
|
||||
resp = s.reply(req, dns.RcodeSuccess)
|
||||
resp.Ns = s.genSOA(req)
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (s *Server) genSOA(req *dns.Msg) []dns.RR {
|
||||
zone := ""
|
||||
if len(req.Question) > 0 {
|
||||
zone = req.Question[0].Name
|
||||
}
|
||||
|
||||
const defaultBlockedResponseTTL = 3600
|
||||
|
||||
soa := dns.SOA{
|
||||
// Values copied from verisign's nonexistent.com domain.
|
||||
//
|
||||
// Their exact values are not important in our use case because they are
|
||||
// used for domain transfers between primary/secondary DNS servers.
|
||||
Refresh: 1800,
|
||||
Retry: 900,
|
||||
Expire: 604800,
|
||||
Minttl: 86400,
|
||||
// copied from AdGuard DNS
|
||||
Ns: "fake-for-negative-caching.adguard.com.",
|
||||
Serial: 100500,
|
||||
// rest is request-specific
|
||||
Hdr: dns.RR_Header{
|
||||
Name: zone,
|
||||
Rrtype: dns.TypeSOA,
|
||||
Ttl: s.dnsFilter.BlockedResponseTTL(),
|
||||
Class: dns.ClassINET,
|
||||
},
|
||||
// zone will be appended later if it's not ".".
|
||||
Mbox: "hostmaster.",
|
||||
}
|
||||
if soa.Hdr.Ttl == 0 {
|
||||
soa.Hdr.Ttl = defaultBlockedResponseTTL
|
||||
}
|
||||
|
||||
if zone != "." {
|
||||
soa.Mbox += zone
|
||||
}
|
||||
|
||||
return []dns.RR{&soa}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ func (s *Server) processInitial(dctx *dnsContext) (rc resultCode) {
|
||||
q := pctx.Req.Question[0]
|
||||
qt := q.Qtype
|
||||
if s.conf.AAAADisabled && qt == dns.TypeAAAA {
|
||||
_ = proxy.CheckDisabledAAAARequest(pctx, true)
|
||||
pctx.Res = s.NewMsgNODATA(pctx.Req)
|
||||
|
||||
return resultCodeFinish
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
@@ -430,6 +431,7 @@ func TestServer_ProcessDHCPHosts_localRestriction(t *testing.T) {
|
||||
dnsFilter: createTestDNSFilter(t),
|
||||
dhcpServer: dhcp,
|
||||
localDomainSuffix: localDomainSuffix,
|
||||
baseLogger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
|
||||
req := &dns.Msg{
|
||||
@@ -565,6 +567,7 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
|
||||
dnsFilter: createTestDNSFilter(t),
|
||||
dhcpServer: testDHCP,
|
||||
localDomainSuffix: tc.suffix,
|
||||
baseLogger: slogutil.NewDiscardLogger(),
|
||||
}
|
||||
|
||||
req := &dns.Msg{
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/stats"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -202,6 +203,7 @@ func TestServer_ProcessQueryLogsAndStats(t *testing.T) {
|
||||
ql := &testQueryLog{}
|
||||
st := &testStats{}
|
||||
srv := &Server{
|
||||
baseLogger: slogutil.NewDiscardLogger(),
|
||||
queryLog: ql,
|
||||
stats: st,
|
||||
anonymizer: aghnet.NewIPMut(nil),
|
||||
|
||||
@@ -150,12 +150,12 @@ func setProxyUpstreamMode(
|
||||
) (err error) {
|
||||
switch upstreamMode {
|
||||
case UpstreamModeParallel:
|
||||
conf.UpstreamMode = proxy.UModeParallel
|
||||
conf.UpstreamMode = proxy.UpstreamModeParallel
|
||||
case UpstreamModeFastestAddr:
|
||||
conf.UpstreamMode = proxy.UModeFastestAddr
|
||||
conf.UpstreamMode = proxy.UpstreamModeFastestAddr
|
||||
conf.FastestPingTimeout = fastestTimeout
|
||||
case UpstreamModeLoadBalance:
|
||||
conf.UpstreamMode = proxy.UModeLoadBalance
|
||||
conf.UpstreamMode = proxy.UpstreamModeLoadBalance
|
||||
default:
|
||||
return fmt.Errorf("unexpected value %q", upstreamMode)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user