Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into AG-32410-imp-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Mizzick committed May 30, 2024
2 parents d2db301 + 17b2ad2 commit 031fb5c
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 248 deletions.
14 changes: 7 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ require (
github.com/jessevdk/go-flags v1.5.0
github.com/miekg/dns v1.1.58
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.43.1
github.com/quic-go/quic-go v0.44.0
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8
golang.org/x/net v0.24.0
golang.org/x/sys v0.19.0
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/net v0.25.0
golang.org/x/sys v0.20.0
gopkg.in/yaml.v3 v3.0.1
)

Expand All @@ -31,11 +31,11 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.21.0 // indirect
gonum.org/v1/gonum v0.14.0
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
)
30 changes: 14 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,35 +46,33 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.42.1-0.20240424141022-12aa63824c7f h1:L7x60Z6AW2giF/SvbDpMglGHJxtmFJV03khPwXLDScU=
github.com/quic-go/quic-go v0.42.1-0.20240424141022-12aa63824c7f/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZQ=
github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
Expand Down
42 changes: 30 additions & 12 deletions proxy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,28 +339,46 @@ func (p *Proxy) logConfigInfo() {

// validateListenAddrs returns an error if the addresses are not configured
// properly.
func (p *Proxy) validateListenAddrs() error {
func (p *Proxy) validateListenAddrs() (err error) {
if !p.hasListenAddrs() {
return errors.Error("no listen address specified")
}

if p.TLSConfig == nil {
if p.TLSListenAddr != nil {
return errors.Error("cannot create tls listener without tls config")
}
err = p.validateTLSConfig()
if err != nil {
return fmt.Errorf("invalid tls configuration: %w", err)
}

if p.HTTPSListenAddr != nil {
return errors.Error("cannot create https listener without tls config")
if p.DNSCryptResolverCert == nil || p.DNSCryptProviderName == "" {
if p.DNSCryptTCPListenAddr != nil {
return errors.Error("cannot create dnscrypt tcp listener without dnscrypt config")
}

if p.QUICListenAddr != nil {
return errors.Error("cannot create quic listener without tls config")
if p.DNSCryptUDPListenAddr != nil {
return errors.Error("cannot create dnscrypt udp listener without dnscrypt config")
}
}

if (p.DNSCryptTCPListenAddr != nil || p.DNSCryptUDPListenAddr != nil) &&
(p.DNSCryptResolverCert == nil || p.DNSCryptProviderName == "") {
return errors.Error("cannot create dnscrypt listener without dnscrypt config")
return nil
}

// validateTLSConfig returns an error if proxy TLS configuration parameters are
// needed but aren't provided.
func (p *Proxy) validateTLSConfig() (err error) {
if p.TLSConfig != nil {
return nil
}

if p.TLSListenAddr != nil {
return errors.Error("tls listener configuration not found")
}

if p.HTTPSListenAddr != nil {
return errors.Error("https listener configuration not found")
}

if p.QUICListenAddr != nil {
return errors.Error("quic listener configuration not found")
}

return nil
Expand Down
5 changes: 2 additions & 3 deletions proxy/dnscontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,11 @@ type DNSContext struct {
//
// TODO(e.burkov): Consider creating DNSContext with this everywhere, to
// actually respect the contract of DNSContext.RequestID field.
//
// TODO(e.burkov): Add remote address into arguments.
func (p *Proxy) newDNSContext(proto Proto, req *dns.Msg) (d *DNSContext) {
func (p *Proxy) newDNSContext(proto Proto, req *dns.Msg, addr netip.AddrPort) (d *DNSContext) {
return &DNSContext{
Proto: proto,
Req: req,
Addr: addr,

RequestID: p.counter.Add(1),
}
Expand Down
30 changes: 21 additions & 9 deletions proxy/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/AdguardTeam/dnsproxy/proxyutil"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
)
Expand All @@ -18,11 +19,15 @@ type lookupResult struct {
err error
}

// lookupIPAddr resolves the specified host IP addresses.
// lookupIPAddr resolves the specified host IP addresses. It is intended to be
// used as a goroutine.
func (p *Proxy) lookupIPAddr(host string, qtype uint16, ch chan *lookupResult) {
defer log.OnPanic("Proxy.lookupIPAddr")

req := (&dns.Msg{}).SetQuestion(host, qtype)

d := p.newDNSContext(ProtoUDP, req)
// TODO(d.kolyshev): Investigate why the client address is not defined.
d := p.newDNSContext(ProtoUDP, req, netip.AddrPort{})
err := p.Resolve(d)
ch <- &lookupResult{d.Res, err}
}
Expand All @@ -36,7 +41,7 @@ var _ upstream.Resolver = (*Proxy)(nil)

// LookupNetIP implements the [upstream.Resolver] interface for *Proxy. It
// resolves the specified host IP addresses by sending two DNS queries (A and
// AAAA) in parallel. It returns both results for those two queries.
// AAAA) in parallel. It returns both results for those two queries.
func (p *Proxy) LookupNetIP(
_ context.Context,
_ string,
Expand All @@ -61,12 +66,7 @@ func (p *Proxy) LookupNetIP(
continue
}

for _, ans := range result.resp.Answer {
a := proxyutil.IPFromRR(ans)
if a != (netip.Addr{}) {
addrs = append(addrs, a)
}
}
addrs = appendAnswerAddrs(addrs, result.resp.Answer)
}

if len(addrs) == 0 && len(errs) != 0 {
Expand All @@ -81,3 +81,15 @@ func (p *Proxy) LookupNetIP(

return addrs, nil
}

// appendAnswerAddrs returns addrs with addresses appended from the given ans.
func appendAnswerAddrs(addrs []netip.Addr, ans []dns.RR) (res []netip.Addr) {
for _, ansRR := range ans {
a := proxyutil.IPFromRR(ansRR)
if a != (netip.Addr{}) {
addrs = append(addrs, a)
}
}

return addrs
}
126 changes: 59 additions & 67 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ func (p *Proxy) validateBasicAuth() (err error) {
return nil
}

// Returns true if proxy is started. It is safe for concurrent use.
func (p *Proxy) isStarted() (ok bool) {
p.RLock()
defer p.RUnlock()

return p.started
}

// type check
var _ service.Interface = (*Proxy)(nil)

Expand All @@ -360,11 +368,12 @@ func (p *Proxy) Start(ctx context.Context) (err error) {
return err
}

err = p.startListeners(ctx)
err = p.configureListeners(ctx)
if err != nil {
return fmt.Errorf("starting listeners: %w", err)
return fmt.Errorf("configuring listeners: %w", err)
}

p.startListeners()
p.started = true

return nil
Expand Down Expand Up @@ -458,97 +467,80 @@ func (p *Proxy) Shutdown(_ context.Context) (err error) {
return nil
}

// Addrs returns all listen addresses for the specified proto or nil if the proxy does not listen to it.
// proto must be "tcp", "tls", "https", "quic", or "udp"
func (p *Proxy) Addrs(proto Proto) []net.Addr {
// addrFunc provides the address from the given A.
type addrFunc[A any] func(l A) (addr net.Addr)

// collectAddrs returns the slice of network addresses of the given listeners
// using the given addrFunc.
func collectAddrs[A any](listeners []A, af addrFunc[A]) (addrs []net.Addr) {
for _, l := range listeners {
addrs = append(addrs, af(l))
}

return addrs
}

// Addrs returns all listen addresses for the specified proto or nil if the
// proxy does not listen to it. proto must be one of [Proto]: [ProtoTCP],
// [ProtoUDP], [ProtoTLS], [ProtoHTTPS], [ProtoQUIC], or [ProtoDNSCrypt].
func (p *Proxy) Addrs(proto Proto) (addrs []net.Addr) {
p.RLock()
defer p.RUnlock()

var addrs []net.Addr

switch proto {
case ProtoTCP:
for _, l := range p.tcpListen {
addrs = append(addrs, l.Addr())
}

return collectAddrs(p.tcpListen, net.Listener.Addr)
case ProtoTLS:
for _, l := range p.tlsListen {
addrs = append(addrs, l.Addr())
}

return collectAddrs(p.tlsListen, net.Listener.Addr)
case ProtoHTTPS:
for _, l := range p.httpsListen {
addrs = append(addrs, l.Addr())
}

return collectAddrs(p.httpsListen, net.Listener.Addr)
case ProtoUDP:
for _, l := range p.udpListen {
addrs = append(addrs, l.LocalAddr())
}

return collectAddrs(p.udpListen, (*net.UDPConn).LocalAddr)
case ProtoQUIC:
for _, l := range p.quicListen {
addrs = append(addrs, l.Addr())
}

return collectAddrs(p.quicListen, (*quic.EarlyListener).Addr)
case ProtoDNSCrypt:
// Using only UDP addrs here
// TODO: to do it better we should either do ProtoDNSCryptTCP/ProtoDNSCryptUDP
// or we should change the configuration so that it was not possible to
// set different ports for TCP/UDP listeners.
for _, l := range p.dnsCryptUDPListen {
addrs = append(addrs, l.LocalAddr())
}

//
// TODO(ameshkov): To do it better we should either do
// ProtoDNSCryptTCP/ProtoDNSCryptUDP or we should change the
// configuration so that it was not possible to set different ports for
// TCP/UDP listeners.
return collectAddrs(p.dnsCryptUDPListen, (*net.UDPConn).LocalAddr)
default:
panic("proto must be 'tcp', 'tls', 'https', 'quic', 'dnscrypt' or 'udp'")
}
}

return addrs
// firstAddr returns the network address of the first listener in the given
// listeners or nil using the given addrFunc.
func firstAddr[A any](listeners []A, af addrFunc[A]) (addr net.Addr) {
if len(listeners) == 0 {
return nil
}

return af(listeners[0])
}

// Addr returns the first listen address for the specified proto or null if the proxy does not listen to it
// proto must be "tcp", "tls", "https", "quic", or "udp"
func (p *Proxy) Addr(proto Proto) net.Addr {
// Addr returns the first listen address for the specified proto or nil if the
// proxy does not listen to it. proto must be one of [Proto]: [ProtoTCP],
// [ProtoUDP], [ProtoTLS], [ProtoHTTPS], [ProtoQUIC], or [ProtoDNSCrypt].
func (p *Proxy) Addr(proto Proto) (addr net.Addr) {
p.RLock()
defer p.RUnlock()

switch proto {
case ProtoTCP:
if len(p.tcpListen) == 0 {
return nil
}
return p.tcpListen[0].Addr()

return firstAddr(p.tcpListen, net.Listener.Addr)
case ProtoTLS:
if len(p.tlsListen) == 0 {
return nil
}
return p.tlsListen[0].Addr()

return firstAddr(p.tlsListen, net.Listener.Addr)
case ProtoHTTPS:
if len(p.httpsListen) == 0 {
return nil
}
return p.httpsListen[0].Addr()

return firstAddr(p.httpsListen, net.Listener.Addr)
case ProtoUDP:
if len(p.udpListen) == 0 {
return nil
}
return p.udpListen[0].LocalAddr()

return firstAddr(p.udpListen, (*net.UDPConn).LocalAddr)
case ProtoQUIC:
if len(p.quicListen) == 0 {
return nil
}
return p.quicListen[0].Addr()

return firstAddr(p.quicListen, (*quic.EarlyListener).Addr)
case ProtoDNSCrypt:
if len(p.dnsCryptUDPListen) == 0 {
return nil
}
return p.dnsCryptUDPListen[0].LocalAddr()
return firstAddr(p.dnsCryptUDPListen, (*net.UDPConn).LocalAddr)
default:
panic("proto must be 'tcp', 'tls', 'https', 'quic', 'dnscrypt' or 'udp'")
}
Expand Down
Loading

0 comments on commit 031fb5c

Please sign in to comment.