refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
package netxlite
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
//
|
|
|
|
// DNS resolver
|
|
|
|
//
|
|
|
|
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
import (
|
|
|
|
"context"
|
2021-09-05 20:41:46 +02:00
|
|
|
"errors"
|
2021-09-27 16:48:46 +02:00
|
|
|
"fmt"
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
"net"
|
2022-05-13 15:32:47 +02:00
|
|
|
"strings"
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
"time"
|
2021-08-17 10:29:06 +02:00
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
2021-08-17 10:29:06 +02:00
|
|
|
"golang.org/x/net/idna"
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
)
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// ErrNoDNSTransport is the error returned when you attempt to perform
|
2022-05-14 17:38:31 +02:00
|
|
|
// a DNS operation that requires a custom DNSTransport (e.g., DNSOverHTTPSTransport)
|
2021-09-29 20:21:25 +02:00
|
|
|
// but you are using the "system" resolver instead.
|
2021-09-27 23:09:41 +02:00
|
|
|
var ErrNoDNSTransport = errors.New("operation requires a DNS transport")
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// NewResolverStdlib creates a new Resolver by combining WrapResolver
|
|
|
|
// with an internal "system" resolver type.
|
2022-01-03 13:53:23 +01:00
|
|
|
func NewResolverStdlib(logger model.DebugLogger) model.Resolver {
|
2021-09-27 12:00:43 +02:00
|
|
|
return WrapResolver(logger, &resolverSystem{})
|
|
|
|
}
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// NewResolverUDP creates a new Resolver using DNS-over-UDP.
|
|
|
|
//
|
|
|
|
// Arguments:
|
|
|
|
//
|
|
|
|
// - logger is the logger to use
|
|
|
|
//
|
|
|
|
// - dialer is the dialer to create and connect UDP conns
|
|
|
|
//
|
|
|
|
// - address is the server address (e.g., 1.1.1.1:53)
|
2022-01-03 13:53:23 +01:00
|
|
|
func NewResolverUDP(logger model.DebugLogger, dialer model.Dialer, address string) model.Resolver {
|
2021-09-28 18:15:38 +02:00
|
|
|
return WrapResolver(logger, NewSerialResolver(
|
2022-05-14 17:38:31 +02:00
|
|
|
NewDNSOverUDPTransport(dialer, address),
|
2021-09-28 18:15:38 +02:00
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2021-09-27 12:00:43 +02:00
|
|
|
// WrapResolver creates a new resolver that wraps an
|
|
|
|
// existing resolver to add these properties:
|
2021-09-08 22:48:10 +02:00
|
|
|
//
|
|
|
|
// 1. handles IDNA;
|
|
|
|
//
|
|
|
|
// 2. performs logging;
|
|
|
|
//
|
|
|
|
// 3. short-circuits IP addresses like getaddrinfo does (i.e.,
|
|
|
|
// resolving "1.1.1.1" yields []string{"1.1.1.1"};
|
|
|
|
//
|
|
|
|
// 4. wraps errors;
|
|
|
|
//
|
|
|
|
// 5. enforces reasonable timeouts (
|
|
|
|
// see https://github.com/ooni/probe/issues/1726).
|
2021-09-29 20:21:25 +02:00
|
|
|
//
|
|
|
|
// This is a low-level factory. Use only if out of alternatives.
|
2022-01-03 13:53:23 +01:00
|
|
|
func WrapResolver(logger model.DebugLogger, resolver model.Resolver) model.Resolver {
|
2021-09-05 18:03:50 +02:00
|
|
|
return &resolverIDNA{
|
|
|
|
Resolver: &resolverLogger{
|
2021-09-05 20:12:05 +02:00
|
|
|
Resolver: &resolverShortCircuitIPAddr{
|
2021-09-07 19:56:42 +02:00
|
|
|
Resolver: &resolverErrWrapper{
|
2021-09-27 12:00:43 +02:00
|
|
|
Resolver: resolver,
|
2021-09-07 19:56:42 +02:00
|
|
|
},
|
2021-09-05 20:12:05 +02:00
|
|
|
},
|
2021-09-05 20:41:46 +02:00
|
|
|
Logger: logger,
|
2021-09-05 18:03:50 +02:00
|
|
|
},
|
|
|
|
}
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
// resolverSystem is the system resolver.
|
2021-09-05 18:50:05 +02:00
|
|
|
type resolverSystem struct {
|
|
|
|
testableTimeout time.Duration
|
|
|
|
testableLookupHost func(ctx context.Context, domain string) ([]string, error)
|
|
|
|
}
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Resolver = &resolverSystem{}
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
func (r *resolverSystem) LookupHost(ctx context.Context, hostname string) ([]string, error) {
|
2021-09-05 18:50:05 +02:00
|
|
|
// This code forces adding a shorter timeout to the domain name
|
|
|
|
// resolutions when using the system resolver. We have seen cases
|
|
|
|
// in which such a timeout becomes too large. One such case is
|
|
|
|
// described in https://github.com/ooni/probe/issues/1726.
|
|
|
|
addrsch, errch := make(chan []string, 1), make(chan error, 1)
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, r.timeout())
|
|
|
|
defer cancel()
|
|
|
|
go func() {
|
|
|
|
addrs, err := r.lookupHost()(ctx, hostname)
|
|
|
|
if err != nil {
|
|
|
|
errch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
addrsch <- addrs
|
|
|
|
}()
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return nil, ctx.Err()
|
|
|
|
case addrs := <-addrsch:
|
|
|
|
return addrs, nil
|
|
|
|
case err := <-errch:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverSystem) timeout() time.Duration {
|
|
|
|
if r.testableTimeout > 0 {
|
|
|
|
return r.testableTimeout
|
|
|
|
}
|
|
|
|
return 15 * time.Second
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverSystem) lookupHost() func(ctx context.Context, domain string) ([]string, error) {
|
|
|
|
if r.testableLookupHost != nil {
|
|
|
|
return r.testableLookupHost
|
|
|
|
}
|
getaddrinfo: fix CGO_ENABLED=0 and record resolver type (#765)
After https://github.com/ooni/probe-cli/pull/764, the build for
CGO_ENABLED=0 has been broken for miniooni:
https://github.com/ooni/probe-cli/runs/6636995859?check_suite_focus=true
Likewise, it's not possible to run tests with CGO_ENABLED=0.
To make tests work with `CGO_ENABLED=0`, I needed to sacrifice some
unit tests run for the CGO case. It is not fully clear to me what was happening
here, but basically `getaddrinfo_cgo_test.go` was compiled with CGO
being disabled, even though the ``//go:build cgo` flag was specified.
Additionally, @hellais previously raised a valid point in the review
of https://github.com/ooni/probe-cli/pull/698:
> Another issue we should consider is that, if I understand how
> this works correctly, depending on whether or not we have built
> with CGO_ENABLED=0 on or not, we are going to be measuring
> things in a different way (using our cgo inspired getaddrinfo
> implementation or using netgo). This might present issues when
> analyzing or interpreting the data.
>
> Do we perhaps want to add some field to the output data format that
> gives us an indication of which DNS resolution code was used to
> generate the the metric?
This comment is relevant to the current commit because
https://github.com/ooni/probe-cli/pull/698 is the previous
iteration of https://github.com/ooni/probe-cli/pull/764.
So, while fixing the build and test issues, let us also distinguish
between the CGO_ENABLED=1 and CGO_ENABLED=0 cases.
Before this commit, OONI used "system" to indicate the case where
we were using net.DefaultResolver. This behavior dates back to the
Measurement Kit days. While it is true that ooni/probe-engine and
ooni/probe-cli could have been using netgo in the past when we
said "system" as the resolver, it also seems reasonable to continue
to use "system" top indicate getaddrinfo.
So, the choice here is basically to use "netgo" from now on to
indicate the cases in which we were built with CGO_ENABLED=0.
This change will need to be documented into ooni/spec along with
the introduction of the `android_dns_cache_no_data` error.
## Checklist
- [x] I have read the [contribution guidelines](https://github.com/ooni/probe-cli/blob/master/CONTRIBUTING.md)
- [x] reference issue for this pull request: https://github.com/ooni/probe/issues/2029
- [x] if you changed anything related how experiments work and you need to reflect these changes in the ooni/spec repository, please link to the related ooni/spec pull request: https://github.com/ooni/spec/pull/242
2022-05-30 07:34:25 +02:00
|
|
|
return TProxy.DefaultResolver().LookupHost
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
func (r *resolverSystem) Network() string {
|
getaddrinfo: fix CGO_ENABLED=0 and record resolver type (#765)
After https://github.com/ooni/probe-cli/pull/764, the build for
CGO_ENABLED=0 has been broken for miniooni:
https://github.com/ooni/probe-cli/runs/6636995859?check_suite_focus=true
Likewise, it's not possible to run tests with CGO_ENABLED=0.
To make tests work with `CGO_ENABLED=0`, I needed to sacrifice some
unit tests run for the CGO case. It is not fully clear to me what was happening
here, but basically `getaddrinfo_cgo_test.go` was compiled with CGO
being disabled, even though the ``//go:build cgo` flag was specified.
Additionally, @hellais previously raised a valid point in the review
of https://github.com/ooni/probe-cli/pull/698:
> Another issue we should consider is that, if I understand how
> this works correctly, depending on whether or not we have built
> with CGO_ENABLED=0 on or not, we are going to be measuring
> things in a different way (using our cgo inspired getaddrinfo
> implementation or using netgo). This might present issues when
> analyzing or interpreting the data.
>
> Do we perhaps want to add some field to the output data format that
> gives us an indication of which DNS resolution code was used to
> generate the the metric?
This comment is relevant to the current commit because
https://github.com/ooni/probe-cli/pull/698 is the previous
iteration of https://github.com/ooni/probe-cli/pull/764.
So, while fixing the build and test issues, let us also distinguish
between the CGO_ENABLED=1 and CGO_ENABLED=0 cases.
Before this commit, OONI used "system" to indicate the case where
we were using net.DefaultResolver. This behavior dates back to the
Measurement Kit days. While it is true that ooni/probe-engine and
ooni/probe-cli could have been using netgo in the past when we
said "system" as the resolver, it also seems reasonable to continue
to use "system" top indicate getaddrinfo.
So, the choice here is basically to use "netgo" from now on to
indicate the cases in which we were built with CGO_ENABLED=0.
This change will need to be documented into ooni/spec along with
the introduction of the `android_dns_cache_no_data` error.
## Checklist
- [x] I have read the [contribution guidelines](https://github.com/ooni/probe-cli/blob/master/CONTRIBUTING.md)
- [x] reference issue for this pull request: https://github.com/ooni/probe/issues/2029
- [x] if you changed anything related how experiments work and you need to reflect these changes in the ooni/spec repository, please link to the related ooni/spec pull request: https://github.com/ooni/spec/pull/242
2022-05-30 07:34:25 +02:00
|
|
|
return TProxy.DefaultResolver().Network()
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
func (r *resolverSystem) Address() string {
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2021-09-05 18:03:50 +02:00
|
|
|
func (r *resolverSystem) CloseIdleConnections() {
|
2021-09-08 22:48:10 +02:00
|
|
|
// nothing to do
|
2021-09-05 18:03:50 +02:00
|
|
|
}
|
|
|
|
|
2021-09-27 23:09:41 +02:00
|
|
|
func (r *resolverSystem) LookupHTTPS(
|
2022-01-03 13:53:23 +01:00
|
|
|
ctx context.Context, domain string) (*model.HTTPSSvc, error) {
|
2021-09-27 23:09:41 +02:00
|
|
|
return nil, ErrNoDNSTransport
|
|
|
|
}
|
|
|
|
|
2022-05-16 10:46:53 +02:00
|
|
|
func (r *resolverSystem) LookupNS(
|
|
|
|
ctx context.Context, domain string) ([]*net.NS, error) {
|
|
|
|
// TODO(bassosimone): figure out in which context it makes sense
|
|
|
|
// to issue this query. How is this implemented under the hood by
|
|
|
|
// the stdlib? Is it using /etc/resolve.conf on Unix? Until we
|
|
|
|
// known all these details, let's pretend this functionality does
|
|
|
|
// not exist in the stdlib and focus on custom resolvers.
|
|
|
|
return nil, ErrNoDNSTransport
|
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
// resolverLogger is a resolver that emits events
|
|
|
|
type resolverLogger struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
Resolver model.Resolver
|
|
|
|
Logger model.DebugLogger
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
}
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Resolver = &resolverLogger{}
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
func (r *resolverLogger) LookupHost(ctx context.Context, hostname string) ([]string, error) {
|
2021-09-27 16:48:46 +02:00
|
|
|
prefix := fmt.Sprintf("resolve[A,AAAA] %s with %s (%s)", hostname, r.Network(), r.Address())
|
|
|
|
r.Logger.Debugf("%s...", prefix)
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
start := time.Now()
|
|
|
|
addrs, err := r.Resolver.LookupHost(ctx, hostname)
|
2021-06-23 17:00:44 +02:00
|
|
|
elapsed := time.Since(start)
|
|
|
|
if err != nil {
|
2021-09-27 16:48:46 +02:00
|
|
|
r.Logger.Debugf("%s... %s in %s", prefix, err, elapsed)
|
2021-06-23 17:00:44 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-09-27 16:48:46 +02:00
|
|
|
r.Logger.Debugf("%s... %+v in %s", prefix, addrs, elapsed)
|
2021-06-23 17:00:44 +02:00
|
|
|
return addrs, nil
|
refactor: start pivoting netx (#396)
What do I mean by pivoting? Netx is currently organized by row:
```
| dialer | quicdialer | resolver | ...
saving | | | | ...
errorwrapping | | | | ...
logging | | | | ...
mocking/sys | | | | ...
```
Every row needs to implement saving, errorwrapping, logging, mocking (or
adapting to the system or to some underlying library).
This causes cross package dependencies and, in turn, complexity. For
example, we need the `trace` package for supporting saving.
And `dialer`, `quickdialer`, et al. need to depend on such a package.
The same goes for errorwrapping.
This arrangement further complicates testing. For example, I am
currently working on https://github.com/ooni/probe/issues/1505 and
I realize it need to repeat integration tests in multiple places.
Let's say instead we pivot the above matrix as follows:
```
| saving | errorwrapping | logging | ...
dialer | | | | ...
quicdialer | | | | ...
logging | | | | ...
mocking/sys | | | | ...
...
```
In this way, now every row contains everything related to a specific
action to perform. We can now share code without relying on extra
support packages. What's more, we can write tests and, judding from
the way in which things are made, it seems we only need integration
testing in `errorwrapping` because it's where data quality matters
whereas, in all other cases, unit testing is fine.
I am going, therefore, to proceed with these changes and "pivot"
`netx`. Hopefully, it won't be too painful.
2021-06-23 15:53:12 +02:00
|
|
|
}
|
|
|
|
|
2021-09-27 23:09:41 +02:00
|
|
|
func (r *resolverLogger) LookupHTTPS(
|
2022-01-03 13:53:23 +01:00
|
|
|
ctx context.Context, domain string) (*model.HTTPSSvc, error) {
|
2021-09-27 23:09:41 +02:00
|
|
|
prefix := fmt.Sprintf("resolve[HTTPS] %s with %s (%s)", domain, r.Network(), r.Address())
|
|
|
|
r.Logger.Debugf("%s...", prefix)
|
|
|
|
start := time.Now()
|
|
|
|
https, err := r.Resolver.LookupHTTPS(ctx, domain)
|
|
|
|
elapsed := time.Since(start)
|
|
|
|
if err != nil {
|
|
|
|
r.Logger.Debugf("%s... %s in %s", prefix, err, elapsed)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
alpn := https.ALPN
|
|
|
|
a := https.IPv4
|
|
|
|
aaaa := https.IPv6
|
|
|
|
r.Logger.Debugf("%s... %+v %+v %+v in %s", prefix, alpn, a, aaaa, elapsed)
|
|
|
|
return https, nil
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
func (r *resolverLogger) Address() string {
|
|
|
|
return r.Resolver.Address()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverLogger) Network() string {
|
|
|
|
return r.Resolver.Network()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverLogger) CloseIdleConnections() {
|
|
|
|
r.Resolver.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
2022-05-16 10:46:53 +02:00
|
|
|
func (r *resolverLogger) LookupNS(
|
|
|
|
ctx context.Context, domain string) ([]*net.NS, error) {
|
|
|
|
prefix := fmt.Sprintf("resolve[NS] %s with %s (%s)", domain, r.Network(), r.Address())
|
|
|
|
r.Logger.Debugf("%s...", prefix)
|
|
|
|
start := time.Now()
|
|
|
|
ns, err := r.Resolver.LookupNS(ctx, domain)
|
|
|
|
elapsed := time.Since(start)
|
|
|
|
if err != nil {
|
|
|
|
r.Logger.Debugf("%s... %s in %s", prefix, err, elapsed)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
r.Logger.Debugf("%s... %+v in %s", prefix, ns, elapsed)
|
|
|
|
return ns, nil
|
|
|
|
}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
// resolverIDNA supports resolving Internationalized Domain Names.
|
2021-08-17 11:02:12 +02:00
|
|
|
//
|
2021-08-17 10:29:06 +02:00
|
|
|
// See RFC3492 for more information.
|
2021-09-05 14:49:38 +02:00
|
|
|
type resolverIDNA struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
Resolver model.Resolver
|
2021-08-17 10:29:06 +02:00
|
|
|
}
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
var _ model.Resolver = &resolverIDNA{}
|
|
|
|
|
2021-09-05 14:49:38 +02:00
|
|
|
func (r *resolverIDNA) LookupHost(ctx context.Context, hostname string) ([]string, error) {
|
2021-08-17 10:29:06 +02:00
|
|
|
host, err := idna.ToASCII(hostname)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return r.Resolver.LookupHost(ctx, host)
|
|
|
|
}
|
2021-09-05 20:12:05 +02:00
|
|
|
|
2021-09-27 23:09:41 +02:00
|
|
|
func (r *resolverIDNA) LookupHTTPS(
|
2022-01-03 13:53:23 +01:00
|
|
|
ctx context.Context, domain string) (*model.HTTPSSvc, error) {
|
2021-09-27 23:09:41 +02:00
|
|
|
host, err := idna.ToASCII(domain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return r.Resolver.LookupHTTPS(ctx, host)
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
func (r *resolverIDNA) Network() string {
|
|
|
|
return r.Resolver.Network()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverIDNA) Address() string {
|
|
|
|
return r.Resolver.Address()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverIDNA) CloseIdleConnections() {
|
|
|
|
r.Resolver.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
2022-05-16 10:46:53 +02:00
|
|
|
func (r *resolverIDNA) LookupNS(
|
|
|
|
ctx context.Context, domain string) ([]*net.NS, error) {
|
|
|
|
host, err := idna.ToASCII(domain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return r.Resolver.LookupNS(ctx, host)
|
|
|
|
}
|
|
|
|
|
2021-09-05 20:12:05 +02:00
|
|
|
// resolverShortCircuitIPAddr recognizes when the input hostname is an
|
|
|
|
// IP address and returns it immediately to the caller.
|
|
|
|
type resolverShortCircuitIPAddr struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
Resolver model.Resolver
|
2021-09-05 20:12:05 +02:00
|
|
|
}
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
var _ model.Resolver = &resolverShortCircuitIPAddr{}
|
|
|
|
|
2021-09-05 20:12:05 +02:00
|
|
|
func (r *resolverShortCircuitIPAddr) LookupHost(ctx context.Context, hostname string) ([]string, error) {
|
|
|
|
if net.ParseIP(hostname) != nil {
|
|
|
|
return []string{hostname}, nil
|
|
|
|
}
|
|
|
|
return r.Resolver.LookupHost(ctx, hostname)
|
|
|
|
}
|
2021-09-05 20:41:46 +02:00
|
|
|
|
2022-05-13 18:26:15 +02:00
|
|
|
func (r *resolverShortCircuitIPAddr) LookupHTTPS(ctx context.Context, hostname string) (*model.HTTPSSvc, error) {
|
|
|
|
if net.ParseIP(hostname) != nil {
|
|
|
|
https := &model.HTTPSSvc{}
|
|
|
|
if isIPv6(hostname) {
|
|
|
|
https.IPv6 = append(https.IPv6, hostname)
|
|
|
|
} else {
|
|
|
|
https.IPv4 = append(https.IPv4, hostname)
|
|
|
|
}
|
|
|
|
return https, nil
|
|
|
|
}
|
|
|
|
return r.Resolver.LookupHTTPS(ctx, hostname)
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:25:27 +02:00
|
|
|
func (r *resolverShortCircuitIPAddr) Network() string {
|
|
|
|
return r.Resolver.Network()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverShortCircuitIPAddr) Address() string {
|
|
|
|
return r.Resolver.Address()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverShortCircuitIPAddr) CloseIdleConnections() {
|
|
|
|
r.Resolver.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
2022-05-16 10:46:53 +02:00
|
|
|
// ErrDNSIPAddress indicates that you passed an IP address to a DNS
|
|
|
|
// function that only works with domain names.
|
|
|
|
var ErrDNSIPAddress = errors.New("ooresolver: expected domain, found IP address")
|
|
|
|
|
|
|
|
func (r *resolverShortCircuitIPAddr) LookupNS(
|
|
|
|
ctx context.Context, hostname string) ([]*net.NS, error) {
|
|
|
|
if net.ParseIP(hostname) != nil {
|
|
|
|
return nil, ErrDNSIPAddress
|
|
|
|
}
|
|
|
|
return r.Resolver.LookupNS(ctx, hostname)
|
|
|
|
}
|
|
|
|
|
2022-05-13 15:32:47 +02:00
|
|
|
// IsIPv6 returns true if the given candidate is a valid IP address
|
|
|
|
// representation and such representation is IPv6.
|
|
|
|
func IsIPv6(candidate string) (bool, error) {
|
|
|
|
if net.ParseIP(candidate) == nil {
|
|
|
|
return false, ErrInvalidIP
|
|
|
|
}
|
|
|
|
return isIPv6(candidate), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// isIPv6 returns true if the given IP address is IPv6.
|
|
|
|
func isIPv6(candidate string) bool {
|
|
|
|
// This check for identifying IPv6 is discussed
|
|
|
|
// at https://stackoverflow.com/questions/22751035
|
|
|
|
// and seems good-enough for our purposes.
|
|
|
|
return strings.Contains(candidate, ":")
|
|
|
|
}
|
|
|
|
|
2021-09-29 20:21:25 +02:00
|
|
|
// ErrNoResolver is the type of error returned by "without resolver"
|
|
|
|
// dialer when asked to dial for and endpoint containing a domain name,
|
|
|
|
// since they can only dial for endpoints containing IP addresses.
|
2021-09-05 20:41:46 +02:00
|
|
|
var ErrNoResolver = errors.New("no configured resolver")
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
// NullResolver is a resolver that is not capable of resolving
|
2021-09-05 20:41:46 +02:00
|
|
|
// domain names to IP addresses and always returns ErrNoResolver.
|
2022-05-31 20:02:11 +02:00
|
|
|
type NullResolver struct{}
|
2021-09-05 20:41:46 +02:00
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (r *NullResolver) LookupHost(ctx context.Context, hostname string) (addrs []string, err error) {
|
2021-09-05 20:41:46 +02:00
|
|
|
return nil, ErrNoResolver
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (r *NullResolver) Network() string {
|
2021-09-05 20:41:46 +02:00
|
|
|
return "null"
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (r *NullResolver) Address() string {
|
2021-09-05 20:41:46 +02:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (r *NullResolver) CloseIdleConnections() {
|
2021-09-08 22:48:10 +02:00
|
|
|
// nothing to do
|
2021-09-05 20:41:46 +02:00
|
|
|
}
|
2021-09-07 19:56:42 +02:00
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (r *NullResolver) LookupHTTPS(
|
2022-01-03 13:53:23 +01:00
|
|
|
ctx context.Context, domain string) (*model.HTTPSSvc, error) {
|
2021-09-27 23:09:41 +02:00
|
|
|
return nil, ErrNoResolver
|
|
|
|
}
|
|
|
|
|
2022-05-31 20:02:11 +02:00
|
|
|
func (r *NullResolver) LookupNS(
|
2022-05-16 10:46:53 +02:00
|
|
|
ctx context.Context, domain string) ([]*net.NS, error) {
|
|
|
|
return nil, ErrNoResolver
|
|
|
|
}
|
|
|
|
|
2021-09-07 19:56:42 +02:00
|
|
|
// resolverErrWrapper is a Resolver that knows about wrapping errors.
|
|
|
|
type resolverErrWrapper struct {
|
2022-05-15 19:25:27 +02:00
|
|
|
Resolver model.Resolver
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
|
2022-01-03 13:53:23 +01:00
|
|
|
var _ model.Resolver = &resolverErrWrapper{}
|
2021-09-07 19:56:42 +02:00
|
|
|
|
|
|
|
func (r *resolverErrWrapper) LookupHost(ctx context.Context, hostname string) ([]string, error) {
|
|
|
|
addrs, err := r.Resolver.LookupHost(ctx, hostname)
|
|
|
|
if err != nil {
|
2022-05-15 19:25:27 +02:00
|
|
|
return nil, newErrWrapper(classifyResolverError, ResolveOperation, err)
|
2021-09-07 19:56:42 +02:00
|
|
|
}
|
|
|
|
return addrs, nil
|
|
|
|
}
|
2021-09-27 23:09:41 +02:00
|
|
|
|
|
|
|
func (r *resolverErrWrapper) LookupHTTPS(
|
2022-01-03 13:53:23 +01:00
|
|
|
ctx context.Context, domain string) (*model.HTTPSSvc, error) {
|
2021-09-27 23:09:41 +02:00
|
|
|
out, err := r.Resolver.LookupHTTPS(ctx, domain)
|
|
|
|
if err != nil {
|
2022-05-15 19:25:27 +02:00
|
|
|
return nil, newErrWrapper(classifyResolverError, ResolveOperation, err)
|
2021-09-27 23:09:41 +02:00
|
|
|
}
|
|
|
|
return out, nil
|
|
|
|
}
|
2022-05-15 19:25:27 +02:00
|
|
|
|
|
|
|
func (r *resolverErrWrapper) Network() string {
|
|
|
|
return r.Resolver.Network()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverErrWrapper) Address() string {
|
|
|
|
return r.Resolver.Address()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *resolverErrWrapper) CloseIdleConnections() {
|
|
|
|
r.Resolver.CloseIdleConnections()
|
|
|
|
}
|
2022-05-16 10:46:53 +02:00
|
|
|
|
|
|
|
func (r *resolverErrWrapper) LookupNS(
|
|
|
|
ctx context.Context, domain string) ([]*net.NS, error) {
|
|
|
|
out, err := r.Resolver.LookupNS(ctx, domain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, newErrWrapper(classifyResolverError, ResolveOperation, err)
|
|
|
|
}
|
|
|
|
return out, nil
|
|
|
|
}
|