AdGuardHome/internal/dnsforward/beforerequest.go
Dimitry Kolyshev 0cff3dbcda Pull request: AG-31863-dnsforward-tests
Merge in DNS/adguard-home from AG-31863-dnsforward-tests to master

Squashed commit of the following:

commit cbdad627c00b30a17af843d98236fe9758b7ddee
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Apr 24 15:00:15 2024 +0200

    dnsforward: imp tests

commit b71304a925c0ea49440e493dc65accadc6e47c5f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Apr 24 12:53:51 2024 +0200

    dnsforward: imp tests

commit 3c42fcaa4906fce48b179a1c523e33839b2a8eee
Merge: 50888df66 60f48e2d0
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Apr 24 08:41:19 2024 +0200

    Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests

commit 50888df6616085872d956c42898ab0eff6c5f5d4
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Apr 24 08:39:37 2024 +0200

    dnsforward: imp code

commit dcd5e41f13d698ce7a6beb0a601910ae03ff4407
Merge: af2507b2a f85d04831
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 23 10:02:45 2024 +0200

    Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests

commit af2507b2ace94d0c39803c2d21273cf11a00843e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 23 10:01:30 2024 +0200

    dnsforward: imp tests

commit 67fc9d3d9c6210e600ca3b26abf7ebfffca5e770
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Apr 22 10:37:45 2024 +0200

    dnsforward: imp tests

commit e7f7df2b688be525ee7582a4e161a4837124e74b
Merge: c610a6c88 762ef4a6d
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Apr 22 09:51:04 2024 +0200

    Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests

commit c610a6c886554f6a2677c993c1c7aae4ca99228e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Apr 19 12:28:49 2024 +0200

    dnsforward: imp tests

commit ca252e8fa28b70f303068775cc682682dd41e77c
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Apr 19 11:58:49 2024 +0200

    dnsforward: imp tests

commit 9d4de18934b1c5b0ae2edbec98bc84d5e0b23126
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Apr 19 11:38:15 2024 +0200

    dnsforward: imp tests

commit a349374d90f48724ddca637e3d547f90026ff72a
Merge: 2243770b3 48c6242a7
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Apr 17 11:02:56 2024 +0200

    Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests

commit 2243770b3a54a55eaf4fd48328a8e40a7b8a8349
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 16 10:56:40 2024 +0200

    dnsforward: imp tests

commit 4c4b565eec0ce8839b94cbaa0b29be6355e3c2e4
Merge: f1e4b72a8 201ac73cf
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Apr 16 10:53:48 2024 +0200

    Merge remote-tracking branch 'origin/master' into AG-31863-dnsforward-tests

commit f1e4b72a8aa4fd0bbc738d959ca9be2f19fbc338
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Apr 15 12:36:21 2024 +0200

    dnsforward: imp tests

commit 6ee6cc9519ddd31f0e78c7521ec612404f85e4b5
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Sun Apr 14 13:55:09 2024 +0200

    dnsforward: add test
2024-04-24 16:22:50 +03:00

116 lines
3.1 KiB
Go

package dnsforward
import (
"encoding/binary"
"fmt"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
)
// type check
var _ proxy.BeforeRequestHandler = (*Server)(nil)
// HandleBefore is the handler that is called before any other processing,
// including logs. It performs access checks and puts the client ID, if there
// is one, into the server's cache.
//
// TODO(d.kolyshev): Extract to separate package.
func (s *Server) HandleBefore(
_ *proxy.Proxy,
pctx *proxy.DNSContext,
) (err error) {
clientID, err := s.clientIDFromDNSContext(pctx)
if err != nil {
return &proxy.BeforeRequestError{
Err: fmt.Errorf("getting clientid: %w", err),
Response: s.NewMsgSERVFAIL(pctx.Req),
}
}
blocked, _ := s.IsBlockedClient(pctx.Addr.Addr(), clientID)
if blocked {
return s.preBlockedResponse(pctx)
}
if len(pctx.Req.Question) == 1 {
q := pctx.Req.Question[0]
qt := q.Qtype
host := aghnet.NormalizeDomain(q.Name)
if s.access.isBlockedHost(host, qt) {
log.Debug("access: request %s %s is in access blocklist", dns.Type(qt), host)
return s.preBlockedResponse(pctx)
}
}
if clientID != "" {
key := [8]byte{}
binary.BigEndian.PutUint64(key[:], pctx.RequestID)
s.clientIDCache.Set(key[:], []byte(clientID))
}
return nil
}
// clientIDFromDNSContext extracts the client's ID from the server name of the
// client's DoT or DoQ request or the path of the client's DoH. If the protocol
// is not one of these, clientID is an empty string and err is nil.
func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string, err error) {
proto := pctx.Proto
if proto == proxy.ProtoHTTPS {
clientID, err = clientIDFromDNSContextHTTPS(pctx)
if err != nil {
return "", fmt.Errorf("checking url: %w", err)
} else if clientID != "" {
return clientID, nil
}
// Go on and check the domain name as well.
} else if proto != proxy.ProtoTLS && proto != proxy.ProtoQUIC {
return "", nil
}
hostSrvName := s.conf.ServerName
if hostSrvName == "" {
return "", nil
}
cliSrvName, err := clientServerName(pctx, proto)
if err != nil {
return "", err
}
clientID, err = clientIDFromClientServerName(
hostSrvName,
cliSrvName,
s.conf.StrictSNICheck,
)
if err != nil {
return "", fmt.Errorf("clientid check: %w", err)
}
return clientID, nil
}
// errAccessBlocked is a sentinel error returned when a request is blocked by
// access settings.
var errAccessBlocked errors.Error = "blocked by access settings"
// preBlockedResponse returns a protocol-appropriate response for a request that
// was blocked by access settings.
func (s *Server) preBlockedResponse(pctx *proxy.DNSContext) (err error) {
if pctx.Proto == proxy.ProtoUDP || pctx.Proto == proxy.ProtoDNSCrypt {
// Return nil so that dnsproxy drops the connection and thus
// prevent DNS amplification attacks.
return errAccessBlocked
}
return &proxy.BeforeRequestError{
Err: errAccessBlocked,
Response: s.makeResponseREFUSED(pctx.Req),
}
}