Skip to content
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

Fix default settings of queries #1397

Merged
merged 9 commits into from
Nov 27, 2024
Merged

Conversation

tgreenx
Copy link
Contributor

@tgreenx tgreenx commented Nov 19, 2024

Purpose

This PR proposes a fix to the default settings of queries which, due to an oversight regarding the edns_size flag from #1147, made all non-DNSSEC queries to be EDNS queries instead of regular non-EDNS queries. Default EDNS0 packet size values will now be properly used when appropriate, and a new, missing one has been created for DNSSEC to align with current specification. The caching logic of queries was also impacted.

The basic usage for creating DNSSEC and EDNS queries remains unchanged.

Context

Fixes zonemaster/zonemaster#1308

Changes

  • Fix logic related to flags dnssecand edns_size for when to use default values, and also when combined with edns_details
  • Fix caching logic when using dnssec and edns_size parameters
  • Add upper and lower bound checks for edns_size
  • Make combined usage of dnssec with edns_details but without edns_details{do} to correctly set the dnssec (DO) flag
  • Removed uneeded code related to resetting flags between queries (- it was already done earlier in the same method)
  • Add constant UDP_DNSSEC_QUERY_DEFAULT (set to 1232)
  • Rename constant UDP_COMMON_EDNS_LIMIT to UDP_EDNS_COMMON_LIMIT
  • Add and update documentation
  • Add unit tests
  • Update unit tests data

How to test this PR

Units tests have been added or updated and should pass. Note that most of the newly added unit tests cannot be properly tested when replaying unit test data files (i.e without ZONEMASTER_RECORD=1), as the actual tested object is the dns attribute of a Zonemaster::Engine::Nameserver object and its properties are not changed when getting query responses directly from the cache.

Manual testing can be done using the commands below:

Default DNS query

$ perl -MZonemaster::Engine -E 'my $ns = Zonemaster::Engine->ns("d.nic.fr", "194.0.9.1"); my $p = $ns->query("fr", "A"); say "dnssec (DO) flag in query: ", $ns->dns->dnssec ? "true" : "false"; say "edns_size in query: ", $ns->dns->edns_size; say "DO flag in response: ", $p->do ? "true": "false"; say "has_edns in response: ", $p->has_edns ? "true": "false"';
dnssec (DO) flag in query: false
edns_size in query: 0
DO flag in response: false
has_edns in response: false

An optional hash can be passed as parameter to the query method, with keys such as dnssec, edns_size and edns_details. They should be changed and/or removed with various combinaisons to see the different behaviors.

Default DNSSEC query

$ perl -MZonemaster::Engine -E 'my $ns = Zonemaster::Engine->ns("d.nic.fr", "194.0.9.1"); my $p = $ns->query("fr", "A", { "dnssec" => 1 }); say "dnssec in query: ", $ns->dns->dnssec ? "true" : "false"; say "edns_size in query: ", $ns->dns->edns_size; say "DO flag in response: ", $p->do ? "true": "false"; say "has_edns in response: ", $p->has_edns ? "true": "false"';
dnssec in query: true
edns_size in query: 1232
DO flag in response: true
has_edns in response: true

Default EDNS query

$ perl -MZonemaster::Engine -E 'my $ns = Zonemaster::Engine->ns("d.nic.fr", "194.0.9.1"); my $p = $ns->query("fr", "A", { "edns_details" => {} }); say "dnssec in query: ", $ns->dns->dnssec ? "true" : "false"; say "edns_size in query: ", $ns->dns->edns_size; say "DO flag in response: ", $p->do ? "true": "false"; say "has_edns in response: ", $p->has_edns ? "true": "false"';
dnssec in query: false
edns_size in query: 512
DO flag in response: false
has_edns in response: true

@tgreenx tgreenx added T-Bug Type: Bug in software or error in test case description V-Patch Versioning: The change gives an update of patch in version. labels Nov 19, 2024
@tgreenx tgreenx added this to the v2024.2 milestone Nov 19, 2024
@tgreenx tgreenx changed the title Fix default EDNS behavior Fix queries default EDNS behavior Nov 19, 2024
Comment on lines 410 to 415
if ( $flags{q{dnssec}} ) {
$flags{q{edns_size}} = $href->{q{edns_size}} // $UDP_EDNS_QUERY_DEFAULT;
}
else {
$flags{q{edns_size}} = $href->{q{edns_size}} // 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value must no be larger than 64 kB. If the value is smaller than 512 it must be treated as 512. Maybe we will create a test case where it is set smaller.

Is it possible by this code to create a non-DNSSEC EDNS query without specifying the size and get the default?

Copy link
Contributor Author

@tgreenx tgreenx Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've entirely reworked this PR, it should now align with our expectations. Please see commit 2566bcc (description and unit tests, in particular)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it doesn’t make much sense to set a value larger than 65 535. I suggest to croak in this situation.

However, if the argument is 512 or lower, we have two options:

  • be a good citizen, not expose bugs in other people’s nameservers, log a warning on our side and force the value to be 512;
  • or, on the contrary, allow ourselves to send EDNS queries with silly buffer size values and see how other servers respond to that.

How should we proceed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a check for both lower (0) and upper (65535) bounds for this parameter.

@tgreenx
Copy link
Contributor Author

tgreenx commented Nov 20, 2024

Unit tests data need to be re-recorded. I'll switch this PR to a draft state in the meantime.

@tgreenx tgreenx marked this pull request as draft November 20, 2024 18:58
Copy link
Contributor

@marc-vanderwal marc-vanderwal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking pretty good already. Just some minor issues with the updated POD.

lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
Comment on lines 410 to 415
if ( $flags{q{dnssec}} ) {
$flags{q{edns_size}} = $href->{q{edns_size}} // $UDP_EDNS_QUERY_DEFAULT;
}
else {
$flags{q{edns_size}} = $href->{q{edns_size}} // 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it doesn’t make much sense to set a value larger than 65 535. I suggest to croak in this situation.

However, if the argument is 512 or lower, we have two options:

  • be a good citizen, not expose bugs in other people’s nameservers, log a warning on our side and force the value to be 512;
  • or, on the contrary, allow ourselves to send EDNS queries with silly buffer size values and see how other servers respond to that.

How should we proceed?

@matsduf
Copy link
Contributor

matsduf commented Nov 21, 2024

The EDNS UDP buffer size is a 16-bit value. If the code tries to set something larger than that I think the code should "crash". This would only come from bad (Zonemaster) code.

If we ever want to set something lower than 512 we must permit that. We do not have such use case today, so I suggest that the code should "crash" so that we do not try to do the wrong thing.

Copy link
Contributor

@marc-vanderwal marc-vanderwal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve made bad suggestions and I apologize. It turns out that the > in those -> I made you add needed escaping. My new suggestions are correct: I’ve actually tested them with perldoc.

lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
@tgreenx tgreenx force-pushed the fix-edns branch 2 times, most recently from fbc11e9 to 52bc120 Compare November 21, 2024 18:04
@tgreenx
Copy link
Contributor Author

tgreenx commented Nov 21, 2024

@matsduf @marc-vanderwal @mattias-p This PR is now ready for review. Unit tests have been re-recorded where applicable, comments have been adressed, and it has been rebased on top of #1398 (commit e9060d1) so that the CI can pass.

@tgreenx tgreenx marked this pull request as ready for review November 21, 2024 18:11
@tgreenx tgreenx added V-Minor Versioning: The change gives an update of minor in version. and removed V-Patch Versioning: The change gives an update of patch in version. labels Nov 21, 2024
@tgreenx tgreenx changed the title Fix queries default EDNS behavior Fix default settings of queries Nov 21, 2024
Copy link
Contributor

@matsduf matsduf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides some detailed comments it looks fine.

lib/Zonemaster/Engine/Constants.pm Outdated Show resolved Hide resolved
}

croak "edns_size (or edns_details->size) parameter must be a value between 0 and 65535" if $edns_size > 65535 or $edns_size < 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
croak "edns_size (or edns_details->size) parameter must be a value between 0 and 65535" if $edns_size > 65535 or $edns_size < 0;
croak "edns_size (or edns_details->size) parameter must be 0 (no EDNS) or a value between 512 and 65535" if $edns_size != 0 and ($edns_size > 65535 or $edns_size < 512);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Today we have no use cases for values 1-511. Any such value would today be a mistake and it would be better to catch those. For EDNS 0-511 is defined to mean the same thing as 512. If we ever want to check for servers handling small values we could always change the logic.

One could also argue that high values would never be used. We have today no use cases for high values. From that perspective it could be argued that the code should set a limit to catch mistakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it is really needed to have such "subjective" checks. These are still "valid" values in the sense that the underlying library (LDNS) will accept them. I don't think we should impose those to us, or to any other user of Zonemaster-Engine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
lib/Zonemaster/Engine/Nameserver.pm Outdated Show resolved Hide resolved
Comment on lines +826 to +827
Set the EDNS0 UDP maximum size. The value must be comprised between 0 and 65535.
Defaults to 0, or 512 if the query is a non-DNSSEC EDNS query, or 1232 if the query is a DNSSEC query.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Set the EDNS0 UDP maximum size. The value must be comprised between 0 and 65535.
Defaults to 0, or 512 if the query is a non-DNSSEC EDNS query, or 1232 if the query is a DNSSEC query.
Set the EDNS0 UDP requestor's maximum size. The value must be 0 or comprised between 512 and 65535 (inclusive).
Defaults to 0 (non-EDNS query), or 512 (non-DNSSEC EDNS query), or 1232 (DNSSEC query).

@tgreenx tgreenx requested a review from matsduf November 25, 2024 16:44
matsduf
matsduf previously approved these changes Nov 25, 2024
@tgreenx tgreenx dismissed matsduf’s stale review November 25, 2024 19:47

The merge-base changed after approval.

matsduf
matsduf previously approved these changes Nov 26, 2024
matsduf
matsduf previously approved these changes Nov 26, 2024
Due to an oversight in a previous refactoring, all non-DNSSEC DNS queries sent by Zonemaster became
EDNS queries. This commit makes it so that those queries are now non-EDNS queries. Default EDNS0 packet
size values will now be properly used when appropriate, and a new, missing one has been created for DNSSEC.
The caching logic of queries was also impacted.

Simply put, a DNSSEC query using the default EDNS0 packet size of 1232 is made by setting parameter "dnssec"
and/or "edns_details{do}" (the latter has precedence).
For a non-DNSSEC EDNS query, setting parameter "edns_size" and/or "edns_details{size}" (the latter has precedence)
will do the trick, but then it will use the provided value for the EDNS0 packet size. To use the default value of 512,
just set parameter "edns_details" with an empty hash (or non-empty with any of its subkey(s) other than edns_details{do,size})
instead.

- Fix logic related to flags dnssec and edns_size for when to use default values, and also when combined with edns_details
- Fix caching logic when using dnssec and edns_size parameters
- Make combined usage of dnssec with edns_details but without edns_details{do} to correctly set the dnssec (DO) flag
- Removed uneeded code related to resetting flags between queries (- it was already done earlier in the same method)
- Add constant UDP_DNSSEC_QUERY_DEFAULT (set to 1232)
- Rename constant UDP_COMMON_EDNS_LIMIT to UDP_EDNS_COMMON_LIMIT
- Add and update documentation
- Add unit tests
…::Nameserver->query()

The maximum value for this parameter, set either by "edns_size" or "edns_details->size", is a 16-bit value,
thus it should not exceed 65535. Documentation and unit tests are updated too.
…::Nameserver->query()

This parameter, set either by "edns_size" or "edns_details->size", is an unsigned 16-bit value,
thus the minimum value should be 0. Documentation and unit tests are updated too.
Use a different query name for each query as to make sure that we do not get a cached response from previous, equivalent queries.
This is needed because the tested object is actually the underlying object in the "dns" attribute of the Zonemaster::Engine::Nameserver class,
which is only updated by the "_query()" method, and not the "query()" method.
Renamed some constants:
 - UDP_DNSSEC_QUERY_DEFAULT to EDNS_UDP_PAYLOAD_DNSSEC_DEFAULT
 - UDP_EDNS_QUERY_DEFAULT to EDNS_UDP_PAYLOAD_DEFAULT
 - UDP_EDNS_COMMON_LIMIT to EDNS_UDP_PAYLOAD_COMMON_LIMIT
@tgreenx
Copy link
Contributor Author

tgreenx commented Nov 27, 2024

@matsduf I fixed a conflict and rebased on latest develop, please re-review.

@tgreenx tgreenx requested a review from matsduf November 27, 2024 13:13
matsduf
matsduf previously approved these changes Nov 27, 2024
@tgreenx tgreenx merged commit 760f9ea into zonemaster:develop Nov 27, 2024
3 checks passed
@tgreenx tgreenx deleted the fix-edns branch November 27, 2024 13:50
@MichaelTimbert MichaelTimbert added the S-ReleaseTested Status: The PR has been successfully tested in release testing label Dec 3, 2024
@tgreenx tgreenx mentioned this pull request Dec 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-ReleaseTested Status: The PR has been successfully tested in release testing T-Bug Type: Bug in software or error in test case description V-Minor Versioning: The change gives an update of minor in version.
Projects
None yet
4 participants