-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: TRR2 resolver #846
base: master
Are you sure you want to change the base?
feat: TRR2 resolver #846
Conversation
This intoduces a TRR2 resolver to measurexlite allowing us to opportunistcally test for DoH and make use of it whenever we can. The resolver uses the system resolver (getaddrinfo) as a fallback when DoH fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the work you did so far. As I mention to you in private, we probably need to figure out some design details around this functionality, which won't cause dramatic changes, so we can discuss them in parallel with the code review proper. I highlighted a bunch of places in which I think you should tweak/refactor your code for improved robustness.
Additionally, I've seen quite a large coverage drop (-0.5%) which most likely means that we have added a bit too much code that we're not testing. I would recommend for you to check which are the new functions that we're not testing and add tests.
internal/measurexlite/dns.go
Outdated
@@ -64,6 +64,20 @@ func (r *resolverTrace) LookupNS(ctx context.Context, domain string) ([]*net.NS, | |||
return r.r.LookupNS(netxlite.ContextWithTrace(ctx, r.tx), domain) | |||
} | |||
|
|||
// NewTrustedRecursiveResolver2 returns a trace-aware TRR2 resolver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// NewTrustedRecursiveResolver2 returns a trace-aware TRR2 resolver | |
// NewTrustedRecursiveResolver2 returns a trace-aware TRR2 resolver. |
internal/measurexlite/resolver.go
Outdated
"github.com/ooni/probe-cli/v3/internal/netxlite" | ||
) | ||
|
||
// NewTrustedRecursiveResolver2 returns a new trusted recursive resolver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// NewTrustedRecursiveResolver2 returns a new trusted recursive resolver | |
// NewTrustedRecursiveResolver2 returns a new trusted recursive resolver. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should document that logger
is MANDATORY
while URL
is OPTIONAL
and you should say what happens if you provide an empty URL
. You should probably say, for future robustness, that we're going to choose a suitable URL (or you could also be specific, up to you).
internal/measurexlite/resolver.go
Outdated
} | ||
} | ||
|
||
// TrustedRecursiveResolver2 emulates Firefox's TRR2 mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// TrustedRecursiveResolver2 emulates Firefox's TRR2 mode | |
// TrustedRecursiveResolver2 emulates Firefox's TRR2 mode. |
internal/measurexlite/resolver.go
Outdated
Logger model.Logger | ||
URL string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, document Logger
and URL
(and mention they're MANDATORY
)
internal/measurexlite/resolver.go
Outdated
// we can't return a decisive address here since we don't know if LookupHost | ||
// succeeds with the DoH resolver or the system resolver | ||
func (trr *TrustedRecursiveResolver2) Address() string { | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about returning the URL here?
internal/measurexlite/resolver.go
Outdated
|
||
// | ||
// Trusted Recursive Resolver | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either call the file trr2.go
and keep this comment or call this file resolver.go
and say it contains resolvers
) | ||
|
||
func TestNewTrustedRecursiveResolver(t *testing.T) { | ||
var called bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, put suitable copies of this variable in the narrowest possible scope to avoid mistakes caused by the variable in a subtest using a value previously computed by another subtest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I see how in the code you only use it once, but I'd like to recommend you probably just create the resolver you need each time rather than having too much shared state for tests. The issue with shared state is that it's not robust to refactoring, so I'd rather just initialize each time the specific calls I need and leave others as nil
)
resolver := NewTrustedRecursiveResolver2(&mocks.Logger{}, "") | ||
resolvert := resolver.(*TrustedRecursiveResolver2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolver := NewTrustedRecursiveResolver2(&mocks.Logger{}, "") | |
resolvert := resolver.(*TrustedRecursiveResolver2) | |
resolver := NewTrustedRecursiveResolver2(&mocks.Logger{}, "").(*TrustedRecursiveResolver2) |
This should save you a variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. Thanks!
resolvert := resolver.(*TrustedRecursiveResolver2) | ||
resolvert.NewParallelDNSOverHTTPSResolverFn = newResolver | ||
ctx := context.Background() | ||
t.Run("LookupHost", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t.Run("LookupHost", func(t *testing.T) { | |
t.Run("LookupHost", func(t *testing.T) { |
Please always add spaces around t.Run
invocations. This allows for easy navigation of blocks using vi's {
and }
commands.
@@ -52,7 +52,7 @@ func TestGetMeasurementMetaWorkingAsIntended(t *testing.T) { | |||
if mmeta.Input == nil || *mmeta.Input != config.Input { | |||
t.Fatal("unexpected input value") | |||
} | |||
if mmeta.MeasurementStartTime.String() != "2020-12-09 05:22:25 +0000 UTC" { | |||
if mmeta.MeasurementStartTime.String() != "2020-12-09 04:22:25 +0000 UTC" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't fully understand why this change is necessary and the commit does not seem to explain in detail why this was behaving in a flaky way. Would you mind clarifying?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a bug in the data pipeline (as I had informed in our 1:1). I have reverted this back since the bug has been fixed now: f71c4e2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional issues that I discovered while writing a design document for this feature
internal/measurexlite/resolver.go
Outdated
if reso == nil { | ||
reso = netxlite.NewParallelDNSOverHTTPSResolver(trr.Logger, trr.URL) | ||
} | ||
addrs, err := reso.LookupHost(ctx, hostname) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to mention: if we want to implement TRR2 correctly, this lookup should be strictly time bounded (i.e., we should timeout the lookup after N seconds have elapsed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added a timeout to the DoH resolver here: 286c78f#diff-4c58fee97f07a0f47542cb08705a81d5f43f76be1d6235538ceb3e4c51725e72R33,
this is currently configured to use Firefox's default timeout value of 1.5s
internal/measurexlite/resolver.go
Outdated
} | ||
out, err := reso.LookupHTTPS(ctx, domain) | ||
if err != nil { | ||
out, err = trr.ResolverSystem.LookupHTTPS(ctx, domain) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the system resolver only implements LookupHost
, we should consider implementing model.SimpleResolver
rather than model.Resolver
.
We discussed this @hellais and it was a bug in the data pipeline which seems to be have been fixed. We can therefore revert back to the original implementation.
Thank you for the feedback! I have made some changes based on the review. I have also added more tests, but the coverage still seems to be decreased. So we probably need to write some more. |
Checklist
Description
This intoduces a TRR2 resolver to measurexlite allowing us to opportunistcally test for DoH and make use of it whenever we can. The resolver uses the system resolver (
getaddrinfo
) as a fallback when DoH fails